1

I'm using the B-L072Z-LRWAN1 with the CMWX1ZZABZ-091 LoRa® /Sigfox™ module (Murata)

The internal RTC (real time clock) is inaccurate and I'm seeing 10 seconds loss per day for some modules.

My question is, why could this be? Datasheet says 1.73 seconds / 20ppm for the LSE. The TXCO is 2ppm. How can I calibrate the RTC using TXCO?

I know there is also temperature that influences the accuracy but I think that is in an insignificant range i.e. does not explain 10seconds /day.

Flying Swissman
  • 818
  • 2
  • 14
  • 39
  • 1
    probably off-topic here (maybe more a hardware issue than a software one). Consider using [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol). How to use NTP is a different question that could be operating system specific – Basile Starynkevitch Jul 25 '18 at 07:31
  • I'm voting to close this question as off-topic because it is about a hardware real-time-clock module and not about programming. – Jim Garrison Jul 26 '18 at 01:36
  • You may get a better response on [electronics.se]. However, be sure to read [their on topic page](https://electronics.stackexchange.com/help/on-topic) and verify that any question you post there is appropriate for that site. – Makyen Jul 26 '18 at 05:55
  • 1
    @JimGarrison This is not a hardware topic, its a question concerning the software used to calibrate the hardware – Flying Swissman Jul 26 '18 at 06:22

3 Answers3

4

How can I calibrate the RTC using TXCO?

A while ago I asked myself the same question, and it took a while until I've found a solution, since there are many options documented in the reference manual and the topic can be quite confusing.

In my case, I needed to calibrate the RTC on a board without a HSE resonator (it was a small wrist watch prototype with only an LSE crystal (32.768 kHz), the board didn't have a HSE, and was clocked from the unstable RC internal oscillator). But the method that worked for me should be applicable in your situation as well.

The keys to my RTC calibration method were:

  1. A fast, stable reference clock. I've used a STM32F4 discovery board (with an 8 MHz HSE crystal, and a APB clock speed of 25 MHz (PLL'ed up), used by timers for the measurement described below).
  2. A very accurate 1PPS calibration input (1 Pluse Per Second). - I've used a GPS module with a 1PPS output on one of the pins.

The calibration steps were as follows in my case:

  1. Count the number of system clock ticks between multiple 1PPS events on a pin connected to the 1PPS signal source (GPS module in my case) with the Input Capture method of a Counter/Timer (choose the right timer width (16 vs 32 bit) and clock division (preferably no division to get maximum resolution)). Then take the average, to know the deviation from the assumed clock speed (25 MHz in my case). It should be stable, and not vary much during the measurement (32 seconds calibration time was enough).
  2. Then count the number of system clock ticks between multiple 1 Hz Calibration output ticks (driven by LSE of the target MCU) (using Input Capture on a different pin), and take the average.
  3. Now calculate the LSE correction required. And use the RTC calibration registers on the target STM32 to adjust the RTC (see also RTC Smooth Calibration in the reference manual or this Application Note (AN3371)).
  4. Redo steps 1 and 2 to verify the correction.

Make sure to undo any RTC correction before starting the calibration:

 if (HAL_RTCEx_SetSmoothCalib(
        &hrtc,
        RTC_SMOOTHCALIB_PERIOD_32SEC,
        RTC_SMOOTHCALIB_PLUSPULSES_RESET,
        0) != HAL_OK) {
    error_handler();
  }
  start_calibration();

To calculate the correction, I've use something similar to this:

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");
}

After measuring the required correction, I've copy-pasted the code manually and had to flash the target board to verify the calibration. Later on, it would nicer to have the option to do the calibration while the device is already deployed...

I've used this on an STM32L011, but the method is more or less independent from the type of MCU. In my case, I used the 8 MHz HSE and a 32-bit counter on the STM32F4 discovery board. But this method should work in modified form also without additional hardware (besides the 1PPS source), when a fast, stable HSE is present. - I managed to get less then 1 PPM deviation, and the RTC kept time accurately for several of days (changes in temperature can influence the accuracy quite a bit, as I had to find out).

The findings were also discussed in the STM32 forum, but the page is down right now, so I can't point you to that...

rel
  • 764
  • 5
  • 18
3

(false statement about LSE removed)

How can I calibrate the RTC using TXCO?

TXCO can supply HSE, and you can derive the RTC clock from HSE through a series of prescalers.

Section 8.5 in the User Manual says,

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.

First, close SB13 with a drop of tin.

PH0_OSC_IN is the HSE bypass clock source. Set HSEBYP then HSEON in RCC->CR to have an accurate 32 MHz HSE clock. But wait, first you have to set RTCPRE to 3 in order to prescale it by 16 for the RTC module. Select this as the RTC clock in RCC->CSR.

Now the RCC generates a 2 MHz clock for the RTC (fRTCCLK = 2000000). You scale it further down to 1 Hz (fCK_SPRE = 1) with the RTC->PRER register. It has two bitfields, PREDIV_A can go from 0 to 127, PREDIV_S from 0 to 32767. Solving the integer equation

fCK_SPRE = fRTCCLK / ((PREDIV_S + 1) × (PREDIV_A + 1))

with the above constraints gives

PREDIV_S = 24999
PREDIV_A = 79

so using

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

you'd have an accurate 1 Hz clock for RTC.

0

Running RTC from LSE, but calibrating it to HSE.

Do the first steps in my previous answer to obtain an accurate HSE clock, but leave it running from LSE.

From the Reference Manual,

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.

The calibration is done in the RTC->CALR register, it can be smoothly adjusted even while the clock is running. The adjust period must be 32 seconds for 0.954 ppm accuracy.

Configure the RTC Periodic Wakeup Timer to generate an interrupt every 32 seconds. Connect the RTC Alarm to the TI1 Input of TIM21 in the TIM21->OR register. Configure TIM21 to capture a TI1 edge. As the timer is only 16 bits, you have to count the overflows (update events) in the TIM21 interrupt handler. When the Capture event occurs, you have the elapsed number of cycles, high halfword in the update count, low halfword in the capture register. If it differs significantly from the nominal value of 32 * 32 * 106, adjust RTC->CALR and repeat.

The difficulty is getting it right when the update and the capture occurs at approximately at the same time, so the code can't reliably decide which one has occured first. I'll give some more thought to it later.