Thanks to visit codestin.com
Credit goes to github.com

Skip to content

STM32F1: RTC does not advance date when running from VBAT for long periods of timeย #87

Closed
@ArrestedLightning

Description

@ArrestedLightning

I am working on a project based on the STM32F1 and have found an issue with this library. I am using a custom board which should be equivalent to a blue pill board for the purposes of this issue. (32.768KHz RTC oscillator, 8MHz main oscillator, 3V CR2032 attached to the VBAT pin, USB-TTL serial adapter on pins PA9 and PA10.)
If the board is powered down (i.e. only VBAT is present) when the clock rolls over from 23:59 to 00:00, the time will be correct when main power is reapplied to the board, but the date will not advance if the power is off for more than hour.

I have created a short Arduino sketch which demonstrates the issue:

#include <STM32RTC.h>
STM32RTC& rtc = STM32RTC::getInstance();

HardwareSerial Serial1(PA10, PA9);

const byte seconds = 0;
const byte minutes = 58;
const byte hours = 23;
const byte weekDay = 1;
const byte day = 1;
const byte month = 1;
const byte year = 23;

void setup()
{
  pinMode(PB0, INPUT_PULLUP);
  Serial1.begin(115200);
  rtc.setClockSource(STM32RTC::LSE_CLOCK);
  rtc.begin(STM32RTC::HOUR_24); // initialize RTC 24H format
  
  Serial1.println("---------------------------------------------------------------"); 
  
  if (digitalRead(PB0) == 0) {
    rtc.setTime(hours, minutes, seconds);
    rtc.setDate(weekDay, day, month, year);
    Serial1.printf("RTC reset to %d:%d:%d %d-%d-%d\n", hours, minutes, seconds, year, month, day);
  }
}

void loop()
{
  Serial1.printf("%02d-%02d-%02d ", rtc.getYear(), rtc.getMonth(), rtc.getDay());
  Serial1.printf("%02d:%02d:%02d.%03d\n", rtc.getHours(), rtc.getMinutes(), rtc.getSeconds(), rtc.getSubSeconds());
  delay(1000);
}

To demonstrate the issue, power on the board with pin B0 shorted to ground, then power it off and wait 10 minutes. When it is powered on again, it will print out the following:

---------------------------------------------------------------
23-01-02 00:10:01.000
23-01-02 00:10:02.000

Note that both the date and time have advanced, as expected.

Then repeat the process: power on the board with pin B0 shorted to ground, then power it off and wait 70 minutes. When it is powered on again, it will print out the following:

---------------------------------------------------------------
23-01-01 01:10:48.000
23-01-01 01:10:49.000

In this case, the time has advanced as expected, but the date has not. Leaving the device powered off for longer periods of time will produce similar results.

As I understand it, the STM32F1 does not have a hardware calendar, so the RTC is just used as a flat seconds counter that (when the CPU is running) is reset every 86400 seconds. Since it is a 32-bit register, there is no technical reason that it couldn't handle more than one day's worth of time, assuming the logic was implemented to support this.

Looking into how the library is implemented, I see that RTC_SetDate is used to set the date from backup RAM when the RTC is initialized:

STM32RTC/src/rtc.c

Lines 487 to 490 in 58da1ed

memcpy(&RtcHandle.DateToUpdate, &BackupDate, 4);
/* and fill the new RTC Date value */
RTC_SetDate(RtcHandle.DateToUpdate.Year, RtcHandle.DateToUpdate.Month,
RtcHandle.DateToUpdate.Date, RtcHandle.DateToUpdate.WeekDay);

RTC_SetDate does not contain any logic to handle advancing the date, though, and in fact intentionally subtracts out any accumulated days:
https://github.com/STMicroelectronics/STM32CubeF1/blob/2976d3b5b5cd1178ece18546e697c497c29d9c14/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rtc.c#L962-L969

However, the logic to advance the date based on accumulated counter time does in fact already exist, in the HAL_RTC_GetTime and RTC_DateUpdate functions:
https://github.com/STMicroelectronics/STM32CubeF1/blob/2976d3b5b5cd1178ece18546e697c497c29d9c14/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rtc.c#L825-L832
https://github.com/STMicroelectronics/STM32CubeF1/blob/2976d3b5b5cd1178ece18546e697c497c29d9c14/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rtc.c#L882

This function even pulls in the backup date from the RtcHandle structure. It seems a little strange to use the GetTime function to actually set the date, but it does not seem to have any other side effects.

I have experimented with replacing the RTC_SetDate call with HAL_RTC_GetTime in the RTC_Init function, and in my testing have found that it appears to resolve the issue, at least for my application. The date is advanced correctly even after being powered off for several days.

https://github.com/ArrestedLightning/STM32RTC/blob/7243392c9bd14c40b534ab96ac5cb333a4cf2909/src/rtc.c#L487-L490

However, I am not sure if there may be other side effects due to this change, or additional changes required for other code paths that I'm not using; someone who is more familiar with the code base would have to comment on that.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions