如何提高 CMWX1ZZABZ-091 RTC(实时时钟)的精度
How to improve accuracy of CMWX1ZZABZ-091 RTC (Real Time Clock)
我将 B-L072Z-LRWAN1 与 CMWX1ZZABZ-091 LoRa® /Sigfox™ 模块 (Murata) 一起使用
内部 RTC(实时时钟)不准确,我发现某些模块每天损失 10 秒。
我的问题是,为什么会这样?数据表显示 LSE 为 1.73 秒/20ppm。 TXCO 为 2ppm。如何使用 TXCO 校准 RTC?
我知道还有温度会影响精度,但我认为它在一个微不足道的范围内,即不能解释 10 秒/天。
(关于 LSE 的虚假陈述已删除)
How can I calibrate the RTC using TXCO?
TXCO可以提供给HSE,你可以通过一系列预分频器从HSE得到RTC时钟。
User Manual 中的第 8.5 节说,
When an accurate external-high-speed clock is needed by the STM32, the TCXO_OUT clock pin is supplied by the module pin PH0_OSC_IN by closing SB13.
首先,用一滴锡关闭 SB13。
PH0_OSC_IN是HSE旁路时钟源。在 RCC->CR
中设置 HSEBYP
然后 HSEON
以获得准确的 32 MHz HSE 时钟。但是等等,首先您必须将 RTCPRE
设置为 3
以便为 RTC 模块将其预分频为 16。 Select 这是 RCC->CSR
中的 RTC 时钟。
现在 RCC 为 RTC 生成 2 MHz 时钟 (fRTCCLK = 2000000)。您可以使用 RTC->PRER
寄存器将其进一步降低至 1 Hz (fCK_SPRE = 1)。它有两个位域,PREDIV_A
可以从 0
到 127
,PREDIV_S
从 0
到 32767
。求解整数方程
fCK_SPRE = fRTCCLK / ((PREDIV_S + 1) × (PREDIV_A + 1))
有了上面的限制给出
PREDIV_S = 24999
PREDIV_A = 79
所以使用
RTC->PRER = (79 << 16) | 24999;
你会有一个准确的 1 Hz 时钟用于 RTC。
运行 来自 LSE 的 RTC,但将其校准为 HSE。
执行 中的第一步以获得准确的 HSE 时钟,但 运行 来自 LSE。
来自参考手册,
22.4.12 RTC smooth digital calibration
The RTC frequency can be digitally calibrated with a resolution of about 0.954 ppm with a range from -487.1 ppm to +488.5 ppm.
校准在RTC->CALR
寄存器中完成,即使时钟为运行也可以平滑调整。调整周期必须为 32 秒才能达到 0.954 ppm 的精度。
将 RTC 定期唤醒定时器配置为每 32 秒生成一次中断。将 RTC 闹钟连接到 TIM21->OR
寄存器中 TIM21
的 TI1 输入。配置 TIM21 以捕获 TI1 边沿。由于定时器只有 16 位,您必须计算 TIM21 中断处理程序中的溢出(更新事件)。当捕获事件发生时,您有经过的周期数,更新计数中的高半字,捕获寄存器中的低半字。如果与标称值32*32*106相差较大,调整RTC->CALR
重复
难点在于当更新和捕获大致同时发生时正确处理,因此代码无法可靠地确定哪个先发生。以后再考虑。
How can I calibrate the RTC using TXCO?
前段时间我问过自己同样的问题,我花了一段时间才找到解决方案,因为参考手册中记录了很多选项,而且主题可能很混乱。
在我的例子中,我需要在没有 HSE 谐振器的电路板上校准 RTC(这是一个只有 LSE crystal (32.768 kHz) 的小型手表原型,电路板没有HSE,并由不稳定的 RC 内部振荡器提供时钟)。但是对我有用的方法应该也适用于你的情况。
我的 RTC 校准方法的关键是:
- 快速、稳定的参考时钟。我使用了 STM32F4 探索板(具有 8 MHz HSE crystal 和 25 MHz 的 APB 时钟速度(PLL'ed up),定时器用于下面描述的测量)。
- 非常精确的 1PPS 校准输入(每秒 1 脉冲)。 - 我在其中一个引脚上使用了 1PPS 输出的 GPS 模块。
我的校准步骤如下:
- 计算多个 1PPS 事件之间的系统时钟滴答数 在连接到 1PPS 信号源(在我的例子中是 GPS 模块)的引脚上使用 Counter/Timer(选择正确的定时器宽度(16 位与 32 位)和时钟分频(最好不分频以获得最大分辨率))。然后取平均值,以了解与假定时钟速度(在我的例子中为 25 MHz)的偏差。它应该是稳定的,并且在测量过程中变化不大(32 秒校准时间就足够了)。
- 然后计算多个 1 Hz 校准输出滴答之间的系统时钟滴答数(由目标 MCU 的 LSE 驱动)(在不同的引脚上使用输入捕获),以及取平均值。
- 现在计算所需的 LSE 校正。并使用目标STM32上的RTC校准寄存器来调整RTC(另请参阅参考手册中的RTC Smooth Calibration或此Application Note (AN3371))。
- 重做步骤 1 和 2 以验证更正。
确保在开始校准之前撤消任何 RTC 校正:
if (HAL_RTCEx_SetSmoothCalib(
&hrtc,
RTC_SMOOTHCALIB_PERIOD_32SEC,
RTC_SMOOTHCALIB_PLUSPULSES_RESET,
0) != HAL_OK) {
error_handler();
}
start_calibration();
为了计算校正,我使用了类似的东西:
const float corr = calib_avg_ext_rtc / calib_avg_1pps;
log("correction:\r\n%f / %f =\r\n%.20f\r\n\r\n",
calib_avg_ext_rtc, calib_avg_1pps, corr);
const float c = corr - 1.0f;
if (corr > 1.0f) {
log("RTC crystal vibrates too fast!\r\n");
log("correction: %.20f ppm\r\n", -1.0e6f * c);
}
else if (corr < 1.0f) {
log("RTC crystal vibrates too slow!\r\n");
log("correction: %.20f ppm\r\n", 1.0e6f * c);
}
else {
log("your RTC crystal is running exactly at the right speed. - STRANGE!\r\n");
}
const int16_t calib32s = (int16_t)roundf(c * 32*32768);
if (calib32s != 0) {
log("correction value (ticks +/- 32 s interval):\r\n");
if (corr < 1.0f) {
log("MINUS %d\r\n", -calib32s); /* clock TOO SLOW, REMOVE cycles */
log("\r\nuse this on the target:\r\n");
log("HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC,\
RTC_SMOOTHCALIB_PLUSPULSES_RESET, %d);",
-calib32s);
}
else {
log("PLUS %d\r\n", calib32s); /* clock TOO FAST, ADD cycles */
log("\r\nuse this on the target:\r\n");
log("HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC,\
RTC_SMOOTHCALIB_PLUSPULSES_SET, 0x1FF - %d);",
calib32s);
}
}
else {
log("calibration complete! NO FURTHER CORRECTION REQUIRED\r\n");
}
测量所需的校正后,我手动复制粘贴了代码,并且必须闪存目标板以验证校准。稍后,最好选择在设备已部署时进行校准...
我在 STM32L011 上使用过这个方法,但该方法或多或少与 MCU 的类型无关。就我而言,我在 STM32F4 发现板上使用了 8 MHz HSE 和一个 32 位计数器。但是,当存在快速、稳定的 HSE 时,这种方法应该以修改后的形式工作,无需额外的硬件(除了 1PPS 源)。 - 我设法得到小于 1 PPM 的偏差,并且 RTC 可以准确地保持时间几天(温度的变化会对精度产生很大影响,正如我必须找出的那样)。
STM32 论坛也讨论了这些发现,但该页面现在已关闭,因此我无法将您指向 that...
我将 B-L072Z-LRWAN1 与 CMWX1ZZABZ-091 LoRa® /Sigfox™ 模块 (Murata) 一起使用
内部 RTC(实时时钟)不准确,我发现某些模块每天损失 10 秒。
我的问题是,为什么会这样?数据表显示 LSE 为 1.73 秒/20ppm。 TXCO 为 2ppm。如何使用 TXCO 校准 RTC?
我知道还有温度会影响精度,但我认为它在一个微不足道的范围内,即不能解释 10 秒/天。
(关于 LSE 的虚假陈述已删除)
How can I calibrate the RTC using TXCO?
TXCO可以提供给HSE,你可以通过一系列预分频器从HSE得到RTC时钟。
User Manual 中的第 8.5 节说,
When an accurate external-high-speed clock is needed by the STM32, the TCXO_OUT clock pin is supplied by the module pin PH0_OSC_IN by closing SB13.
首先,用一滴锡关闭 SB13。
PH0_OSC_IN是HSE旁路时钟源。在 RCC->CR
中设置 HSEBYP
然后 HSEON
以获得准确的 32 MHz HSE 时钟。但是等等,首先您必须将 RTCPRE
设置为 3
以便为 RTC 模块将其预分频为 16。 Select 这是 RCC->CSR
中的 RTC 时钟。
现在 RCC 为 RTC 生成 2 MHz 时钟 (fRTCCLK = 2000000)。您可以使用 RTC->PRER
寄存器将其进一步降低至 1 Hz (fCK_SPRE = 1)。它有两个位域,PREDIV_A
可以从 0
到 127
,PREDIV_S
从 0
到 32767
。求解整数方程
fCK_SPRE = fRTCCLK / ((PREDIV_S + 1) × (PREDIV_A + 1))
有了上面的限制给出
PREDIV_S = 24999
PREDIV_A = 79
所以使用
RTC->PRER = (79 << 16) | 24999;
你会有一个准确的 1 Hz 时钟用于 RTC。
运行 来自 LSE 的 RTC,但将其校准为 HSE。
执行
来自参考手册,
22.4.12 RTC smooth digital calibration
The RTC frequency can be digitally calibrated with a resolution of about 0.954 ppm with a range from -487.1 ppm to +488.5 ppm.
校准在RTC->CALR
寄存器中完成,即使时钟为运行也可以平滑调整。调整周期必须为 32 秒才能达到 0.954 ppm 的精度。
将 RTC 定期唤醒定时器配置为每 32 秒生成一次中断。将 RTC 闹钟连接到 TIM21->OR
寄存器中 TIM21
的 TI1 输入。配置 TIM21 以捕获 TI1 边沿。由于定时器只有 16 位,您必须计算 TIM21 中断处理程序中的溢出(更新事件)。当捕获事件发生时,您有经过的周期数,更新计数中的高半字,捕获寄存器中的低半字。如果与标称值32*32*106相差较大,调整RTC->CALR
重复
难点在于当更新和捕获大致同时发生时正确处理,因此代码无法可靠地确定哪个先发生。以后再考虑。
How can I calibrate the RTC using TXCO?
前段时间我问过自己同样的问题,我花了一段时间才找到解决方案,因为参考手册中记录了很多选项,而且主题可能很混乱。
在我的例子中,我需要在没有 HSE 谐振器的电路板上校准 RTC(这是一个只有 LSE crystal (32.768 kHz) 的小型手表原型,电路板没有HSE,并由不稳定的 RC 内部振荡器提供时钟)。但是对我有用的方法应该也适用于你的情况。
我的 RTC 校准方法的关键是:
- 快速、稳定的参考时钟。我使用了 STM32F4 探索板(具有 8 MHz HSE crystal 和 25 MHz 的 APB 时钟速度(PLL'ed up),定时器用于下面描述的测量)。
- 非常精确的 1PPS 校准输入(每秒 1 脉冲)。 - 我在其中一个引脚上使用了 1PPS 输出的 GPS 模块。
我的校准步骤如下:
- 计算多个 1PPS 事件之间的系统时钟滴答数 在连接到 1PPS 信号源(在我的例子中是 GPS 模块)的引脚上使用 Counter/Timer(选择正确的定时器宽度(16 位与 32 位)和时钟分频(最好不分频以获得最大分辨率))。然后取平均值,以了解与假定时钟速度(在我的例子中为 25 MHz)的偏差。它应该是稳定的,并且在测量过程中变化不大(32 秒校准时间就足够了)。
- 然后计算多个 1 Hz 校准输出滴答之间的系统时钟滴答数(由目标 MCU 的 LSE 驱动)(在不同的引脚上使用输入捕获),以及取平均值。
- 现在计算所需的 LSE 校正。并使用目标STM32上的RTC校准寄存器来调整RTC(另请参阅参考手册中的RTC Smooth Calibration或此Application Note (AN3371))。
- 重做步骤 1 和 2 以验证更正。
确保在开始校准之前撤消任何 RTC 校正:
if (HAL_RTCEx_SetSmoothCalib(
&hrtc,
RTC_SMOOTHCALIB_PERIOD_32SEC,
RTC_SMOOTHCALIB_PLUSPULSES_RESET,
0) != HAL_OK) {
error_handler();
}
start_calibration();
为了计算校正,我使用了类似的东西:
const float corr = calib_avg_ext_rtc / calib_avg_1pps;
log("correction:\r\n%f / %f =\r\n%.20f\r\n\r\n",
calib_avg_ext_rtc, calib_avg_1pps, corr);
const float c = corr - 1.0f;
if (corr > 1.0f) {
log("RTC crystal vibrates too fast!\r\n");
log("correction: %.20f ppm\r\n", -1.0e6f * c);
}
else if (corr < 1.0f) {
log("RTC crystal vibrates too slow!\r\n");
log("correction: %.20f ppm\r\n", 1.0e6f * c);
}
else {
log("your RTC crystal is running exactly at the right speed. - STRANGE!\r\n");
}
const int16_t calib32s = (int16_t)roundf(c * 32*32768);
if (calib32s != 0) {
log("correction value (ticks +/- 32 s interval):\r\n");
if (corr < 1.0f) {
log("MINUS %d\r\n", -calib32s); /* clock TOO SLOW, REMOVE cycles */
log("\r\nuse this on the target:\r\n");
log("HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC,\
RTC_SMOOTHCALIB_PLUSPULSES_RESET, %d);",
-calib32s);
}
else {
log("PLUS %d\r\n", calib32s); /* clock TOO FAST, ADD cycles */
log("\r\nuse this on the target:\r\n");
log("HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC,\
RTC_SMOOTHCALIB_PLUSPULSES_SET, 0x1FF - %d);",
calib32s);
}
}
else {
log("calibration complete! NO FURTHER CORRECTION REQUIRED\r\n");
}
测量所需的校正后,我手动复制粘贴了代码,并且必须闪存目标板以验证校准。稍后,最好选择在设备已部署时进行校准...
我在 STM32L011 上使用过这个方法,但该方法或多或少与 MCU 的类型无关。就我而言,我在 STM32F4 发现板上使用了 8 MHz HSE 和一个 32 位计数器。但是,当存在快速、稳定的 HSE 时,这种方法应该以修改后的形式工作,无需额外的硬件(除了 1PPS 源)。 - 我设法得到小于 1 PPM 的偏差,并且 RTC 可以准确地保持时间几天(温度的变化会对精度产生很大影响,正如我必须找出的那样)。
STM32 论坛也讨论了这些发现,但该页面现在已关闭,因此我无法将您指向 that...