This is a RTC additional function. This is only for Nucleo F401RE & F411RE mbed(Added L152RE, F334R8, L476RG & F746xx). If you connected battery backup circuit for internal RTC, you can make a power-off and reset condition. RTC still has proper time and date.

Dependents:   Nucleo_rtos_sample PB_Emma_Ethernet

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

SetRTC.cpp

Committer:
kenjiArai
Date:
2015-02-14
Revision:
1:3129de8d50ea
Parent:
0:e4c20fd769f1

File content as of revision 1:3129de8d50ea:

/*
 * mbed Library program
 *      Check & set RTC function and set proper clock if we can set
 *      ONLY FOR "Nucleo Board"
 *
 *  Copyright (c) 2014-2015 Kenji Arai / JH1PJL
 *  http://www.page.sannet.ne.jp/kenjia/index.html
 *  http://mbed.org/users/kenjiArai/
 *      Created:  October   24th, 2014
 *      Revised:  Feburary  14th, 2015
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
 * AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_L152RE)

//#define DEBUG         // use Communication with PC(UART)

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

//  Definition ------------------------------------------------------------------------------------
#ifdef DEBUG
#define BAUD(x)         pcr.baud(x)
#define GETC(x)         pcr.getc(x)
#define PUTC(x)         pcr.putc(x)
#define PRINTF(...)     pcr.printf(__VA_ARGS__)
#define READABLE(x)     pcr.readable(x)
#else
#define BAUD(x)         {;}
#define GETC(x)         {;}
#define PUTC(x)         {;}
#define PRINTF(...)     {;}
#define READABLE(x)     {;}
#endif

//  Object ----------------------------------------------------------------------------------------
Serial pcr(USBTX, USBRX);

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

//  ROM / Constant data ---------------------------------------------------------------------------

//  Function prototypes ---------------------------------------------------------------------------
static int32_t set_RTC_LSI(void);
static int32_t set_RTC_LSE(void);
static int32_t rtc_external_osc_init(void);
static uint32_t read_RTC_reg(uint32_t RTC_BKP_DR);
static uint32_t check_RTC_backup_reg( void );
static int xatoi (char **str, unsigned long *res);
static void get_line (char *buff, int len);

//-------------------------------------------------------------------------------------------------
//  Control Program
//-------------------------------------------------------------------------------------------------
int32_t SetRTC()
{
    if (rtc_external_osc_init() == OK) {
        return OK;
    } else {
        return NG;
    }
}

int32_t set_RTC_LSE(void)
{
    uint32_t timeout = 0;

    //---------------------------- LSE Configuration -------------------------
    // Enable Power Clock
    __PWR_CLK_ENABLE();
    // Enable write access to Backup domain
    PWR->CR |= PWR_CR_DBP;
    // Wait for Backup domain Write protection disable
    timeout = HAL_GetTick() + DBP_TIMEOUT_VALUE;
    while((PWR->CR & PWR_CR_DBP) == RESET) {
        if(HAL_GetTick() >= timeout) {
            PRINTF("Time-Out 1\r\n");
            return NG;
        }
    }
    // Reset LSEON and LSEBYP bits before configuring the LSE ----------------
    __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF);
    // Get timeout
    timeout = HAL_GetTick() + TIMEOUT;
    // Wait till LSE is ready
    while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET) {
        if(HAL_GetTick() >= timeout) {
            PRINTF("Time-Out 2\r\n");
            return NG;
        }
    }
    // Set the new LSE configuration -----------------------------------------
    __HAL_RCC_LSE_CONFIG(RCC_LSE_ON);
    // Get timeout
    timeout = HAL_GetTick() + TIMEOUT;
    // Wait till LSE is ready
    while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) {
        if(HAL_GetTick() >= timeout) {
            PRINTF("Time-Out 3\r\n");
            return NG;
        }
    }
    PRINTF("OK");
    return OK;
}

int32_t set_RTC_LSI(void)
{
    uint32_t timeout = 0;

    // 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 Power Clock
    __PWR_CLK_ENABLE();
    // Enable write access to Backup domain
    PWR->CR |= PWR_CR_DBP;
    // Wait for Backup domain Write protection disable
    timeout = HAL_GetTick() + DBP_TIMEOUT_VALUE;
    while((PWR->CR & PWR_CR_DBP) == RESET) {
        if(HAL_GetTick() >= timeout) {
            return NG;
        }
    }
    __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF);
    // Enable LSI
    __HAL_RCC_LSI_ENABLE();
    timeout = HAL_GetTick() + TIMEOUT;
    // Wait till LSI is ready
    while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) {
        if(HAL_GetTick() >= timeout) {
            return NG;
        }
    }
    // Connect LSI to RTC
    __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSI);
    __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI);
    return OK;
}

int32_t rtc_external_osc_init(void)
{
    // Enable Power clock
    __PWR_CLK_ENABLE();
    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();
    // Check backup condition
    if ( check_RTC_backup_reg() ) {
        return OK;
    } else {
        // Reset Backup domain
        __HAL_RCC_BACKUPRESET_FORCE();
        __HAL_RCC_BACKUPRESET_RELEASE();
        // Enable LSE Oscillator
        if (set_RTC_LSE() == OK) {
            // Connect LSE to RTC
            __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE);
            __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
            return OK;
        } else {
            set_RTC_LSI();
            return NG;
        }
    }
}

uint32_t read_RTC_reg(uint32_t RTC_BKP_DR)
{
    __IO uint32_t tmp = 0;

    // Check the parameters
    assert_param(IS_RTC_BKP(RTC_BKP_DR));
    tmp = RTC_BASE + 0x50;
    tmp += (RTC_BKP_DR * 4);
    // Read the specified register
    return (*(__IO uint32_t *)tmp);
}

// Check RTC Backup registers contents
uint32_t check_RTC_backup_reg( void )
{
    if ( read_RTC_reg( RTC_BKP_DR0 ) == RTC_DAT0 ) {
        if ( read_RTC_reg( RTC_BKP_DR1 ) == RTC_DAT1 ) {
            return 1;
        }
    }
    return 0;
}

void show_RTC_reg( void )
{
    // Show registers
    pcr.printf( "\r\nShow RTC registers by JH1PJL\r\n" );
    pcr.printf( " Reg0  =0x%08x, Reg1  =0x%08x\r\n",
                read_RTC_reg( RTC_BKP_DR0 ),
                read_RTC_reg( RTC_BKP_DR1 )
              );
    pcr.printf( " TR    =0x..%06x, DR    =0x..%06x, CR    =0x..%06x\r\n",
                RTC->TR, RTC->DR, RTC->CR
              );
    pcr.printf( " ISR   =0x...%05x, PRER  =0x..%06x, WUTR  =0x....%04x\r\n",
                RTC->ISR, RTC->PRER, RTC->WUTR
              );
    pcr.printf( " CALIBR=0x....%04x, ALRMAR=0x%08x, ALRMBR=0x%08x\r\n",
                RTC->CALIBR, RTC->ALRMAR, RTC->ALRMBR
              );
    pcr.printf(
        " WPR   =0x......%02x, SSR   =0x....%04x, SHIFTR=0x....%04x\r\n",
        RTC->WPR, RTC->SSR, RTC->SHIFTR
    );
    pcr.printf(
        " TSTR  =0x..%06x, TSDR  =0x....%04x, TSSSR =0x....%04x\r\n\r\n",
        RTC->TSTR, RTC->TSDR, RTC->TSSSR
    );
}

//  Change string -> integer
int xatoi (char **str, unsigned long *res)
{
    unsigned long val;
    unsigned char 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
void get_line (char *buff, int len)
{
    char c;
    int idx = 0;

    for (;;) {
        c = pcr.getc();
        if (c == '\r') {
            buff[idx++] = c;
            break;
        }
        if ((c == '\b') && idx) {
            idx--;
            pcr.putc(c);
            pcr.putc(' ');
            pcr.putc(c);
        }
        if (((uint8_t)c >= ' ') && (idx < len - 1)) {
            buff[idx++] = c;
            pcr.putc(c);
        }
    }
    buff[idx] = 0;
    pcr.putc('\n');
}


// RTC related subroutines
void chk_and_set_time(char *ptr)
{
    unsigned long 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
    pcr.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);
#if 0
    time_t seconds;
    char buf[40];

    seconds = mktime(&t);
    // ex.2
    strftime(buf, 40, "%x %X", localtime(&seconds));
    pcr.printf("Date: %s\r\n", buf);
    // ex.3
    strftime(buf, 40, "%I:%M:%S %p (%Y/%m/%d)", localtime(&seconds));
    pcr.printf("Date: %s\r\n", buf);
    // ex.4
    strftime(buf, 40, "%B %d,'%y, %H:%M:%S", localtime(&seconds));
    pcr.printf("Date: %s\r\n", buf);
#endif
}

void time_enter_mode(void)
{
    char *ptr;
    char linebuf[64];

    pcr.printf("\r\nSet time into RTC\r\n");
    pcr.printf(" e.g. >15 2 7 10 11 12 -> Feb. 7th, '15, 10:11:12\r\n");
    pcr.printf(" If time is fine, just hit enter\r\n");
    pcr.putc('>');
    ptr = linebuf;
    get_line(ptr, sizeof(linebuf));
    pcr.printf("\r");
    chk_and_set_time(ptr);
}

#if defined(TARGET_NUCLEO_L152RE)
void deepsleep_preparation(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    // Port C sets analog mode except Xtal 32.768kHz pins
    GPIO_InitStruct.Pin = (uint16_t)0x3FFF; // 32.768kHz Xtal, PC15 & PC14
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    // All other ports are analog input mode
    GPIO_InitStruct.Pin = GPIO_PIN_All;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    HAL_GPIO_Init(GPIOH, &GPIO_InitStruct);
}
#else   // defined(TARGET_NUCLEO_L152RE)
void deepsleep_preparation(void)
{
    ;   // No implementation
}
#endif  // defined(TARGET_NUCLEO_L152RE)
#else   // defined(TARGET_NUCLEO_F401RE,TARGET_NUCLEO_F411RE,TARGET_NUCLEO_L152RE)
#error "No suport this mbed, only for Nucleo mbed"
#endif  // defined(TARGET_NUCLEO_F401RE,TARGET_NUCLEO_F411RE,TARGET_NUCLEO_L152RE)