diff --git a/stmhal/boards/PYBV10/mpconfigboard.h b/stmhal/boards/PYBV10/mpconfigboard.h index 7aa9804986..fece733308 100644 --- a/stmhal/boards/PYBV10/mpconfigboard.h +++ b/stmhal/boards/PYBV10/mpconfigboard.h @@ -22,9 +22,12 @@ #define MICROPY_HW_CLK_PLLN (336) #define MICROPY_HW_CLK_PLLP (RCC_PLLP_DIV2) #define MICROPY_HW_CLK_PLLQ (7) +#define MICROPY_HW_CLK_LAST_FREQ (1) // The pyboard has a 32kHz crystal for the RTC #define MICROPY_HW_RTC_USE_LSE (1) +#define MICROPY_HW_RTC_USE_US (0) +#define MICROPY_HW_RTC_USE_CALOUT (1) // UART config #define MICROPY_HW_UART1_NAME "XB" diff --git a/stmhal/diskio.c b/stmhal/diskio.c index a15dce1aa5..8c8c8ee15b 100644 --- a/stmhal/diskio.c +++ b/stmhal/diskio.c @@ -279,6 +279,7 @@ DWORD get_fattime ( void ) { + rtc_init_finalise(); RTC_TimeTypeDef time; RTC_DateTypeDef date; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); diff --git a/stmhal/main.c b/stmhal/main.c index f6d6ada703..ffbd6cfa96 100644 --- a/stmhal/main.c +++ b/stmhal/main.c @@ -422,7 +422,7 @@ soft_reset: #if MICROPY_HW_ENABLE_RTC if (first_soft_reset) { - rtc_init(); + rtc_init_start(); } #endif diff --git a/stmhal/modmachine.c b/stmhal/modmachine.c index c495573fb1..25977e789c 100644 --- a/stmhal/modmachine.c +++ b/stmhal/modmachine.c @@ -39,6 +39,7 @@ #include "pin.h" #include "timer.h" #include "usb.h" +#include "rtc.h" #include "i2c.h" #include "spi.h" @@ -281,6 +282,9 @@ STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) { } else { RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; } + uint32_t h = RCC_ClkInitStruct.AHBCLKDivider >> 4; + uint32_t b1 = RCC_ClkInitStruct.APB1CLKDivider >> 10; + uint32_t b2 = RCC_ClkInitStruct.APB2CLKDivider >> 10; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { goto fail; } @@ -312,6 +316,23 @@ STATIC mp_obj_t machine_freq(mp_uint_t n_args, const mp_obj_t *args) { // re-init TIM3 for USB CDC rate timer_tim3_init(); + #if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ + #if defined(MCU_SERIES_F7) + #define FREQ_BKP BKP31R + #else + #define FREQ_BKP BKP19R + #endif + // qqqqqqqq pppppppp nnnnnnnn nnmmmmmm + // qqqqQQQQ ppppppPP nNNNNNNN NNMMMMMM + // 222111HH HHQQQQPP nNNNNNNN NNMMMMMM + p = (p / 2) - 1; + RTC->FREQ_BKP = m + | (n << 6) | (p << 16) | (q << 18) + | (h << 22) + | (b1 << 26) + | (b2 << 29); + #endif + return mp_const_none; fail:; @@ -349,6 +370,8 @@ STATIC mp_obj_t machine_sleep(void) { MP_DEFINE_CONST_FUN_OBJ_0(machine_sleep_obj, machine_sleep); STATIC mp_obj_t machine_deepsleep(void) { + rtc_init_finalise(); + #if defined(MCU_SERIES_F7) printf("machine.deepsleep not supported yet\n"); #else diff --git a/stmhal/modutime.c b/stmhal/modutime.c index 8892295582..8502e0fd62 100644 --- a/stmhal/modutime.c +++ b/stmhal/modutime.c @@ -57,6 +57,7 @@ STATIC mp_obj_t time_localtime(mp_uint_t n_args, const mp_obj_t *args) { if (n_args == 0 || args[0] == mp_const_none) { // get current date and time // note: need to call get time then get date to correctly access the registers + rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); @@ -119,6 +120,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(time_mktime_obj, time_mktime); STATIC mp_obj_t time_time(void) { // get date and time // note: need to call get time then get date to correctly access the registers + rtc_init_finalise(); RTC_DateTypeDef date; RTC_TimeTypeDef time; HAL_RTC_GetTime(&RTCHandle, &time, FORMAT_BIN); diff --git a/stmhal/rtc.c b/stmhal/rtc.c index 561548ee49..8fdb112504 100644 --- a/stmhal/rtc.c +++ b/stmhal/rtc.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "rtc.h" #include "irq.h" +#include "mphalport.h" /// \moduleref pyb /// \class RTC - real time clock @@ -52,112 +53,18 @@ static mp_uint_t rtc_info; // Note: LSI is around (32KHz), these dividers should work either way // ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1) +// modify RTC_ASYNCH_PREDIV & RTC_SYNCH_PREDIV in board//mpconfigport.h to change sub-second ticks +// default is 3906.25 µs, min is ~30.52 µs (will increas Ivbat by ~500nA) +#ifndef RTC_ASYNCH_PREDIV #define RTC_ASYNCH_PREDIV (0x7f) +#endif +#ifndef RTC_SYNCH_PREDIV #define RTC_SYNCH_PREDIV (0x00ff) - -#if 0 -#define RTC_INFO_USE_EXISTING (0) -#define RTC_INFO_USE_LSE (1) -#define RTC_INFO_USE_LSI (3) - -void rtc_init(void) { - // Enable the PWR clock - RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); - - // Allow access to RTC - PWR_BackupAccessCmd(ENABLE); - - if (RTC_ReadBackupRegister(RTC_BKP_DR0) == 0x32F2) { - // RTC still alive, so don't re-init it - // wait for RTC APB register synchronisation - RTC_WaitForSynchro(); - rtc_info = RTC_INFO_USE_EXISTING; - return; - } - - uint32_t timeout = 10000000; - - // Enable the PWR clock - RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); - - // Allow access to RTC - PWR_BackupAccessCmd(ENABLE); - - // Enable the LSE OSC - RCC_LSEConfig(RCC_LSE_ON); - - // Wait till LSE is ready - mp_uint_t sys_tick = sys_tick_counter; - while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) && (--timeout > 0)) { - } - - // record how long it took for the RTC to start up - rtc_info = (sys_tick_counter - sys_tick) << 2; - - // If LSE timed out, use LSI instead - if (timeout == 0) { - // Disable the LSE OSC - RCC_LSEConfig(RCC_LSE_OFF); - - // Enable the LSI OSC - RCC_LSICmd(ENABLE); - - // Wait till LSI is ready - while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET) { - } - - // Use LSI as the RTC Clock Source - RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); - - // record that we are using the LSI - rtc_info |= RTC_INFO_USE_LSI; - } else { - // Use LSE as the RTC Clock Source - RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); - - // record that we are using the LSE - rtc_info |= RTC_INFO_USE_LSE; - } - - // Note: LSI is around (32KHz), these dividers should work either way - // ck_spre(1Hz) = RTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1) - uint32_t uwSynchPrediv = 0xFF; - uint32_t uwAsynchPrediv = 0x7F; - - // Enable the RTC Clock - RCC_RTCCLKCmd(ENABLE); - - // Wait for RTC APB registers synchronisation - RTC_WaitForSynchro(); - - // Configure the RTC data register and RTC prescaler - RTC_InitTypeDef RTC_InitStructure; - RTC_InitStructure.RTC_AsynchPrediv = uwAsynchPrediv; - RTC_InitStructure.RTC_SynchPrediv = uwSynchPrediv; - RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24; - RTC_Init(&RTC_InitStructure); - - // Set the date (BCD) - RTC_DateTypeDef RTC_DateStructure; - RTC_DateStructure.RTC_Year = 0x13; - RTC_DateStructure.RTC_Month = RTC_Month_October; - RTC_DateStructure.RTC_Date = 0x26; - RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Saturday; - RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure); - - // Set the time (BCD) - RTC_TimeTypeDef RTC_TimeStructure; - RTC_TimeStructure.RTC_H12 = RTC_H12_AM; - RTC_TimeStructure.RTC_Hours = 0x01; - RTC_TimeStructure.RTC_Minutes = 0x53; - RTC_TimeStructure.RTC_Seconds = 0x00; - RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure); - - // Indicator for the RTC configuration - RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2); -} #endif +STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc); +STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse); +STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc); STATIC void RTC_CalendarConfig(void); #if defined(MICROPY_HW_RTC_USE_LSE) && MICROPY_HW_RTC_USE_LSE @@ -165,8 +72,40 @@ STATIC bool rtc_use_lse = true; #else STATIC bool rtc_use_lse = false; #endif +STATIC uint32_t rtc_startup_tick; +STATIC bool rtc_need_init_finalise = false; -void rtc_init(void) { +// check if LSE exists +// not well tested, should probably be removed +STATIC bool lse_magic(void) { +#if 0 + uint32_t mode_in = GPIOC->MODER & 0x3fffffff; + uint32_t mode_out = mode_in | 0x40000000; + GPIOC->MODER = mode_out; + GPIOC->OTYPER &= 0x7fff; + GPIOC->BSRRH = 0x8000; + GPIOC->OSPEEDR &= 0x3fffffff; + GPIOC->PUPDR &= 0x3fffffff; + int i = 0xff0; + __IO int d = 0; + uint32_t tc = 0; + __IO uint32_t j; + while (i) { + GPIOC->MODER = mode_out; + GPIOC->MODER = mode_in; + for (j = 0; j < d; j++) ; + i--; + if ((GPIOC->IDR & 0x8000) == 0) { + tc++; + } + } + return (tc < 0xff0)?true:false; +#else + return false; +#endif +} + +void rtc_init_start(void) { RTCHandle.Instance = RTC; /* Configure RTC prescaler and RTC data registers */ @@ -184,6 +123,7 @@ void rtc_init(void) { RTCHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RTCHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; + rtc_need_init_finalise = false; if ((RCC->BDCR & (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) == (RCC_BDCR_LSEON | RCC_BDCR_LSERDY)) { // LSE is enabled & ready --> no need to (re-)init RTC // remove Backup Domain write protection @@ -193,8 +133,8 @@ void rtc_init(void) { // provide some status information rtc_info |= 0x40000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; return; - } else if ((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) { - // LSI is already active + } else if (((RCC->BDCR & RCC_BDCR_RTCSEL) == RCC_BDCR_RTCSEL_1) && ((RCC->CSR & 3) == 3)) { + // LSI configured & enabled & ready --> no need to (re-)init RTC // remove Backup Domain write protection HAL_PWR_EnableBkUpAccess(); // Clear source Reset Flag @@ -204,16 +144,33 @@ void rtc_init(void) { rtc_info |= 0x80000 | (RCC->BDCR & 7) | (RCC->CSR & 3) << 8; return; } + rtc_startup_tick = HAL_GetTick(); + rtc_info = 0x3f000000 | (rtc_startup_tick & 0xffffff); + if (rtc_use_lse) { + if (lse_magic()) { + // don't even try LSE + rtc_use_lse = false; + rtc_info &= ~0x01000000; + } + } + PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse); +} - mp_uint_t tick = HAL_GetTick(); +void rtc_init_finalise() { + if (!rtc_need_init_finalise) { + return; + } - if (HAL_RTC_Init(&RTCHandle) != HAL_OK) { + rtc_info = 0x20000000 | (rtc_use_lse << 28); + if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { if (rtc_use_lse) { // fall back to LSI... rtc_use_lse = false; + rtc_startup_tick = HAL_GetTick(); + PYB_RTC_MspInit_Kick(&RTCHandle, rtc_use_lse); HAL_PWR_EnableBkUpAccess(); RTCHandle.State = HAL_RTC_STATE_RESET; - if (HAL_RTC_Init(&RTCHandle) != HAL_OK) { + if (PYB_RTC_Init(&RTCHandle) != HAL_OK) { rtc_info = 0x0100ffff; // indicate error return; } @@ -225,11 +182,10 @@ void rtc_init(void) { } // record how long it took for the RTC to start up - rtc_info = HAL_GetTick() - tick; + rtc_info |= (HAL_GetTick() - rtc_startup_tick) & 0xffff; // fresh reset; configure RTC Calendar RTC_CalendarConfig(); - if(__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET) { // power on reset occurred rtc_info |= 0x10000; @@ -240,15 +196,192 @@ void rtc_init(void) { } // Clear source Reset Flag __HAL_RCC_CLEAR_RESET_FLAGS(); + rtc_need_init_finalise = false; +} + +STATIC HAL_StatusTypeDef PYB_RCC_OscConfig(RCC_OscInitTypeDef *RCC_OscInitStruct) { + /*------------------------------ LSI Configuration -------------------------*/ + if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSI) == RCC_OSCILLATORTYPE_LSI) { + // Check the LSI State + if (RCC_OscInitStruct->LSIState != RCC_LSI_OFF) { + // Enable the Internal Low Speed oscillator (LSI). + __HAL_RCC_LSI_ENABLE(); + } else { + // Disable the Internal Low Speed oscillator (LSI). + __HAL_RCC_LSI_DISABLE(); + } + } + + /*------------------------------ LSE Configuration -------------------------*/ + if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_LSE) == RCC_OSCILLATORTYPE_LSE) { + // Enable Power Clock + __PWR_CLK_ENABLE(); + HAL_PWR_EnableBkUpAccess(); + uint32_t tickstart = HAL_GetTick(); + + #if defined(MCU_SERIES_F7) + //__HAL_RCC_PWR_CLK_ENABLE(); + // Enable write access to Backup domain + //PWR->CR1 |= PWR_CR1_DBP; + // Wait for Backup domain Write protection disable + while ((PWR->CR1 & PWR_CR1_DBP) == RESET) { + if (HAL_GetTick() - tickstart > RCC_DBP_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + #else + // Enable write access to Backup domain + //PWR->CR |= PWR_CR_DBP; + // Wait for Backup domain Write protection disable + while ((PWR->CR & PWR_CR_DBP) == RESET) { + if (HAL_GetTick() - tickstart > DBP_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + #endif + + // Set the new LSE configuration + __HAL_RCC_LSE_CONFIG(RCC_OscInitStruct->LSEState); + } + + return HAL_OK; +} + +STATIC HAL_StatusTypeDef PYB_RTC_Init(RTC_HandleTypeDef *hrtc) { + // Check the RTC peripheral state + if (hrtc == NULL) { + return HAL_ERROR; + } + if (hrtc->State == HAL_RTC_STATE_RESET) { + // Allocate lock resource and initialize it + hrtc->Lock = HAL_UNLOCKED; + // Initialize RTC MSP + if (PYB_RTC_MspInit_Finalise(hrtc) != HAL_OK) { + return HAL_ERROR; + } + } + + // Set RTC state + hrtc->State = HAL_RTC_STATE_BUSY; + + // Disable the write protection for RTC registers + __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc); + + // Set Initialization mode + if (RTC_EnterInitMode(hrtc) != HAL_OK) { + // Enable the write protection for RTC registers + __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); + + // Set RTC state + hrtc->State = HAL_RTC_STATE_ERROR; + + return HAL_ERROR; + } else { + // Clear RTC_CR FMT, OSEL and POL Bits + hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL)); + // Set RTC_CR register + hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity); + + // Configure the RTC PRER + hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv); + hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16); + + // Exit Initialization mode + hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT; + + #if defined(MCU_SERIES_F7) + hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE; + hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType); + #else + hrtc->Instance->TAFCR &= (uint32_t)~RTC_TAFCR_ALARMOUTTYPE; + hrtc->Instance->TAFCR |= (uint32_t)(hrtc->Init.OutPutType); + #endif + + // Enable the write protection for RTC registers + __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc); + + // Set RTC state + hrtc->State = HAL_RTC_STATE_READY; + + return HAL_OK; + } +} + +STATIC void PYB_RTC_MspInit_Kick(RTC_HandleTypeDef *hrtc, bool rtc_use_lse) { + /* To change the source clock of the RTC feature (LSE, LSI), You have to: + - Enable the power clock using __PWR_CLK_ENABLE() + - Enable write access using HAL_PWR_EnableBkUpAccess() function before to + configure the RTC clock source (to be done once after reset). + - Reset the Back up Domain using __HAL_RCC_BACKUPRESET_FORCE() and + __HAL_RCC_BACKUPRESET_RELEASE(). + - Configure the needed RTc clock source */ + + // RTC clock source uses LSE (external crystal) only if relevant + // configuration variable is set. Otherwise it uses LSI (internal osc). + + RCC_OscInitTypeDef RCC_OscInitStruct; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + if (rtc_use_lse) { + RCC_OscInitStruct.LSEState = RCC_LSE_ON; + RCC_OscInitStruct.LSIState = RCC_LSI_OFF; + } else { + RCC_OscInitStruct.LSEState = RCC_LSE_OFF; + RCC_OscInitStruct.LSIState = RCC_LSI_ON; + } + PYB_RCC_OscConfig(&RCC_OscInitStruct); + + // now ramp up osc. in background and flag calendear init needed + rtc_need_init_finalise = true; +} + +#define PYB_LSE_TIMEOUT_VALUE 1000 // ST docs spec 2000 ms LSE startup, seems to be too pessimistic +#define PYB_LSI_TIMEOUT_VALUE 500 // this is way too pessimistic, typ. < 1ms + +STATIC HAL_StatusTypeDef PYB_RTC_MspInit_Finalise(RTC_HandleTypeDef *hrtc) { + // we already had a kick so now wait for the corresponding ready state... + if (rtc_use_lse) { + // we now have to wait for LSE ready or timeout + uint32_t tickstart = rtc_startup_tick; + while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET) { + if ((HAL_GetTick() - tickstart ) > PYB_LSE_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + } else { + // we now have to wait for LSI ready or timeout + uint32_t tickstart = rtc_startup_tick; + while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) == RESET) { + if ((HAL_GetTick() - tickstart ) > PYB_LSI_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + } + + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; + if (rtc_use_lse) { + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; + } else { + PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + } + if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { + //Error_Handler(); + return HAL_ERROR; + } + + // enable RTC peripheral clock + __HAL_RCC_RTC_ENABLE(); + return HAL_OK; } STATIC void RTC_CalendarConfig(void) { - // set the date to 1st Jan 2014 + // set the date to 1st Jan 2015 RTC_DateTypeDef date; - date.Year = 14; + date.Year = 15; date.Month = 1; date.Date = 1; - date.WeekDay = RTC_WEEKDAY_WEDNESDAY; + date.WeekDay = RTC_WEEKDAY_THURSDAY; if(HAL_RTC_SetDate(&RTCHandle, &date, FORMAT_BIN) != HAL_OK) { // init error @@ -270,60 +403,6 @@ STATIC void RTC_CalendarConfig(void) { } } -/* - Note: Care must be taken when HAL_RCCEx_PeriphCLKConfig() is used to select - the RTC clock source; in this case the Backup domain will be reset in - order to modify the RTC Clock source, as consequence RTC registers (including - the backup registers) and RCC_BDCR register are set to their reset values. -*/ -void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc) { - RCC_OscInitTypeDef RCC_OscInitStruct; - RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; - - /* To change the source clock of the RTC feature (LSE, LSI), You have to: - - Enable the power clock using __PWR_CLK_ENABLE() - - Enable write access using HAL_PWR_EnableBkUpAccess() function before to - configure the RTC clock source (to be done once after reset). - - Reset the Back up Domain using __HAL_RCC_BACKUPRESET_FORCE() and - __HAL_RCC_BACKUPRESET_RELEASE(). - - Configure the needed RTc clock source */ - - // RTC clock source uses LSE (external crystal) only if relevant - // configuration variable is set. Otherwise it uses LSI (internal osc). - - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; - if (rtc_use_lse) { - RCC_OscInitStruct.LSEState = RCC_LSE_ON; - RCC_OscInitStruct.LSIState = RCC_LSI_OFF; - } else { - RCC_OscInitStruct.LSEState = RCC_LSE_OFF; - RCC_OscInitStruct.LSIState = RCC_LSI_ON; - } - if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { - //Error_Handler(); - return; - } - - PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; - if (rtc_use_lse) { - PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; - } else { - PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; - } - if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { - //Error_Handler(); - return; - } - - // enable RTC peripheral clock - __HAL_RCC_RTC_ENABLE(); -} - -void HAL_RTC_MspDeInit(RTC_HandleTypeDef *hrtc) { - __HAL_RCC_RTC_DISABLE(); -} - /******************************************************************************/ // Micro Python bindings @@ -369,7 +448,25 @@ MP_DEFINE_CONST_FUN_OBJ_1(pyb_rtc_info_obj, pyb_rtc_info); /// `weekday` is 1-7 for Monday through Sunday. /// /// `subseconds` counts down from 255 to 0 + +#define MEG_DIV_64 (1000000 / 64) +#define MEG_DIV_SCALE ((RTC_SYNCH_PREDIV + 1) / 64) + +#if defined(MICROPY_HW_RTC_USE_US) && MICROPY_HW_RTC_USE_US +uint32_t rtc_subsec_to_us(uint32_t ss) { + return ((RTC_SYNCH_PREDIV - ss) * MEG_DIV_64) / MEG_DIV_SCALE; +} + +uint32_t rtc_us_to_subsec(uint32_t us) { + return RTC_SYNCH_PREDIV - (us * MEG_DIV_SCALE / MEG_DIV_64); +} +#else +#define rtc_us_to_subsec +#define rtc_subsec_to_us +#endif + mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { + rtc_init_finalise(); if (n_args == 1) { // get date and time // note: need to call get time then get date to correctly access the registers @@ -385,7 +482,7 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { mp_obj_new_int(time.Hours), mp_obj_new_int(time.Minutes), mp_obj_new_int(time.Seconds), - mp_obj_new_int(time.SubSeconds), + mp_obj_new_int(rtc_subsec_to_us(time.SubSeconds)), }; return mp_obj_new_tuple(8, tuple); } else { @@ -404,7 +501,7 @@ mp_obj_t pyb_rtc_datetime(mp_uint_t n_args, const mp_obj_t *args) { time.Hours = mp_obj_get_int(items[4]); time.Minutes = mp_obj_get_int(items[5]); time.Seconds = mp_obj_get_int(items[6]); - time.SubSeconds = mp_obj_get_int(items[7]); + time.SubSeconds = rtc_us_to_subsec(mp_obj_get_int(items[7])); time.TimeFormat = RTC_HOURFORMAT12_AM; time.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; time.StoreOperation = RTC_STOREOPERATION_SET; @@ -429,6 +526,8 @@ mp_obj_t pyb_rtc_wakeup(mp_uint_t n_args, const mp_obj_t *args) { // wucksel=0b110 is 1Hz clock with 0x10000 added to wut // so a 1 second wakeup could be wut=2047, wucksel=0b000, or wut=4095, wucksel=0b001, etc + rtc_init_finalise(); + // disable wakeup IRQ while we configure it HAL_NVIC_DisableIRQ(RTC_WKUP_IRQn); @@ -539,13 +638,31 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_wakeup_obj, 2, 4, pyb_rtc_wakeup); // When an integer argument is provided, check that it falls in the range [-511 to 512] // and set the calibration value; otherwise return calibration value mp_obj_t pyb_rtc_calibration(mp_uint_t n_args, const mp_obj_t *args) { + rtc_init_finalise(); mp_int_t cal; if (n_args == 2) { cal = mp_obj_get_int(args[1]); mp_uint_t cal_p, cal_m; if (cal < -511 || cal > 512) { +#if defined(MICROPY_HW_RTC_USE_CALOUT) && MICROPY_HW_RTC_USE_CALOUT + if ((cal & 0xfffe) == 0x0ffe) { + // turn on/off X18 (PC13) 512Hz output + // Note: + // Output will stay active even in VBAT mode (and inrease current) + if (cal & 1) { + HAL_RTCEx_SetCalibrationOutPut(&RTCHandle, RTC_CALIBOUTPUT_512HZ); + } else { + HAL_RTCEx_DeactivateCalibrationOutPut(&RTCHandle); + } + return mp_obj_new_int(cal & 1); + } else { + nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, + "calibration value out of range")); + } +#else nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "calibration value out of range")); +#endif } if (cal > 0) { cal_p = RTC_SMOOTHCALIB_PLUSPULSES_SET; diff --git a/stmhal/rtc.h b/stmhal/rtc.h index 6aacd653c6..c8f215c053 100644 --- a/stmhal/rtc.h +++ b/stmhal/rtc.h @@ -27,4 +27,5 @@ extern RTC_HandleTypeDef RTCHandle; extern const mp_obj_type_t pyb_rtc_type; -void rtc_init(void); +void rtc_init_start(void); +void rtc_init_finalise(void); diff --git a/stmhal/system_stm32.c b/stmhal/system_stm32.c index 22c917adcb..e286a15725 100644 --- a/stmhal/system_stm32.c +++ b/stmhal/system_stm32.c @@ -269,15 +269,66 @@ void SystemClock_Config(void) regarding system frequency refer to product datasheet. */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); - /* Enable HSE Oscillator and activate PLL with HSE as source */ - RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; - RCC_OscInitStruct.HSEState = RCC_HSE_ON; - RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; - RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; - RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; - RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; - RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; + /* Enable HSE Oscillator and activate PLL with HSE as source */ + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; + RCC_OscInitStruct.HSEState = RCC_HSE_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; + RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; + /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 + clocks dividers */ + RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); + RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; + +#if defined(MICROPY_HW_CLK_LAST_FREQ) && MICROPY_HW_CLK_LAST_FREQ + #if defined(MCU_SERIES_F7) + #define FREQ_BKP BKP31R + #else + #define FREQ_BKP BKP19R + #endif + uint32_t m = RTC->FREQ_BKP; + uint32_t n; + uint32_t p; + uint32_t q; + + // 222111HH HHQQQQPP nNNNNNNN NNMMMMMM + uint32_t h = (m >> 22) & 0xf; + uint32_t b1 = (m >> 26) & 0x7; + uint32_t b2 = (m >> 29) & 0x7; + q = (m >> 18) & 0xf; + p = (((m >> 16) & 0x03)+1)*2; + n = (m >> 6) & 0x3ff; + m &= 0x3f; + if ((q < 2) || (q > 15) || (p > 8) || (p < 2) || (n < 192) || (n >= 433) || (m < 2)) { + m = MICROPY_HW_CLK_PLLM; + n = MICROPY_HW_CLK_PLLN; + p = MICROPY_HW_CLK_PLLP; + q = MICROPY_HW_CLK_PLLQ; + h = RCC_SYSCLK_DIV1; + b1 = RCC_HCLK_DIV4; + b2 = RCC_HCLK_DIV2; + } else { + h <<= 4; + b1 <<= 10; + b2 <<= 10; + } + RCC_OscInitStruct.PLL.PLLM = m; //MICROPY_HW_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = n; //MICROPY_HW_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = p; //MICROPY_HW_CLK_PLLP; + RCC_OscInitStruct.PLL.PLLQ = q; //MICROPY_HW_CLK_PLLQ; + + RCC_ClkInitStruct.AHBCLKDivider = h; //RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = b1; //RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = b2; //RCC_HCLK_DIV2; +#else + RCC_OscInitStruct.PLL.PLLM = MICROPY_HW_CLK_PLLM; + RCC_OscInitStruct.PLL.PLLN = MICROPY_HW_CLK_PLLN; + RCC_OscInitStruct.PLL.PLLP = MICROPY_HW_CLK_PLLP; + RCC_OscInitStruct.PLL.PLLQ = MICROPY_HW_CLK_PLLQ; + + RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; + RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; + RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; +#endif if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { __fatal_error("HAL_RCC_OscConfig"); @@ -291,14 +342,6 @@ void SystemClock_Config(void) } #endif - /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 - clocks dividers */ - RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); - RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; - RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; - RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; - RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; - #if !defined(MICROPY_HW_FLASH_LATENCY) #define MICROPY_HW_FLASH_LATENCY FLASH_LATENCY_5 #endif