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:
- 2016-07-02
- Revision:
- 14:78e453d7bb85
- Parent:
- 13:44e5327acb05
File content as of revision 14:78e453d7bb85:
/* * mbed Library program * Check & set RTC function and set proper clock if we can set * ONLY FOR "Nucleo Board" * * Copyright (c) 2014,'15,'16 Kenji Arai / JH1PJL * http://www.page.sannet.ne.jp/kenjia/index.html * http://mbed.org/users/kenjiArai/ * Created: October 24th, 2014 * Revised: July 2nd, 2016 * * 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_STM32F401RE) || defined(TARGET_STM32F411RE) \ || defined(TARGET_STM32L152RE) || defined(TARGET_STM32F334R8) \ || defined(TARGET_STM32L476RG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) //#define DEBUG // use Communication with PC(UART) // Include --------------------------------------------------------------------------------------- #include "mbed.h" #include "SetRTC.h" #if (defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) #include "stm32f7xx_hal.h" #endif // 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); static void set_5v_drop_detect(uint8_t function_use); //------------------------------------------------------------------------------------------------- // Control Program //------------------------------------------------------------------------------------------------- int32_t SetRTC(uint8_t use_comparator) { if (rtc_external_osc_init() == 1) { set_5v_drop_detect(use_comparator); return 1; } else { return 0; } } int32_t set_RTC_LSE(void) { uint32_t timeout = 0; //---------------------------- LSE Configuration ------------------------- // Enable Power Clock __PWR_CLK_ENABLE(); // Enable write access to Backup domain #if (defined(TARGET_STM32L476RG) || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG)) PWR->CR1 |= PWR_CR1_DBP; #else PWR->CR |= PWR_CR_DBP; #endif // Wait for Backup domain Write protection disable timeout = HAL_GetTick() + DBP_TIMEOUT_VALUE; PRINTF("Time-Out %d\r\n", timeout); #if (defined(TARGET_STM32L476RG) || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG)) while((PWR->CR1 & PWR_CR1_DBP) == RESET) { #else while((PWR->CR & PWR_CR_DBP) == RESET) { #endif if(HAL_GetTick() >= timeout) { PRINTF("Time-Out 1\r\n"); return 0; } else { PRINTF("GetTick: %d\r\n",HAL_GetTick()); } } // Reset LSEON and LSEBYP bits before configuring the LSE ---------------- __HAL_RCC_LSE_CONFIG(RCC_LSE_OFF); // Get timeout timeout = HAL_GetTick() + TIMEOUT; PRINTF("Time-Out %d\r\n", 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 0; } else { PRINTF("GetTick: %d\r\n",HAL_GetTick()); } } // Set the new LSE configuration ----------------------------------------- __HAL_RCC_LSE_CONFIG(RCC_LSE_ON); // Get timeout timeout = HAL_GetTick() + TIMEOUT; PRINTF("Time-Out %d\r\n", timeout); // Wait till LSE is ready #if (defined(TARGET_STM32F401RE) || defined(TARGET_STM32F411RE) \ || defined(TARGET_STM32F334R8) || defined(TARGET_STM32L476RG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) while((RCC->BDCR & 0x02) != 2){ #elif defined(TARGET_STM32L152RE) while(__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) { #endif if(HAL_GetTick() >= timeout) { PRINTF("Time-Out 3\r\n"); return 0; } else { PRINTF("GetTick: %d\r\n",HAL_GetTick()); } } PRINTF("OK\r\n"); return 1; } 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 #if (defined(TARGET_STM32L476RG) || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG)) PWR->CR1 |= PWR_CR1_DBP; #else PWR->CR |= PWR_CR_DBP; #endif // Wait for Backup domain Write protection disable timeout = HAL_GetTick() + DBP_TIMEOUT_VALUE; #if (defined(TARGET_STM32L476RG) || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG)) while((PWR->CR1 & PWR_CR1_DBP) == RESET) { #else while((PWR->CR & PWR_CR_DBP) == RESET) { #endif if(HAL_GetTick() >= timeout) { return 0; } } __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 0; } } // Connect LSI to RTC #if !(defined(TARGET_STM32F334R8) || defined(TARGET_STM32L476RG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSI); #endif __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSI); return 1; } int32_t rtc_external_osc_init(void) { uint32_t timeout = 0; time_t seconds; uint8_t external_ok = 1; // Enable Power clock __PWR_CLK_ENABLE(); // Enable access to Backup domain HAL_PWR_EnableBkUpAccess(); // Check backup condition if ( check_RTC_backup_reg() ) { #if (defined(TARGET_STM32F401RE) || defined(TARGET_STM32F411RE) \ || defined(TARGET_STM32F334R8) || defined(TARGET_STM32L476RG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) if ((RCC->BDCR & 0x8307) == 0x8103){ #else if ((RCC->CSR & 0x430703) == 0x410300) { #endif //if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) != RESET) { timeout = HAL_GetTick() + TIMEOUT / 5; seconds = time(NULL); while (seconds == time(NULL)){ if(HAL_GetTick() >= timeout) { PRINTF("Not available External Xtal\r\n"); external_ok = 0; break; } } if (external_ok){ PRINTF("OK everything\r\n"); return 1; } } } PRINTF("Reset RTC LSE config.\r\n"); // Reset Backup domain __HAL_RCC_BACKUPRESET_FORCE(); __HAL_RCC_BACKUPRESET_RELEASE(); // Enable LSE Oscillator if (set_RTC_LSE() == 1) { // Connect LSE to RTC #if !(defined(TARGET_STM32F334R8) || defined(TARGET_STM32L476RG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) __HAL_RCC_RTC_CLKPRESCALER(RCC_RTCCLKSOURCE_LSE); #endif __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE); PRINTF("Set LSE/External\r\n"); return 1; } else { set_RTC_LSI(); PRINTF("Set LSI/Internal\r\n"); return 0; } } 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\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 ); #if (defined(TARGET_STM32F401RE) || defined(TARGET_STM32F411RE) \ || defined(TARGET_STM32L152RE) ) pcr.printf( " CALIBR=0x....%04x, ALRMAR=0x%08x, ALRMBR=0x%08x\r\n", RTC->CALIBR, RTC->ALRMAR, RTC->ALRMBR ); #endif 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", RTC->TSTR, RTC->TSDR, RTC->TSSSR ); pcr.printf( "Show RCC registers (only RTC Related reg.)\r\n" ); #if (defined(TARGET_STM32F401RE) || defined(TARGET_STM32F411RE) \ || defined(TARGET_STM32F334R8) || defined(TARGET_STM32L476RG) \ || defined(TARGET_STM32F746NG) || defined(TARGET_STM32F746ZG) ) pcr.printf( " RCC_BDCR=0x...%05x\r\n", RCC->BDCR); #else pcr.printf( " RCC_CSR =0x%08x\r\n", RCC->CSR); #endif pcr.printf( "\r\n"); } // 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. >16 5 28 10 11 12 -> May 28th, '16, 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_STM32L152RE) void goto_standby(void) { RCC->AHBENR |= (RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOHEN); #if 0 GPIO_InitTypeDef GPIO_InitStruct; // All other ports are analog input mode GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_LOW; 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 GPIOA->MODER = 0xffffffff; GPIOB->MODER = 0xffffffff; GPIOC->MODER = 0xffffffff; GPIOD->MODER = 0xffffffff; GPIOE->MODER = 0xffffffff; GPIOH->MODER = 0xffffffff; #endif RCC->AHBENR &= ~(RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN |RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN | RCC_AHBENR_GPIOHEN); while(1) { #if 0 // Stop mode HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); #else // Standby mode HAL_PWR_EnterSTANDBYMode(); #endif } } #else // defined(TARGET_STM32L152RE) void goto_standby(void) { deepsleep(); // Not Standby Mode but Deep Sleep Mode } #endif // defined(TARGET_STM32L152RE) #if defined(TARGET_STM32L152RE) #if defined(USE_IRQ_FOR_RTC_BKUP) // COMP2 Interrupt routine void irq_comp2_handler(void) { __disable_irq(); goto_standby(); } COMP_HandleTypeDef COMP_HandleStruct; GPIO_InitTypeDef GPIO_InitStruct; // Set BOR level3 (2.54 to 2.74V) void set_BOR_level3(void) { FLASH_OBProgramInitTypeDef my_flash; HAL_FLASHEx_OBGetConfig(&my_flash); // read current configuration if (my_flash.BORLevel != OB_BOR_LEVEL3) { my_flash.BORLevel = OB_BOR_LEVEL3; HAL_FLASHEx_OBProgram(&my_flash); } } void set_5v_drop_detect(uint8_t function_use) { if (function_use == 0){ return;} set_BOR_level3(); // Set Analog voltage input (PB5 or PB6) #if defined(USE_PB5_FOR_COMP) GPIO_InitStruct.Pin = GPIO_PIN_5; // PB5 comp input #elif defined(USE_PB6_FOR_COMP) GPIO_InitStruct.Pin = GPIO_PIN_6; // PB6 comp input #else #error "Please define USE_PB5_FOR_COMP or USE_PB6_FOR_COMP in SetRTC.h" #endif GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); // COMP2 sets for low volatage detection __COMP_CLK_ENABLE(); COMP_HandleStruct.Instance = COMP2; COMP_HandleStruct.Init.InvertingInput = COMP_INVERTINGINPUT_VREFINT; #if defined(USE_PB5_FOR_COMP) COMP_HandleStruct.Init.NonInvertingInput = COMP_NONINVERTINGINPUT_PB5; #elif defined(USE_PB6_FOR_COMP) COMP_HandleStruct.Init.NonInvertingInput = COMP_NONINVERTINGINPUT_PB6; #endif COMP_HandleStruct.Init.Output = COMP_OUTPUT_NONE; COMP_HandleStruct.Init.Mode = COMP_MODE_HIGHSPEED; COMP_HandleStruct.Init.WindowMode = COMP_WINDOWMODE_DISABLED; COMP_HandleStruct.Init.TriggerMode = COMP_TRIGGERMODE_IT_FALLING; HAL_COMP_Init(&COMP_HandleStruct); // Interrupt configuration NVIC_SetVector(COMP_IRQn, (uint32_t)irq_comp2_handler); HAL_NVIC_SetPriority(COMP_IRQn, 0, 0); HAL_NVIC_ClearPendingIRQ(COMP_IRQn); HAL_COMP_Start_IT(&COMP_HandleStruct); HAL_NVIC_EnableIRQ(COMP_IRQn); } #else // defined(USE_IRQ_FOR_RTC_BKUP) void set_5v_drop_detect(uint8_t function_use) { ; // No implementation } #endif // defined(USE_IRQ_FOR_RTC_BKUP) #else // defined(TARGET_STM32L152RE) void set_5v_drop_detect(uint8_t function_use) { ; // No implementation } #endif // defined(TARGET_STM32L152RE) #else // defined(TARGET_STM32F401RE,_F411RE,_L152RE,_F334R8,_L476RG, _F746xx) #error "No suport this mbed, only for Nucleo mbed" #endif // defined(TARGET_STM32F401RE,_F411RE,_L152RE,_F334R8,_L476RG, _F746xx)