Library 19- Use internal RTC on STM32F4

It’s been some time when I post last library. Next one is internal RTC library. STM32F4xx devices have Real Time Clock (RTC) inside, with support of internal calibrated 32768 Hz oscillator or external (more accurate) 32768 Hz oscillator.

RTC peripheral has also backup register support, which means that when you reset MCU, registers are not reset or if power is off and you have battery connected on Vbat pin, clock is still working.

RTC can also wakeup MCU from all powerdown modes. It has interrupt connected to EXTI lines which allows him to do that. As of version 1.1, you can now also wakeup MCU with alarm interrupt. This is now supported in library.

Library also provide converting time to epoch time (seconds from 01.01.1970 00:00:00) and back.

RTC peripheral has 2 between independent alarm sources which can trigger an interrupt once a week or once a month according to its settings. I have made a little explanation down, but you will see how to use it in example 2.

RTC Library

Features

  • Support Internal or external clock source
    • PC14 and PC15 pins are used for external crystal oscillator
    • STM32F4/429 Discovery does not have RTC crystal onboard. Check board’s manual on how to set it up
  • Support wakeup interrupt
  • Get seconds from 01.01.1970 00:00:00
  • Get readable time from seconds from 01.01.1970 00:00:00
  • Support to save/get data in binary or BCD format
  • Support for read/write data to/from RTC backup registers
  • Version 1.1 – October 20, 2014
    • Added support to set 2 internal alarms to trigger interrupts
    • They can also wake up STM32F4 from any low power mode
  • Version 1.2 – October 27, 2014
  • Version 1.4 – December 21, 2014
    • Added support to write data in string format,
    • Date&Time are checked before saved for valid input data
  • Version 1.5 – December 21, 2014
    • Added functions to get days in a month and days in a year
  • Version 1.7 – March 15, 2015
    • Added support for read/write from/to RTC backup registers

Dependencies

  • CMSIS
    • STM32F4xx
    • STM32F4xx RCC
    • STM32F4xx RTC
    • STM32F4xx PWR
    • STM32F4xx EXTI
    • MISC
  • TM
    • defines.h
    • attributes.h

Oscillator

STM32F4 has internal 32768 calibrated oscillator, which is not so calibrated as it is maybe heard. For any clock accuracy, you need external clock source. For this purpose, you can connect external 32768Hz crystal.

OSC 32768Hz STM32F4xx Description
OSC1 PC14 Oscillator pin 1
OSC2 PC15 Oscillator pin 2

Datetime structure

Time structure is used to work with time.

Datetime format structure

These are options which you use when set or get data from RTC.

Clock source structure

RTC can work with internal or external oscillator.

Remember: Internal RC oscillator (it says that is calibrated) is not accurate at all. It failed about 2 seconds per minute on my both discovery boards. Use external clock source.

Interrupt structure

Wakeup with RTC is also possible. Below is structure where you can set every x seconds interrupt will happen.

Initialize RTC peripheral

On power on, you have to initialize RTC peripheral. This function enables clock for RTC, synchronize registers and prepare RTC to work.

Set date and time

RTC is set to 01.01.01 00:00:00 on power up, if it is not configured before. If time is configured and reset happen, time should stay as it was before reset.

To set data, you have to fill time structure. When you do this, use

Get date and time

To get data from RTC you also need to have initialized time struct. Then use it like when you set date and time.

Seconds from 01.01.1970 00:00:00

I also made a function which calculates seconds from 01.01.1970 00:00:00.

Note: When you call function to get time from RTC, this function is also used to calculate time and store it in unix member of time structure.

Get date and time from 01.01.1970 00:00:00

Let’s say, that you are working on project where you have to save your time somehow. If you save date, month, year… separatelly, this will take a lot of bytes. If you convert time to seconds offset from 01.01.1970 00:00:00, and save it, that takes 4bytes, which is smaller. But than you have to get time back from this seconds. This is doing function below. It converts seconds from 1970 to a human readable time.

RTC wake up interrupt

Because RTC support wakeup interrupt, you can use it if you need it. For that purpose, I wrote a function. As parameter you have to pass it Interrupt time struct

Also, when you activate wakeup interrupt, if you want to handle it, you have to make another function somewhere in your project (let’s say in main.c)

RTC Alarms

RTC peripheral on STM32F4 has capability to trigger 2 different alarms, Alarm A and Alarm B. They can be set, to trigger interrupt one time in a week or one time in a month. Also, they are completely independent between each, but they have interrupt handler in common. You are of course able to set one alarm to be triggered each month and one to be triggered each week.

RTC subsecond

RTC in STM32F4 supports also subsecond accuracy. But here is one problem. Subsecond depends on values you set for your “prescaler”. STM32F4’s RTC has 2 predivision values:

  • ASYNC: 7-bit asynchronous prescaler
    • Max value can be 0x7F
  • SYNC: 15-bit synchronous prescaler
    • Max value can be 0x7FFF

These 2 values are used to “digital” fix inaccuracy for RTC. Equation for RTC 1Hz clock is:

rtc_1hz_clock = RTC_IN_CLK(LSI or LSE) / ((ASYNC + 1) * (SYNC + 1))

By changing these two values, you can set your custom prescaler for RTC, but result should always be one.

You are maybe asking, why I’m posting this in subsecond section. The point is also, that subsecond “resolution” depends on SYNC value. Bigger than this value is, better resolution you will get for subsecond, max of max SYNC value. Subsecond is a downcounter. When it reaches zero (0), seconds are updated and it’s reload value is the same as SYNC value. For that purpose I’ve also edit this two constants:

  • Before
    • ASYNC: 0x7F
    • SYNC: 0x00FF
  • Now
    • ASYNC: 0x1F
    • SYNC: 0x03FF

This give us now 1/1024 of a second resolution. Subseconds are read from RTC registers when you read clock. I have also made some modification to library, which now allows you to custom set values for ASYNC and SYNC. If you need to calibrate your RTC crystal, you can set them to match your crystal frequency.

To get proper milliseconds from last second, you can do some easy math:

  • General
    • milliseconds = 1000ms – (subseconds * 1000 / SYNC)
  • Our case
    • milliseconds = 1000ms – (subseconds * 1000 / 1023)
  • Subsecond register is downcounter, but we probably want milliseconds to raise with time, so 1000ms – is at the beginning of equation

Open defines.h file and edit settings:

  • When you set this new library, you have to set date and time again, or your settings will not be valid!
  • You can not set subseconds, you can just read it
    • When you update your clock, subsecond is set to reload value = SYNC value

Set date and time with string

Sometimes, useful function will be to set date and time using string format. For that purpose (in version 1.4) I’ve added this option. Function accepts pointer to string in format below:

Example 4 shows you how to use this.

RTC backup registers

RTC features 20 internal backup registers where you can store anything and will be available whole time RTC is active and has power.

My library uses backup register 19 (last one) to store informations about library, so you are not allowed to store data there. This is also prevent using my functions for that.

I’ve made 2 functions for this.

Look at example 5 how to use this.

Functions and enumerations

Below are listed all functions and enumerations used in this library. In new version 1.1, alarm is supported. How to properly use it, look at example 2.

Common questions

Why is RTC not updated on read?

When i developed this library, I found somekind of a bug on STM32F4 RTC peripheral. If I first read date register and then time register, date was not correct updated on read. If I turn this arround, so first time, then date, everything was perfect.

Example 1

  • Wakeup interrupt is triggered each second.
  • After trigger, date & time is read from MCU and displayed over USART3 to user.
  • If you press button on discovery boards, date & time is set to some other value.

Example 2

  • Example below works the same as Example 1, except Alarms A and B are activated
  • If you press the button, global date & time is set to 21:11:00
    • Alarm A is triggered each week at day 1 (Monday is day 1, Sunday is day 7) at time 21:11:05
      • After 5 seconds Alarm A is first time triggered
    • Alarm B is triggered each month at day 20 at time 21:11:10
      • After 10 seconds Alarm B is first time triggered

RTC Alarms A and B triggered

RTC Alarms A and B triggered


Example 3

  • Example below works the same as example 1, just subsecond is added to USART output.
  • Wakeup interrupt is set to 125ms, so you can see counter
  • Important
    • Subsecond register is downcounter, so do not be confused

Example 4

  • USART1 (TX: PB6, RX: PB7, 115200baud) waits for any string (with \n at the end),
  • received string is then analyzed with RTC internal checker,
  • if date and time are valid, RTC is set
  • For example, send from your USART:
    • 11.12.14.4;10:45:50\n
    • Date: 11
    • Month: 12
    • Year: 2014
    • Day in a week: 4 (Thursday)
    • Hours: 10
    • Minutes: 45
    • Seconds: 45

Example 5

  • If RTC is first time initialized, data is store to RTC backup register 4
  • If you press button on discovery/nucleo board, board will reset
  • After reset, RTC is still initialized and you will be able to test if written data is the same as read

Projects are available at Github, download library below.

tilz0R

Owner of this site. Application engineer, currently employed by STMicroelectronics. Exploring latest technologies and owner of different libraries posted on Github.

You may also like...

Read before commenting!

Before you make a new comment, make sure you agree with things listed below:

  • - Read post to make sure if it is already posted what you are asking for,
  • - Make sure you have the latest version of libraries used in your project,
  • - Make a clean and grammatically correct written message,
  • - Report as many details as possible, including what have you done so far,
  • - Do NOT post any code here. Use Pastebin,
  • - Do NOT post any error codes here. Use Pastebin,
  • - Specify STM32Fxxx family and used Discovery/EVAL/Nucleo or custom made board,
  • - Make sure your clock is set correct for PLL,
  • - If you are using my HAL drivers, please check this post how to start.
Comment will be deleted on breaking these rules without notification!