In the past, you need modify rtc_api.c in mbed-dev source code. From this revision, you can just use RTC function all of conditions (Normal, Reset, Stand-by, Power OFF).

Note

From now on, you do NOT need any modification for mbed-dev library because STM team updates rtc_api.c source code and support RTC function under reset & standby condition includes power off condition (You need additional VBAT back-up hardware).

Please refer following NOTE information.
/users/kenjiArai/notebook/nucleo-series-rtc-control-under-power-onoff-and-re/

main.cpp

Committer:
kenjiArai
Date:
2021-03-06
Revision:
14:4b03106ece1f
Parent:
13:c1f984932e98

File content as of revision 14:4b03106ece1f:

/*
 * mbed Application program
 *      RTC (inside STM32x CPU) test program
 *
 * Copyright (c) 2015,'16,'17,'20, '21 Kenji Arai / JH1PJL
 *  http://www7b.biglobe.ne.jp/~kenjia/
 *  https://os.mbed.com/users/kenjiArai/
 *      Created: January   17th, 2015
 *      Revised: March      6th, 2021
 */

/*  mbed library now suports RTC continuous operation at Reset & Power ON/OFF
    --------------------------------------------------------------------------
    In the past, rtc_api.c (inside mbed) alway made a reset RTC registers
    when user push a reset buttom or terninate a power.
    Even if user configures a back-up circuit for RTC, mbed board could not
    keep proper time.
    --> Right now, you don't worry thoese issue.
 */

/*
    ----- Tested board -----
                  / Reset: / Stanby: / power off and restart:
    Nucleo-F401RE /  ok    /  ok     / ok (need following Back-up Circuit)
    Nucleo-F411RE /  ok    /  ok     / ok (need following Back-up Circuit)
    Nucleo-F446RE /  ok    /  ok     / ok (need following Back-up Circuit)
    not support on Mbed-os6.6.0 Nucleo-F334R8
    Nucleo-L476RG /  ok    /  ok     / ok (need following Back-up Circuit)
    DISCO-L45VG-IOT/ ok    /  ok     / ok (Need additional hardware)
    Nucleo-L152RE /  ok    /  ok     / no check (Need additional hardware)
    Nucleo-L073RZ /  ok    /  ok     / no check (Need additional hardware)
    not support on Mbed-os6.6.0 Nucleo-L053R8
    
    ----- add tested board -----
    Nucleo-F446ZE
    DISCO-F746NG
    Nucleo-F746ZG
    DISCO-F769NI
    Nucleo-H743ZI2
    Nucleo-F303K8
    Nucleo-L432KC

    < Back-up circuit >
    CN7 VIN <- SBD <- 330 Ohm <- CR2032 + - -> CN7 GND
    Remove SB45 Zero Ohm resistor

    ----- PLEASE REFER FOLLOWS ----
    https://os.mbed.com/users/kenjiArai/notebook/
                        nucleo-series-rtc-control-under-power-onoff-and-re/
 */

//  Include --------------------------------------------------------------------
#include "mbed.h"
#include "uart_as_stdio.h"

//  Definition -----------------------------------------------------------------
#if defined(TARGET_DISCO_F746NG)  \
 || defined(TARGET_NUCLEO_F746ZG) \
 || defined(TARGET_DISCO_F769NI)  \
 || defined(TARGET_DISCO_F469NI)  \
 || defined(TARGET_NUCLEO_F446ZE) \
 || defined(TARGET_NUCLEO_H743ZI2)
#define PUSHED_SW   1   // Active high
#elif  defined(TARGET_NUCLEO_F303K8) \
    || defined(TARGET_NUCLEO_L432KC)
#define USER_BUTTON A0  // temporary setting
#define PUSHED_SW   0   // Active low
#else
#define PUSHED_SW   0   // Active low
#endif

#define LONGLONGTIME    2147483647s

//  Object ---------------------------------------------------------------------
DigitalIn userSW(USER_BUTTON);
DigitalOut myled(LED1);                 // Indicate the sampling period

//  RAM ------------------------------------------------------------------------

//  ROM / Constant data --------------------------------------------------------
const char *const msg0 = "Is a time correct? If no, please hit any key. ";
const char *const msg1 = "<Push USER SW then enter the Standby mode> ";

//  Function prototypes --------------------------------------------------------
FileHandle *mbed::mbed_override_console(int fd);
static void time_enter_mode(void);
static void chk_and_set_time(char *ptr);
static int32_t xatoi (char **str, int32_t *res);
static void get_line (char *buff, int32_t len);
static void usr_sw_irq(void);
extern void print_revision(void);

//------------------------------------------------------------------------------
//  Control Program
//------------------------------------------------------------------------------
int main()
{
    char buf[64];
    time_t seconds;
    uint8_t wait_counter = 0;

    puts("\r\n\r\nTest Nucleo RTC Function.");
    print_revision();
    myled = !myled;
    ThisThread::sleep_for(500ms);
    myled = !myled;
    ThisThread::sleep_for(500ms);
    while(true) {
        seconds = time(NULL);
        strftime(buf, 50, " %B %d,'%y, %H:%M:%S\r\n", localtime(&seconds));
        printf("[Time] %s", buf);
        printf("%s", msg0);
        printf("%s", msg1);
        puts("\r");
        wait_counter = 0;
        while (seconds == time(NULL)) {
            if (readable() == 1) {
                buf[0] = getc();    // dummy read
                time_enter_mode();
            }
            if (userSW == PUSHED_SW) {  // goto sleep
                while (userSW == PUSHED_SW) {
                    ThisThread::sleep_for(10ms);
                }
                ThisThread::sleep_for(10ms);
                puts("Entered the standby mode. ");
#if defined(TARGET_NUCLEO_F303K8) || defined(TARGET_NUCLEO_L432KC)
                puts("Please change A0 level for wake-up(Reset).");
#else
                puts("Please push USER BUTTON to wake-up(Reset).");
#endif
                myled = 0;
 
                InterruptIn usr_sw(USER_BUTTON);
                ThisThread::sleep_for(1s);
                DigitalIn dmy0(LED1);
                DigitalIn dmy1(USBTX);
                DigitalIn dmy2(USBRX);
                usr_sw.fall(&usr_sw_irq); // actual push or chattering
                sleep_preparation();
                ThisThread::sleep_for(LONGLONGTIME);
            }
            ThisThread::sleep_for(50ms);
            if (++wait_counter > (2000 / 50)) {
                break;
            }
        }
        // delete previous strings
        // https://en.wikipedia.org/wiki/ANSI_escape_code#CSIsection
        // \33[ = CSI sequences, 1A=Cursor Up (one line), 2K=Erase in Line(all)
        //                       G=Cursor Horizontal Absolute
        printf("\33[1A\033[2K\033[G");
        myled = !myled;
    }
}

//  Interrupt for wake up
static void usr_sw_irq(void)
{
    system_reset(); // restart from RESET condition
}

//  Time adjustment
static void time_enter_mode(void)
{
    char *ptr;
    char linebuf[64];

    puts("Set time into RTC.");
    puts(" e.g. >21 3 3 3 33 33 -> March  03,'21, 03:33:33");
    puts(" If time is fine, just hit enter key.");
    putc('>');
    ptr = linebuf;
    get_line(ptr, sizeof(linebuf));
    putc('\r');
    chk_and_set_time(ptr);
}

//  Change string -> integer
static int32_t xatoi(char **str, int32_t *res)
{
    uint32_t val;
    uint8_t c, radix, s = 0;

    while ((c = **str) == ' ') (*str)++;
    if (c == '-') {
        s = 1;
        c = *(++(*str));
    }
    if (c == '0') {
        c = *(++(*str));
        if (c <= ' ') {
            *res = 0;
            return 1;
        }
        if (c == 'x') {
            radix = 16;
            c = *(++(*str));
        } else {
            if (c == 'b') {
                radix = 2;
                c = *(++(*str));
            } else {
                if ((c >= '0')&&(c <= '9')) {
                    radix = 8;
                }   else {
                    return 0;
                }
            }
        }
    } else {
        if ((c < '1')||(c > '9')) {
            return 0;
        }
        radix = 10;
    }
    val = 0;
    while (c > ' ') {
        if (c >= 'a') c -= 0x20;
        c -= '0';
        if (c >= 17) {
            c -= 7;
            if (c <= 9) return 0;
        }
        if (c >= radix) return 0;
        val = val * radix + c;
        c = *(++(*str));
    }
    if (s) val = -val;
    *res = val;
    return 1;
}

//  Get key input data
static void get_line(char *buff, int32_t len)
{
    char c;
    int32_t idx = 0;

    for (;;) {
        c = getc();
        //printf("0x%x \r\n", c);
        if (c == '\r') {
            buff[idx++] = c;
            break;
        }
        if ((c == '\b') && idx) {
            idx--;
            const char bf_bs[] =
            {0x1b, '[', '1', 'D', ' ', 0x1b, '[', '1', 'D'};
            printf(bf_bs, 9);
        }
        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
            buff[idx++] = c;
            putc(c);
        }
    }
    buff[idx] = 0;
    putc('\n');
}

//  Check key input strings and set time
static void chk_and_set_time(char *ptr)
{
    int32_t p1;
    struct tm t;
    time_t seconds;

    if (xatoi(&ptr, &p1)) {
        t.tm_year       = (uint8_t)p1 + 100;
        printf("Year:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_mon        = (uint8_t)p1 - 1;
        printf("Month:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_mday       = (uint8_t)p1;
        printf("Day:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_hour       = (uint8_t)p1;
        printf("Hour:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_min        = (uint8_t)p1;
        printf("Min:%d ",p1);
        xatoi( &ptr, &p1 );
        t.tm_sec        = (uint8_t)p1;
        printf("Sec: %d \r\n",p1);
    } else {
        return;
    }
    seconds = mktime(&t);
    set_time(seconds);
    // Show Time with several example
    // ex.1
    printf(
        "Date: %04d/%02d/%02d, %02d:%02d:%02d\r\n",
        t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec
    );
    char buf[64];
    // ex.2
    strftime(buf, 40, "%x %X", localtime(&seconds));
    printf("Date: %s\r\n", buf);
    // ex.3
    strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds));
    printf("Date: %s\r\n", buf);
    // ex.4
    strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds));
    printf("Date: %s\r\n", buf);
}