8 years, 8 months ago.

RTC resets on power down with back up cell fitted

Last go at this.

I have 4 Nucleo boards with crystals and loading capacitors fitted. they all engage the crystals during start up and the RTC does work and keep time.

HOWEVER if the board is reset, the RTC time registers are cleared.

I have fitted a back up cell and confirmed 3v is present on the RTC Vin. The registers continue to be reset when the main MCU power is cycled or hard reset.

Clearly this should not happen.

After more than two years trying to get a resolve I'm begging to think it may be a better option to ditch the ST platform altogether.

Is it possible for someone from the ST team to finally resolve this?

(I have a wager on this question and I think I'm going to win it.)

Paul Have you tried using the (edited) E5V since powering the Board via the st-link will send a NRST to the Nucleo Board and thus reset the RTC. according to /mbed-src/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_hal_rtc.c you should be able to store and maintain the RTC but a Reset Power Down etc will reset the RTC, Just a thought Regards Martin

posted by Martin Simpson 19 Aug 2015

The problem is Martin there is a 'HAL_RCC_BACKUPRESET_FORCE();' in this API that I believe resets the RTC registers every time the MCU is powered or NRST. So in a back up cell fitted situation the RTC still gets that reset. I did spend some time switching code around here and got it nearly working but found on a total power down (remove back up cell as well) the RTC would not initialize. NRST should never reset the RTC registers with or without back up cell fitted.

When I looked further I found there was code affecting the RTC in many files of the library, so gave up at that point. I believe that's why this issue has not been addressed, it would involve a big re-write of the ST library to fix it.

posted by Paul Staron 19 Aug 2015

1 Answer

8 years, 8 months ago.

Problem is in rtc_time.c and rtc_api.c rtc_time needs the following edit

  if (_rtc_isenabled != NULL) {
        if (!(_rtc_isenabled())) {
					                                             //added the following three lines
					    if (_rtc_init != NULL) {
								_rtc_init();
							}
     //       set_time(0);// ORIG CODE HERE !!!!!!!!! commented out this will clear the RTC to Zero but alas not only here see below!
        }
    }

and rtc_api.c needs the following

void rtc_init(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct;
    uint32_t rtc_freq = 0;

    if (rtc_inited) return;
    rtc_inited = 1;

    RtcHandle.Instance = RTC;

    // Enable Power clock
    __PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Reset Backup domain
  //  __HAL_RCC_BACKUPRESET_FORCE(); // The following commented out they reset the registers directly
  //  __HAL_RCC_BACKUPRESET_RELEASE();

I wil get a PR Was able to reset NRST and remote all kept RTC values

Regards Martin

The code in rtc_time.c is in principle fine. The main issue there is that the rtc_isenabled code for the Nucleo ones is broken (since it simply uses a static variable instead of actually checking if it is enabled). That set_time(0) is intended to be there, since that is only called if it isn't enabled anyway.

So if it is possible to get correct isenabled() code I think it should already function as it should.

posted by Erik - 20 Aug 2015

After a system reset, the application can read the INITS flag in the RTC_ISR register to check if the calendar has been initialized or not. If this flag equals 0, the calendar has not been initialized since the year field is set at its RTC domain reset default value (0x00). To read the calendar after initialization, the software must first check that the RSF flag is set in the RTC_ISR register. So isenabled() can be linked to this register.

But where in the set up could that be done? there is a lot of library parts to the rtc.

Pretty sure I'm gonna win my bet.

posted by Paul Staron 20 Aug 2015

well maybe all we need is this then is from ../mbed-src/targets/cmsis/TARGET_STM/TARGET_STM32F4/stm32f4xx_hal_rcc.h

    /* --- BDCR Register ---*/
/* Alias word address of RTCEN bit */
#define RCC_BDCR_OFFSET            (RCC_OFFSET + 0x70)
#define RCC_RTCEN_BIT_NUMBER       0x0F
#define RCC_BDCR_RTCEN_BB          (PERIPH_BB_BASE + (RCC_BDCR_OFFSET * 32) + (RCC_RTCEN_BIT_NUMBER * 4))
/* Alias word address of BDRST bit */
#define RCC_BDRST_BIT_NUMBER       0x10
#define RCC_BDCR_BDRST_BB          (PERIPH_BB_BASE + (RCC_BDCR_OFFSET * 32) + (RCC_BDRST_BIT_NUMBER * 4))

in the rtc_api.c in the "rtc_init()" function test for the appropriate bit Regards Martin btw I don't see why we need to reset the RTC twice with setting the time to zero and using reset bit in RTC register maybe it's just me And the edit I suggested in the answer does work on a F401re

posted by Martin Simpson 20 Aug 2015

Thanks to the clues from you two it turns out as simple as this:

rtc_api.c snip

void rtc_init(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct;
    uint32_t rtc_freq = 0;
    
//add this code here:
//....................

    if(RTC->ISR != 7){ // Register Status Flag cold start value
        rtc_inited=1;
    }
//....................
        
    if (rtc_inited) return;
    rtc_inited = 1;

    RtcHandle.Instance = RTC;

The RSF is always '7' on a power up, then remains at '55' when the RTC has been set and on a reset. It may change to some other value depending on other RTC functions, but always seems to be '7' when MCU is powered up (without back up cell).

Need to make some more checks and refinements will probably be needed.

posted by Paul Staron 05 Sep 2015