/* * Copyright (c) 2019-2020, Dmitry (DiSlord) dislordlive@gmail.com * All rights reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * The software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #include "ch.h" #include "hal.h" #include "nanovna.h" #ifdef __USE_RTC__ // Compact STM32 RTC time library #if HAL_USE_RTC == TRUE #error "Error VNA use self RTC lib, define HAL_USE_RTC = FALSE in halconf.h" #endif // Get RTC time as binary structure in 0x00HHMMSS uint32_t rtc_get_tr_bin(void){ uint32_t tr = RTC->TR; uint32_t v = (tr&0x0F0F0F) + ((tr&0x707070)>>1) + ((tr&0x707070)>>3); return v; } // Get RTC time as binary structure in 0x00YYMMDD uint32_t rtc_get_dr_bin(void){ uint32_t dr = RTC->DR; uint32_t v = (dr&0x000F0F0F) + ((dr&0x00F01030)>>1) + ((dr&0x00F01030)>>3); return v;// | ((dr&0xE000)<<15); // day of week at end } uint32_t rtc_get_FAT(void) { uint32_t fattime; uint32_t tr = rtc_get_tr_bin(); uint32_t dr = rtc_get_dr_bin(); fattime = ((tr>> 0)&0xFF) >> 1U; // Seconds / 2 fattime |= ((tr>> 8)&0xFF) << 5U; // Minutes fattime |= ((tr>>16)&0xFF) << 11U; // Hour fattime |= ((dr>> 0)&0xFF) << 16U; // Day fattime |= ((dr>> 8)&0xFF) << 21U; // Month fattime |= (((dr>>16)&0xFF) + RTC_START_YEAR - 1980) << 25U; // Local year begin from 2000, fat from 1980 return fattime; } // Finish of configuration procedure. static void rtc_exit_init(void) { RTC->ISR &= ~RTC_ISR_INIT; } // Beginning of configuration procedure. static bool rtc_enter_init(void){ RTC->ISR |= RTC_ISR_INIT; uint32_t count = 4*65536; while (--count) if (RTC->ISR & RTC_ISR_INITF) return true; return false; } void rtc_set_time(uint32_t dr, uint32_t tr) { if (rtc_enter_init()){ RTC->TR = tr; // Write TR register RTC->DR = dr; // Write TD register } rtc_exit_init(); } #ifdef VNA_AUTO_SELECT_RTC_SOURCE // Enable LSE bypass if need #if defined(STM32_LSE_BYPASS) #define STM32_LSE_BYPASS RCC_BDCR_LSEBYP #else #define STM32_LSE_BYPASS 0 #endif // Startup LSE or if not work, LSI generator static void rtc_start_source(void){ // LSE already work (enabled and ready) if ((RCC->BDCR & (RCC_BDCR_LSEON|RCC_BDCR_LSERDY|STM32_LSE_BYPASS)) == (RCC_BDCR_LSEON|RCC_BDCR_LSERDY|STM32_LSE_BYPASS)) return; // If LSE not enabled, try startup RCC->BDCR |= STM32_LSEDRV | STM32_LSE_BYPASS | RCC_BDCR_LSEON; // Waits until LSE is stable (need ~150ms for startup). chThdSleepMilliseconds(200); if (RCC->BDCR & RCC_BDCR_LSERDY) return; // Startup LSI if not allow start LSE RCC->CSR |= RCC_CSR_LSION; while ((RCC->CSR & RCC_CSR_LSIRDY) == 0); } static void resetBCDR(uint32_t rtc_drv){ // Backup domain reset, for change source. RCC->BDCR = RCC_BDCR_BDRST; RCC->BDCR = 0; // Startup again source generator rtc_start_source(); // Select new clock source. And enable RCC->BDCR|= rtc_drv; } void auto_backup_domain_init(void){ // Init Backup domain, RTC clock source uint32_t rtc_drv; // Backup domain access enabled and left open. PWR->CR |= PWR_CR_DBP; // Start/check source rtc_start_source(); // Check LSE ready, if ok, select as source rtc_drv = RCC->BDCR & RCC_BDCR_LSERDY ? STM32_RTCSEL_LSE|RCC_BDCR_RTCEN : // Select LSE as source STM32_RTCSEL_LSI|RCC_BDCR_RTCEN; // Select LSI as source // If the backup domain hasn't been initialized yet or work on different source, then proceed with initialization if ((RCC->BDCR & (STM32_RTCSEL_MASK|RCC_BDCR_RTCEN)) != rtc_drv) resetBCDR(rtc_drv); /* // Check RTC clock, and reset backup domain to LSI if clock not start if (rtc_enter_init()) rtc_exit_init(); else resetBCDR(STM32_RTCSEL_LSI|RCC_BDCR_RTCEN); */ } #endif // Initiate RTC clock void rtc_init(void){ #ifdef VNA_AUTO_SELECT_RTC_SOURCE // Auto start LSE or LSI source for RTC auto_backup_domain_init(); #else // ChibiOS init BDCR LSE or LSI source by self from user defined in mcuconf.h source // For add auto select RTC source need rewrite it // see hal_lld_backup_domain_init() in hal_lld.c for every CPU // Default RTC clock is LSE, but it possible not launch if no quartz installed #endif #if HAL_USE_RTC == FALSE uint32_t src = RCC->BDCR & STM32_RTCSEL_MASK; if (src == STM32_RTCSEL_NOCLOCK) return; // If calendar has not been initialized yet or different PRER settings then proceed with the initial setup. // Disable write protection. RTC->WPR = 0xCA; RTC->WPR = 0x53; uint32_t rtc_prer = (src == STM32_RTCSEL_LSE) ? STM32_RTC_LSE_PRER : STM32_RTC_LSI_PRER; // If calendar has not been initialized yet then proceed with the initial setup. if ((RTC->ISR & RTC_ISR_INITS) == 0 || RTC->PRER != rtc_prer) { if (rtc_enter_init()){ RTC->CR = 0; RTC->ISR = RTC_ISR_INIT; // Clearing all but RTC_ISR_INIT. RTC->PRER = rtc_prer; // Prescaler value loaded in registers 2 times RTC->PRER = rtc_prer; } // Finalizing of configuration procedure. rtc_exit_init(); } else RTC->ISR &= ~RTC_ISR_RSF; #endif } #endif // __USE_RTC__