S_API double s_rel_diff(double a, double b) { double c = S_ABS(a); double d = S_ABS(b); d = S_MAX(c, d); return d == 0.0 ? 0.0 : (S_ABS(a - b) / d); }
/** * @brief Computes the values of the wakeup timer counter and prescaler from the user time expressed in millisecond. * The prescaler and the counter values are computed maintaining the prescaler value as * small as possible in order to obtain the best resolution, and in the meantime minimizing the error. * @param fDesiredMsec desired wakeup timeout in millisecs. * This parameter must be a float. Since the counter and prescaler are 8 bit registers the maximum * reachable value is maxTime = fTclk x 256 x 256. * @param pcCounter pointer to the variable in which the value for the wakeup timer counter has to be stored. * This parameter must be a uint8_t*. * @param pcPrescaler pointer to the variable in which the value for the wakeup timer prescaler has to be stored. * This parameter must be an uint8_t*. * @retval None */ void SpiritTimerComputeWakeUpValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler) { uint8_t b0, a0; uint32_t n; int32_t err, err_min; /* Check the parameters */ s_assert_param(IS_WKUP_TIMEOUT(fDesiredMsec)); n = (uint32_t)((fDesiredMsec*1000)/WAKEUP_TCLK); err_min = n; /* These are the initial values for the prescaler and the counter, where the prescaler is settled to the minimum value and the counter accordingly. In order to avoid a zero division for the counter the prescaler is increased by one. Then because the wakeup timeout is calculated as: Twu=(PRESCALER +1)*(COUNTER+1)*Tck the counter and the prescaler are decreased by one.*/ *pcPrescaler = a0 = (n/0xFF)+1; *pcCounter = b0 = (n / *pcPrescaler); (*pcPrescaler)--; /* If the desired value is over the maximum limit, the counter and the prescaler are settled to their maximum values, and doesn't execute the routine */ if(fDesiredMsec>1888.0) { *pcCounter = 0xFF; *pcPrescaler = 0xFF; return; } /* Iterative cycle to minimize the error */ for (; ; (*pcPrescaler)++) { *pcCounter = ((n/(*pcPrescaler+1))-1); err = (((int32_t)*pcPrescaler)+1) * (((int32_t)*pcCounter)+1) - (int32_t)n; if (S_ABS(err) > (*pcPrescaler / 2)) { (*pcCounter)++; err = (((int32_t)*pcPrescaler)+1) * (((int32_t)*pcCounter)+1) - (int32_t)n; } if (S_ABS(err) < S_ABS(err_min)) { err_min = err; a0 = *pcPrescaler; b0 = *pcCounter; if (err == 0) break; } if(*pcPrescaler == 0xFF) break; } *pcPrescaler = a0; *pcCounter = b0; }
/** * @brief Computes the values of the wakeup timer counter and prescaler from the user time expressed in millisecond. * The prescaler and the counter values are computed maintaining the prescaler value as * small as possible in order to obtain the best resolution, and in the meantime minimizing the error. * @param fDesiredMsec desired wakeup timeout in millisecs. * This parameter must be a float. Since the counter and prescaler are 8 bit registers the maximum * reachable value is maxTime = fTclk x 256 x 256. * @param pcCounter pointer to the variable in which the value for the wakeup timer counter has to be stored. * This parameter must be a uint8_t*. * @param pcPrescaler pointer to the variable in which the value for the wakeup timer prescaler has to be stored. * This parameter must be an uint8_t*. * @retval None */ void SpiritTimerComputeWakeUpValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler) { float rco_freq,err; uint32_t n; rco_freq=((float)SpiritTimerGetRcoFrequency())/1000; /* N cycles in the time base of the timer: - clock of the timer is RCO frequency - divide times 1000 more because we have an input in ms (variable rco_freq is already this frequency divided by 1000) */ n=(uint32_t)(fDesiredMsec*rco_freq); /* check if it is possible to reach that target with prescaler and counter of spirit1 */ if(n/0xFF>0xFD) { /* if not return the maximum possible value */ (*pcCounter) = 0xFF; (*pcPrescaler) = 0xFF; return; } /* prescaler is really 2 as min value */ (*pcPrescaler)=(n/0xFF)+2; (*pcCounter) = n / (*pcPrescaler); /* check if the error is minimum */ err=S_ABS((float)(*pcCounter)*(*pcPrescaler)/rco_freq-fDesiredMsec); if((*pcCounter)<=254) { if(S_ABS((float)((*pcCounter)+1)*(*pcPrescaler)/rco_freq-fDesiredMsec)<err) (*pcCounter)=(*pcCounter)+1; } /* decrement prescaler and counter according to the logic of this timer in spirit1 */ (*pcPrescaler)--; if((*pcCounter)>1) (*pcCounter)--; else (*pcCounter)=1; }
/** * @brief Computes the values of the rx_timeout timer counter and prescaler from the user time expressed in millisecond. * The prescaler and the counter values are computed maintaining the prescaler value as * small as possible in order to obtain the best resolution, and in the meantime minimizing the error. * @param fDesiredMsec desired rx_timeout in millisecs. * This parameter must be a float. Since the counter and prescaler are 8 bit registers the maximum * reachable value is maxTime = fTclk x 255 x 255. * @param pcCounter pointer to the variable in which the value for the rx_timeout counter has to be stored. * This parameter must be a uint8_t*. * @param pcPrescaler pointer to the variable in which the value for the rx_timeout prescaler has to be stored. * This parameter must be an uint8_t*. * @retval None */ void SpiritTimerComputeRxTimeoutValues(float fDesiredMsec , uint8_t* pcCounter , uint8_t* pcPrescaler) { uint8_t b0, a0, xtal; uint32_t n; int32_t err, err_min; /* Reads the Xtal configuration in the ANA_FUNC_CONF_0 register */ g_xStatus = SpiritSpiReadRegisters(ANA_FUNC_CONF0_BASE, 1, &xtal); /* Check the parameters and set the number of clock cylces according to the xtal configuration */ if((xtal & 0x40)== SELECT_24_26_MHZ_MASK) { /* Check the parameters */ s_assert_param(IS_RX_TIMEOUT_26MHz(fDesiredMsec)); /* If the desired value is over the maximum limit, the counter and the prescaler are settled to their maximum values, and doesn't execute the routine */ if(fDesiredMsec>3026.0) { *pcCounter = 0xFF; *pcPrescaler = 0xFF; return; } n = (uint32_t)((fDesiredMsec*1000)/RX_TCLK_26MHz); } else { /* Check the parameters */ s_assert_param(IS_RX_TIMEOUT_24MHz(fDesiredMsec)); /* If the desired value is over the maximum limit the counter and the prescaler are settled to their maximum values, and doesn't execute the routine */ if(fDesiredMsec>3278.0) { *pcCounter = 0xFF; *pcPrescaler = 0xFF; return; } n = (uint32_t)((fDesiredMsec*1000)/RX_TCLK_24MHz); } err_min = n; /* These are the initial values for the prescaler and the counter, where the prescaler is settled to the minimum value and the counter accordingly. In order to avoid a zero division for the counter the prescaler is increased by one.*/ *pcPrescaler = a0 = ((n-1)/0xFF)+1; *pcCounter = b0 = (n / *pcPrescaler); /* Iterative cycle to minimize the error */ for (; ; (*pcPrescaler)++) { *pcCounter = n / *pcPrescaler; err = 1+((int32_t)(*pcPrescaler)+1) * ((int32_t)*pcCounter) - (int32_t)n; if (S_ABS(err) > (*pcPrescaler / 2)) { (*pcCounter)++; err = 1+((int32_t)(*pcPrescaler)+1) * ((int32_t)*pcCounter) - (int32_t)n; } if (S_ABS(err) < S_ABS(err_min)) { err_min = err; a0 = *pcPrescaler; b0 = *pcCounter; if (err == 0) break; } if(*pcPrescaler == 0xFF) break; } *pcPrescaler = a0; *pcCounter = b0; }