The PM component of RT-Thread uses LPTIM to achieve low-power wake-up and system tick compensation, and the clock source of LPTIM generally selects LSI. Although the power consumption of LSI is only a few hundred nA, the frequency deviation is very large. For example, the STML051 manual says that the frequency of LSI is between 26kHz and 56kHz, with a typical value of 38kHz (37kHz in the HAL library), as shown in the figure below .
In some low-power application scenarios with slightly higher time requirements, the accuracy of LSI cannot meet the demand. For example, a device needs to wake up every 30 seconds. If the clock of the LSI is high, the device's wake-up cycle will definitely be less than 30 seconds. Although we cannot calibrate the actual accuracy of LSI, we can measure the actual clock frequency of LPTIM. In the drv_lptim driver of RT-Thread, the LPTIM frequency needs to be provided to the upper layer. As long as the frequency we provide is close to the actual value, the time error caused during sleep can be reduced.
How to measure the actual frequency of LPTIM? In fact, it can be calculated by a high-speed clock, such as systick. Compared with LSI, high-speed clock has much higher accuracy. The specific idea is as follows: Suppose the frequency of LSI is 37kHz, and the clock of LPTIM is divided by 32 of LSI, then the frequency of LPTIM is (37000 >> 5), at this frequency, let LPTIM time for 1 second, and use systick to record the actual passing Time delta_time, then you can easily use delta_time to reverse the actual frequency of LPTIM. The reference code is as follows. The accuracy of LSI is affected by the chip itself and the external environment. It is recommended to calibrate the LPTIM regularly.
void stm32lx_lptim_calibration(void)
{
rt_uint32_t delta_time = 0;
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_FLAG_CMPM);
/* 定时1秒,reload = 37000 / 32 = 1156 */
HAL_LPTIM_TimeOut_Start(&LptimHandle, 0xFFFF, 1156);
delta_time = rt_tick_get();
/* 等待lptim定时时间到 */
while(!__HAL_LPTIM_GET_FLAG(&LptimHandle, LPTIM_FLAG_CMPM))
{
rt_thread_delay(1);
}
delta_time = rt_tick_get() - delta_time;
/* 计算lptim的实际频率 */
lptim_freq = (LSI_VALUE >> 5) * RT_TICK_PER_SECOND / delta_time;
}