如何提高CMWX1ZZABZ-091 RTC(实时时钟)的准确性

时间:2018-07-25 07:28:38

标签: c embedded stm32 real-time-clock

我正在将B-L072Z-LRWAN1与CMWX1ZZABZ-091LoRa®/ Sigfox™模块(村田)一起使用

内部RTC(实时时钟)不准确,我发现某些模块每天损失10秒。

我的问题是,为什么会这样?数据表显示LSE为1.73秒/ 20ppm。 TXCO为2ppm。如何使用TXCO校准RTC?

我知道还有温度会影响精度,但是我认为这个范围很小,即不能解释10秒/天。

3 个答案:

答案 0 :(得分:3)

(已删除有关LSE的错误陈述)

  

如何使用TXCO校准RTC?

TXCO可以提供HSE,并且您可以通过一系列预分频器从HSE导出RTC时钟。

User Manual中的8.5节说,

  

当STM32需要精确的外部高速时钟时,通过闭合SB13,由模块引脚PH0_OSC_IN提供TCXO_OUT时钟引脚。

首先,用一滴锡关闭SB13。

PH0_OSC_IN是HSE旁路时钟源。在HSEBYP中先设置HSEON,然后再设置RCC->CR,以获得准确的32 MHz HSE时钟。但是,等等,首先您必须将RTCPRE设置为3,以便将RTC模块的比例预先缩放16。在RCC->CSR中选择它作为RTC时钟。

现在,RCC为RTC生成2 MHz时钟(f RTCCLK = 2000000)。您可以使用RTC->PRER寄存器将其进一步缩小至1 Hz(f CK_SPRE = 1)。它具有两个位域,PREDIV_A可以从0127PREDIV_S032767。求解整数方程

f CK_SPRE = f RTCCLK / ((PREDIV_S + 1) × (PREDIV_A + 1))

具有上述限制的

PREDIV_S = 24999
PREDIV_A = 79

因此使用

RTC->PRER = (79 << 16) | 24999;

您将有一个准确的1 Hz RTC时钟。

答案 1 :(得分:3)

  

如何使用TXCO校准RTC?

不久前,我问自己一个相同的问题,花了一段时间才找到解决方案,因为参考手册中记录了许多选项,并且该主题可能非常令人困惑。

在我的情况下,我需要在没有HSE谐振器的板上校准RTC(这是一个小型手表原型,仅带有LSE晶体(32.768 kHz),该板没有HSE,并且需要时钟来自不稳定的RC内部振荡器)。但是对我有用的方法也应该适用于您的情况。

我的RTC校准方法的关键是:

  1. 快速,稳定的参考时钟。我使用了STM32F4发现板(带有8 MHz的HSE晶体和25 MHz的APB时钟速度(PLL提升)),计时器,如下所述。
  2. 非常准确的1PPS校准输入(每秒1加号)。 -我使用了其中一个引脚上具有1PPS输出的GPS模块。

在我的情况下,校准步骤如下:

  1. 使用计数器/计时器的输入捕获方法(连接到1PPS信号源(在本例中为GPS模块))上的引脚上计数多个1PPS事件之间的系统时钟滴答次数(选择正确的定时器宽度(16 vs 32位)和时钟分频(最好不进行分频以获得最大分辨率)。然后取平均值,以了解与假定时钟速度(在我的情况下为25 MHz)的偏差。它应该稳定,并且在测量期间变化不大(32秒的校准时间就足够了。)
  2. 然后计算多个1 Hz校准输出刻度(由目标MCU的LSE驱动)之间的系统时钟刻度数量(在其他引脚上使用输入捕获),并取平均值。 / li>
  3. 现在计算所需的LSE校正。并使用目标STM32上的RTC校准寄存器来调整RTC(另请参见参考手册或本Application Note (AN3371)中的 RTC平滑校准)。
  4. 重做步骤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 ...

答案 2 :(得分:0)

从LSE运行RTC,但将其校准为HSE。

执行my previous answer中的第一步,以获取准确的HSE时钟,但保持其在LSE上运行。

根据参考手册,

  

22.4.12 RTC平滑数字校准

     

可以以大约0.954 ppm的分辨率对RTC频率进行数字校准,范围为-487.1 ppm至+488.5 ppm。

校准在RTC->CALR寄存器中进行,即使在时钟运行时也可以平滑地进行调整。调整周期必须为32秒,才能达到0.954 ppm的精度。

配置RTC定期唤醒定时器以每32秒生成一次中断。将RTC警报连接到TIM21寄存器中TIM21->OR的TI1输入。配置TIM21以捕获TI1边缘。由于定时器只有16位,因此您必须计算TIM21中断处理程序中的溢出(更新事件)。发生捕获事件时,您将拥有经过的周期数,更新计数中的高半字,捕获寄存器中的低半字。如果它与标称值32 * 32 * 10 6 明显不同,请调整RTC->CALR并重复。

当更新和捕获大约同时发生时,难点在于正确,因此代码无法可靠地确定首先发生的是哪个。稍后再考虑。