8 years, 11 months ago.

What might cause RTC Backup Domain Reset when LSI is clocking RTC versus LSE on STM32F4 ?

Hello I have a STM32F411 where the RTC is reset (TR=0) and (ISR=7) when the device is reset while fully powered with LSI clocking RTC versus LSE. When LSE is selected everything works great.

My desire to use LSI stems from the need use the LSI in a case where LSE is not functioning reliably. I am not concerned with time drift, but need the RTC for timed sleep intervals.

I copy RTC_ISR and RTC_TR to an unused area of memory at the very beginning of SystemInit() then read that memory print print the results after the system has finished its init and transferred control to main().

This lets me know that nothing is generating a Backup-Domain reset later on in the init process, e.g. in HAL_Init()... I have implemented code to handle rtc_init() resetting RTC as mentioned in other threads..

When LSE is selected, resetting or sleeping the device causes no problems. I see values I expect in TR and a non- 0x7 value in RTC_ISR. When LSI is selected, reset kills the RTC and it ends up stopped (Backup Domain Reset) where also the Backup Registers (user 20 words) are also cleared.

As a double check when I have selected LSE if I put my finger on the 32KHz XTAL (after touching ground , not exposing device to ESD) the clock stops (I print the time every time it changes) then resumes when I remove my finger (only when LSE selected - no change when LSI of course). Also, I double checked LSEON/RDY and LSION/RDY registers to verify I am using the correct oscillator before I thought up finger test.

Help! Anyone Have some ideas?

What kind of program are you excuting? You need to concern not only RTC itself but also RTC clock source slection likes RCC_BDCR and/or RCC_CSR. Please confirm LSI clock goes to RTC module or not.

posted by Kenji Arai 27 Jan 2016

Hello Kenji, Thanks for your reply. My program relies on performing a NVIC_SystemReset() call after sleep. Maybe this is what is getting me into trouble with trying to keep RTC running with LSI source. After a soft/hard reset, I see RCC_BDCR is not reset by Internal or External Reset which carries enable bits for LSE, but that RCC_CSR (which has LSI enable bit LSION) is reset to a value where LSI is turned off. (Referencing RM0383 July 2014 version Page 128). I could live with restarting LSI, after reset but in the process a backup domain reset happens clearing the RTC registers. I have not looked at trying to save RTC state just before issuing Reset. Maybe on wakeup,just before I order the NVIC_SystemReset() I could save the RTC user registers which I store state information in designed to survive system reset (20 on this device) to unused area of SRAM and also save current time and date, then recover just after reset. Does my thinking sound reasonable?

PS Yes, I confirmed that the LSI was clocking the RTC. I even went into the LSI init code in rtc_api.c and changed the divisor on LSI init so the RTC would be clocked at 2X. In my program after forcing rtc_init() The RTC would start counting time at 2X. Also, to note that I implemented code suggested on mbed to disable init of RTC when ISR register was not in its reset configuration. That is mainly if power has not failed on start-up then don't do rtc_init().

I know this is the type of thing where code might be helpful, but really comparing RTC registers between LSE operation and LSI operation at the start of execution could not be much simpler, well, so I say. Ha!

posted by Ron Grant 27 Jan 2016

2 Answers

8 years, 10 months ago.

Below is the fix for the RTC to stop register reset on POR or nRST and NVIC_SystemReset() . In fact this covers all the STM platforms that uses the same RTC peripheral.

Copy & paste the whole chunk to replace the existing code.

Haven't tried using with LSI, didn't see the point as it is soooo inaccurate for time functions.

The LSI set up is in the RTC_API.c, it should be the same unless NVIC_SystemReset() somehow resets it elsewhere. In which case you will need to restart it.

rtc_api.c

/* mbed Microcontroller Library
 *******************************************************************************
 * Copyright (c) 2014, STMicroelectronics
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of STMicroelectronics nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************
 */
#include "rtc_api.h"

#if DEVICE_RTC

#include "mbed_error.h"

static RTC_HandleTypeDef RtcHandle;

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

    if ((RTC->ISR & RTC_ISR_INITS) ==  RTC_ISR_INITS) return;

    RtcHandle.Instance = RTC;

    // Enable Power clock
    __PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Reset Backup domain
    __HAL_RCC_BACKUPRESET_FORCE();
    __HAL_RCC_BACKUPRESET_RELEASE();

    // Enable LSE Oscillator
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; /* Mandatory, otherwise the PLL is reconfigured! */
    RCC_OscInitStruct.LSEState       = RCC_LSE_ON; /* External 32.768 kHz clock on OSC_IN/OSC_OUT */
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) == HAL_OK) {
        // Connect LSE to RTC
        __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE);
        __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
        rtc_freq = LSE_VALUE;
    } else {
        // Enable LSI clock
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
        RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
        RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
        RCC_OscInitStruct.LSIState       = RCC_LSI_ON;
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
            error("RTC error: LSI clock initialization failed.");
        }
        // Connect LSI to RTC
        __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSI);
        __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI);
        // [TODO] This value is LSI typical value. To be measured precisely using a timer input capture
        rtc_freq = LSI_VALUE;
    }

    // Enable RTC
    __HAL_RCC_RTC_ENABLE();

    RtcHandle.Init.HourFormat     = RTC_HOURFORMAT_24;
    RtcHandle.Init.AsynchPrediv   = 127;
    RtcHandle.Init.SynchPrediv    = (rtc_freq / 128) - 1;
    RtcHandle.Init.OutPut         = RTC_OUTPUT_DISABLE;
    RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    RtcHandle.Init.OutPutType     = RTC_OUTPUT_TYPE_OPENDRAIN;

    if (HAL_RTC_Init(&RtcHandle) != HAL_OK) {
        error("RTC error: RTC initialization failed.");
    }
}

void rtc_free(void)
{
    // Enable Power clock
    __PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Reset Backup domain
    __HAL_RCC_BACKUPRESET_FORCE();
    __HAL_RCC_BACKUPRESET_RELEASE();

    // Disable access to Backup domain
    HAL_PWR_DisableBkUpAccess();

    // Disable LSI and LSE clocks
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE;
    RCC_OscInitStruct.LSIState       = RCC_LSI_OFF;
    RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
}

int rtc_isenabled(void)
{
   if ((RTC->ISR & RTC_ISR_INITS) ==  RTC_ISR_INITS){
        return 1;
    } else {
        return 0;
    }
}

/*
 RTC Registers
   RTC_WeekDay 1=monday, 2=tuesday, ..., 7=sunday
   RTC_Month   1=january, 2=february, ..., 12=december
   RTC_Date    day of the month 1-31
   RTC_Year    year 0-99
 struct tm
   tm_sec      seconds after the minute 0-61
   tm_min      minutes after the hour 0-59
   tm_hour     hours since midnight 0-23
   tm_mday     day of the month 1-31
   tm_mon      months since January 0-11
   tm_year     years since 1900
   tm_wday     days since Sunday 0-6
   tm_yday     days since January 1 0-365
   tm_isdst    Daylight Saving Time flag
*/
time_t rtc_read(void)
{
    RTC_DateTypeDef dateStruct;
    RTC_TimeTypeDef timeStruct;
    struct tm timeinfo;

    RtcHandle.Instance = RTC;

    // Read actual date and time
    // Warning: the time must be read first!
    HAL_RTC_GetTime(&RtcHandle, &timeStruct, FORMAT_BIN);
    HAL_RTC_GetDate(&RtcHandle, &dateStruct, FORMAT_BIN);

    // Setup a tm structure based on the RTC
    timeinfo.tm_wday = dateStruct.WeekDay;
    timeinfo.tm_mon  = dateStruct.Month - 1;
    timeinfo.tm_mday = dateStruct.Date;
    timeinfo.tm_year = dateStruct.Year + 100;
    timeinfo.tm_hour = timeStruct.Hours;
    timeinfo.tm_min  = timeStruct.Minutes;
    timeinfo.tm_sec  = timeStruct.Seconds;

    // Convert to timestamp
    time_t t = mktime(&timeinfo);

    return t;
}

void rtc_write(time_t t)
{
    RTC_DateTypeDef dateStruct;
    RTC_TimeTypeDef timeStruct;

    RtcHandle.Instance = RTC;
    
     // Enable Power clock
    __HAL_RCC_PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Convert the time into a tm
    struct tm *timeinfo = localtime(&t);

    // Fill RTC structures
    dateStruct.WeekDay        = timeinfo->tm_wday;
    dateStruct.Month          = timeinfo->tm_mon + 1;
    dateStruct.Date           = timeinfo->tm_mday;
    dateStruct.Year           = timeinfo->tm_year - 100;
    timeStruct.Hours          = timeinfo->tm_hour;
    timeStruct.Minutes        = timeinfo->tm_min;
    timeStruct.Seconds        = timeinfo->tm_sec;
    timeStruct.TimeFormat     = RTC_HOURFORMAT12_PM;
    timeStruct.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    timeStruct.StoreOperation = RTC_STOREOPERATION_RESET;

    // Change the RTC current date/time
    HAL_RTC_SetDate(&RtcHandle, &dateStruct, FORMAT_BIN);
    HAL_RTC_SetTime(&RtcHandle, &timeStruct, FORMAT_BIN);
}

#endif

8 years, 10 months ago.

Hi Ron, I just give you a small hint. It looks like rtc_init() routine problem. Please import my library as below.

/users/kenjiArai/code/SetRTC/

In addition, you need to use mbed-dev (supersedes mbed-src) library and delete mbed lib.

/users/mbed_official/code/mbed-dev/

In your case, you need to modify following part in “rtc_api_F4xx.c” (part of SetRTC lib.) line 124.

rtc_api_F4xx.c

#if defined(ORIGINAL) 
    // Enable LSE Oscillator
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; /* Mandatory, otherwise the PLL is reconfigured! */
    RCC_OscInitStruct.LSEState       = RCC_LSE_ON; /* External 32.768 kHz clock on OSC_IN/OSC_OUT */
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) == HAL_OK) {
        // Connect LSE to RTC
        __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE);
        __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
        rtc_freq = LSE_VALUE;
    } else {
        // Enable LSI clock
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
        RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
        RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
        RCC_OscInitStruct.LSIState       = RCC_LSI_ON;
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
            error("RTC error: LSI clock initialization failed.");
        }
        // Connect LSI to RTC
        __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSI);
        __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI);
        // [TODO] This value is LSI typical value. To be measured precisely using a timer input capture
        rtc_freq = LSI_VALUE;
    }
#else
    // Enable LSI clock
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
    RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
    RCC_OscInitStruct.LSIState       = RCC_LSI_ON;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        error("RTC error: LSI clock initialization failed.");
    }
    // Connect LSI to RTC
    __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSI);
    __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI);
    // [TODO] This value is LSI typical value. To be measured precisely using a timer input capture
    rtc_freq = LSI_VALUE;
#endif

Remark: I have NOT tested this modification.