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/
Diff: SetRTC.cpp
- Revision:
- 0:e4c20fd769f1
- Child:
- 1:3129de8d50ea
- Child:
- 2:765470eab2a6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SetRTC.cpp Sat Feb 07 02:19:57 2015 +0000 @@ -0,0 +1,379 @@ +/* + * 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 7th, 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); +} + +#else +#error "No suport this mbed, only for Nucleo mbed" +#endif +// defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_L152RE)