You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tinySA/rtc.c

177 lines
5.6 KiB

/*
* 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__

Powered by TurnKey Linux.