cancel
Showing results for 
Search instead for 
Did you mean: 

How to calibrate the STM32's real-time clock (RTC)

B.Montanari
ST Employee

Summary

This article provides a step-by-step guide on how to calibrate the precision of a real-time clock (RTC). The examples in this guide are provided using the NUCLEO-U575ZI-Q board, but can be tailored to any other STM32.

Introduction

The real-time clock (RTC) is a peripheral dedicated to providing an accurate measure of time and ideally never stop independent of the MCU status (running or in low-power mode). Common use cases involve tracking clock time, set up alarms and calendar. It can also be used as a wake-up interrupt trigger for low-power modes or periodic interrupt calls.

Time precision may vary depending on different factors. Different factors include frequency variation from the external oscillator/crystal used for the RTC clock source, which lets the STM32 can implement a digital calibration. ST has an application note for that, but it does not cover the firmware implementation example. 

This article aims to provide the calculations based on the reference manual and a step by step on the firmware implementation to generate the periodic counter corrections. The primary objective of this article is to cover how to calibrate the RTC to reduce the ppm error.

1. Development

1.1. Measuring a timer precision

The precision of timers is commonly measured using the parts per million (ppm) unit, which measures the number of errors that can occur every one million iterations. For reference, if we were to consider a 100ppm RTC timer and wanted to know the possible drift after one day or one year, this formula could be used: PPM / (1 × 106) × 86400 = Seconds of Error per day, where 86400 is the number of seconds in a day. This means that a timer working with 100 ppm has an imprecision of approximately 8.64 seconds per day which may result in up to 51 minutes per year.

1.2. Project configuration

All the following configurations are made using a STM32U575 microcontroller and the STM32CubeIDE 1.16.1 is used for programming and debugging.

Start by creating a new project in STM32CubeIDE by clicking [File] → [New] → [STM32 Project]. Select the [Board Selector] and in the empty field of [Commercial Part Number] type [NUCLEO-U575ZI-Q]
Select the first option in [Boards List] and then click [Next]. Choose a name for the project and press [Finish]. Use everything in default mode.

1.3. RTC configuration

The first step is to enable the RTC and select the calibration configuration 512 Hz. A pin is selected as RTC_OUT_CALIB, in this case PB2.

BMontanari_1-1732041172104.png

Also, it is recommended to enable the Low-Speed Clock (LSE) Crystal/Ceramic resonator, which is a highly accurate clock source commonly used to drive the RTC for clock/calendar or other timing functions. Be aware that the default selection is the LSI (Low-speed Internal) oscillator, which is not ideal for RTC applications due to its high PPM.

The figure below shows the step to enable the LSE and to verify if it is configured as the RTC clock source in the [Clock Configuration] tab.

BMontanari_2-1732041172109.png

 

BMontanari_3-1732041172111.png

These are all the needed steps. Now, you can generate the code by clicking [Project] → [Generate Code].
Build by pressing (CTRL+B) and program your STM32 microcontroller by clicking [Run][OK]. Now, by connecting an oscilloscope to the referred RTC_OUT_CALIB pin, you should obtain a wave with approximately 512Hz, 32768 divided by 64, like the illustration below:

BMontanari_4-1732041172112.png

The next step is to extract the current frequency from the RTC. The measurement period used for the calibration should be equal to the current calibration cycle update period, which is 32 as default. While there are several means to do this measurement, the article relies on the scope to acquire the needed time samples.
Given the default settings, the time to be sample should be at least a 32-wave interval, since we will start by using the calibration as 32.

If using a scope, align the cursor as precisely as possible with one of the edges. This article uses the rising edge from the calibration wave, as shown in the figure below.

BMontanari_5-1732041172113.png

This simple formula is used to acquire the average frequency. The 32 is due to the sampling interval used: Frequency = 1 / (period / 32).

As an example, the obtained period from the image above is 62.4995 ms. When applied to the formula the result is 512.004096 Hz, which means the real RTC frequency is this number multiplied by 64, equivalent to 32768.20972 Hz.

With this information, it is now possible to compare this pin output with the expected calibration frequency and obtain the current clock error. The following formula reflects this by calculating the average clock error in PPM: PPM error = ((Average Frequency - 512) / 512) x 106.

Based on the previous frequency, the average error is approximately 8 PPM. With this value, it is possible to adjust the RTC to compensate for the inaccuracies utilizing the registers CALP and CALM.
Note: Not all STM32 has the CALP.  For those STM32s without CALP, consider the steps detailed in the application note 2604.

1.4. RTC registers

Considering the STM32U5 series, 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 correction of the frequency is performed using a series of small adjustments (adding and/or subtracting individual ck_cal pulses). These adjustments are fairly well distributed so that the RTC is calibrated even when observed over a short duration of time. Make sure that the duration is at least the same size of the calibration period selected.

The smooth calibration register (RTC_CALR) specifies the number of ck_cal clock cycles to be masked during the calibration cycle:

  • Setting the bit CALM[0] to 1 causes exactly one pulse to be masked during the calibration cycle.
  • Setting CALM[1] to 1 causes two additional cycles to be masked.
  • Setting CALM[2] to 1 causes four additional cycles to be masked, and so on, up to CALM[8] set to 1 which causes 256 clocks to be masked.

While CALM permits the RTC frequency to be reduced by up to 487.1 ppm with fine resolution, the bit CALP can be used to increase the frequency by 488.5 ppm. Setting CALP to 1 effectively inserts an extra ck_cal pulse every 2^11 ck_cal cycles, which means that 512 clocks are added during every calibration cycle.

Using CALM together with CALP, an offset ranging from -511 to +512 ck_cal cycles can be added during the calibration cycle. It translates to a calibration range of -487.1 ppm to +488.5 ppm with a resolution of about 0.954 ppm. The relevant STM32 reference manual presents the formula to calibrate it.

Also in the RTC_CALR, there are two other bits that are relevant when it comes to precision and calibration cycle period, which uses 32 seconds as its default. The CALW8 and CALW16 bits can change the cycle period to 8 seconds or 16 seconds, but that comes at a cost. While the reference manual’s chapter related to the RTC, subsection "Verifying the RTC calibration" contains more details, the summary is available in this quick table:

 

Calibration cycle

Period (seconds)

Best obtainable error (ppm)

Default

32

0.477

CALW16

16

0.954

CALW8

8

1.907

 

1.5. RTC CALM calculation

To calculate the correct CALM value, use the formula below, which is the same formula provided in the reference manual, just isolating the CALM. Once calculated, convert the result to a hexadecimal number:

CALM = ( (CALP × 512 − (FCAL / (FRTCCLK − 1)) × 220 + (FCAL / (FRTCCLK − 1)) × CALP × 512) / (1 + (FCAL / (FRTCCLK − 1))).

FCAL is the desired frequency, which should be 32768 Hz, since it is the expected frequency generated from the LSE clock assuming 0ppm.

FTRCCLK is the actual frequency from the RTC before calibration, obtained by multiplying the average sampled frequency, in this case 512.004096 * 64, which lead to 32768.20972 Hz.

Applying the simple math equation, the CALM register value in hex is equal to 0x08.

If you inject the newly calculated value for CALM in the reference manual’s formula, it is possible to calculate the expected error using the formula: FCAL = FRTCCLK × (1 + (CALP × 512 − CALM) / (220 + CALM − CALP × 512)).

By adding the resulting FCAL inside an adjusted PPM error formula, which accounts for the fact that FCAL should be 64 times the value of the calibration wave, it is also possible to calculate the expected ppm: PPM error = ((FCAL / 64 − 512) / 512) × 106

1.6. Calibrating the RTC

Using the obtained CALM and CALP values we can use the function SetSmoothCalib from HAL_Driver to change the register RTC_CALR.

 

HAL_RTCEx_SetSmoothCalib(RTC_HandleTypeDef *hrtc, uint32_t SmoothCalibPeriod, uint32_t SmoothCalibPlusPulses, uint32_t SmoothCalibMinusPulsesValue)

 

The first parameter should be the RTC handler, which usually is hrtc.

The second parameter configures the intervals from the calibration cycle, in this example it should occur every 32 seconds, and can be configured as:

  • RTC_SMOOTHCALIB_PERIOD_32SEC
  • RTC_SMOOTHCALIB_PERIOD_16SEC
  • RTC_SMOOTHCALIB_PERIOD_8SEC

The third parameter sets the value of the CALP parameter, and can be one of the following values:

  • RTC_SMOOTHCALIB_PLUSPULSES_SET: Sets CALP to 1
  • RTC_SMOOTHCALIB_PLUSPULSES_RESET: Sets CALP to 0

The fourth parameter sets the CALM value, which needs to be a value between 0 to 0x000001FF. 

Now, insert the following code snippets with your necessary configurations inside the MX_RTC_Init function, RTC_Init_2 field:

 

/* USER CODE BEGIN RTC_Init 2 */
  HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_RESET, 0x8);
  /* USER CODE END RTC_Init 2 */

 

2. Results

Press the [Debug] button to program your STM32 microcontroller. There should be no errors or warnings. You can now check the RTC_OUT_CALIB pin waveform using the oscilloscope, extract the calibration frequency and calculate the PPM error using the same methods showed in the RTC configuration section. Note: The value 0x08 was used due to the calculation and collected average frequency used as an example.

Conclusion

The real-time clock is an important microcontroller peripheral for providing precise time measurement used to applications that range from calendars to wake-up signals for low-power modes. However, it can be unusable with incorrect calibration. In this article, we explored the step by step of how to calibrate the RTC for the magnitude of precision required for a determined application correctly.

Related links

Comments

Just to add a few details:

AN2604 is for the RTCv1, which is only in STM32F1xx, and differs significantly from all other STM32s' RTCs.

This article deals with Smooth calibration in RTCv2 (except STM32L1xx and STM32F2xx where RTCv2 has only Coarse calibration, which does not have a good description beyond what's in the respective RMs, AFAIK) and in RTCv3; these are described in AN4759 and Smooth calibration is described in chapter 2.5 therein. Of course, it is also described in the respective RMs so one should start by reading the Smooth calibration subchapter of RTC chapter there.

Also note, that the RTC Smooth calibration is not intended to correct for improper LSE hardware design (i.e. systemic RTC clock deviation caused e.g. by improper burden capacitors), just to compensate for manufacturing spread of the crystals and/or their aging. For LSE HW design guidance, see AN2867, which among other useful guidelines includes also example PCB layouts worth following.

That said, the RTC can be clocked also by some fraction of HSE in non-VBAT applications (details differ between STM32 families, see respective RM), and as those crystals are usually less precise, the RTC Smooth Calibration may be of utility there, too.

To measure the LSE deviation using the calibration output (which can be both 512Hz and 1Hz), there's usually also an option to compare LSE to some more precise external clock source (e.g. GPS 1PPS) through an optional link from LSE to some of the timers - details differ among STM32 families, see respective RM.

JW

Alizmay
Associate

512.004096 * 64 = 32768.20972?

(FCAL / (FRTCCLK − 1))?

CALM = CALP*512 - 220 * (1 - FRTCCLK/FCAL)

Version history
Last update:
‎2024-12-02 05:59 AM
Updated by: