gd32的rtc用起来真是不好用,对晶振要求太高,不容易起振。本**旨在解决外部LSE不起振时,使用LSI并保证精度的解决方案。 struct RTC_MONITOR
{
uint8_t monitor_on;//0:on,1:off
uint8_t rtcclk_source;//0:lse,1:lsi
uint8_t rtc_backsecond;
uint8_t rtc_second;
uint32_t timer_period;
uint32_t sysrun_bytimer;
uint32_t sysrun_bytimers;
uint32_t sysrun_byrtc;
uint8_t get_second;
uint8_t get_minute;
uint8_t get_hour;
uint8_t get_day;
uint8_t get_month;
uint32_t get_year;
uint32_t get_counter;
};
struct RTC_MONITOR rtc_monitor;
int main(void) { //init hardware RTC_Configuration(); init_rtc_monitor();
while(1) { rtc_monitor_on(); } } uint32_t lwoff_timeout,rsf_timeout,lsifrequency;
void RTC_Configuration(void)
{
uint32_t WaitForOscSource;
/*Enables the clock to Backup and power interface peripherals */
RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_BKP | RCC_APB1PERIPH_PWR,ENABLE);
/* RTC clock source configuration ------------------------------------------*/
/* Allow access to BKP Domain */
PWR_BackupAccess_Enable(ENABLE);
/*Enable 40 kHz internal oscillator */
RCC_LSI_Enable(ENABLE);//´ò¿ªLSI
while(RCC_GetBitState(RCC_FLAG_LSISTB)==RESET);//µÈ´ýÖ±µ½LSIÎȶ¨
//read back
rtc_monitor.get_day = BKP_ReadBackupRegister(BKP_DR3);
rtc_monitor.get_month = BKP_ReadBackupRegister(BKP_DR2);
rtc_monitor.get_year = BKP_ReadBackupRegister(BKP_DR4);
rtc_monitor.get_second = BKP_ReadBackupRegister(BKP_DR5);
rtc_monitor.get_minute = BKP_ReadBackupRegister(BKP_DR6);
rtc_monitor.get_hour = BKP_ReadBackupRegister(BKP_DR7);
rtc_monitor.get_counter = RTC_GetCounter();
if(BKP_ReadBackupRegister(BKP_DR1)==CONFIGURATION_RESET)
{
/* Backup Domain Reset */
//rtc clk init
BKP_DeInit();
PWR_BackupAccess_Enable(ENABLE);
while((PWR->CTLR & PWR_CTLR_BKPWE) == RESET);
/*Enable 32.768 kHz external oscillator */
RCC_LSEConfig(RCC_LSE_EN);
for(WaitForOscSource=0;WaitForOscSource<5000;WaitForOscSource++)
{
}
RCC_RTCCLKConfig(RCC_RTCCLKSOURCE_LSE);
/* RTC Enabled */
RCC_RTCCLK_Enable(ENABLE);
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
/*Wait for RTC registers synchronisation */
//RTC_WaitRSF();
/* Clear RSF flag */
RTC->CTLR2 &= ~((uint16_t)RTC_FLAG_RSF);
/* Loop until RSF flag is set */
rsf_timeout = LSE_STARTUP_TIMEOUT;
while (((RTC->CTLR2 & RTC_FLAG_RSF) == (uint16_t)RESET)&&(rsf_timeout))
{
rsf_timeout--;
}
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
/* Setting RTC Interrupts-Seconds interrupt enabled */
/* Enable the RTC Second */
RTC_INT_Enable(RTC_INT_SF , ENABLE);
/* Wait until last write operation on RTC registers has finished */
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
/* Set RTC prescaler: set RTC period to 1 sec */
RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
/* Prescaler is set to 32766 instead of 32768 to compensate for
lower as well as higher frequencies*/
/* Wait until last write operation on RTC registers has finished */
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
Day = (rtc_monitor.get_day == 0)?(DEFAULT_DAY):(rtc_monitor.get_day);
Month = (rtc_monitor.get_month == 0)?(DEFAULT_MONTH):(rtc_monitor.get_month);
Year = rtc_monitor.get_year;
Hour = rtc_monitor.get_hour;
Minute = rtc_monitor.get_minute;
Second = rtc_monitor.get_second;
BKP_WriteBackupRegister(BKP_DR2,Month);
BKP_WriteBackupRegister(BKP_DR3,Day);
BKP_WriteBackupRegister(BKP_DR4,Year);
BKP_WriteBackupRegister(BKP_DR5,Second);
BKP_WriteBackupRegister(BKP_DR6,Minute);
BKP_WriteBackupRegister(BKP_DR7,Hour);
BKP_WriteBackupRegister(BKP_DR1, CONFIGURATION_DONE);
}
else
{
/* Allow access to BKP Domain */
PWR_BackupAccess_Enable(ENABLE);
while((PWR->CTLR & PWR_CTLR_BKPWE) == RESET);
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
/* Enable the RTC Second */
RTC_INT_Enable(RTC_INT_SF , ENABLE);
/* Wait until last write operation on RTC registers has finished */
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
}
/* Check if how many days are elapsed in power down/Low Power Mode-
Updates Date that many Times*/
CheckForDaysElapsed();
BKP_RTCOutputConfig(BKP_RTCOUTPUT_NULL);
}
void RTC_LSI_Configuration(void)
{
uint32_t WaitForOscSource;
//lse can not work use lsi
RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_BKP | RCC_APB1PERIPH_PWR,ENABLE);
BKP_DeInit();
for(WaitForOscSource=0;WaitForOscSource<50000;WaitForOscSource++)
{
}
PWR_BackupAccess_Enable(ENABLE);
while((PWR->CTLR & PWR_CTLR_BKPWE) == RESET);
/*Enable 40 kHz internal oscillator */
RCC_LSI_Enable(ENABLE);//´ò¿ªLSI
while(RCC_GetBitState(RCC_FLAG_LSISTB)==RESET);//µÈ´ýÖ±µ½LSIÎȶ¨
RCC_RTCCLKConfig(RCC_RTCCLKSOURCE_LSI);
/* RTC Enabled */
RCC_RTCCLK_Enable(ENABLE);
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
/*Wait for RTC registers synchronisation */
//RTC_WaitRSF();
/* Clear RSF flag */
RTC->CTLR2 &= ~((uint16_t)RTC_FLAG_RSF);
/* Loop until RSF flag is set */
rsf_timeout = LSE_STARTUP_TIMEOUT;
while (((RTC->CTLR2 & RTC_FLAG_RSF) == (uint16_t)RESET)&&(rsf_timeout))
{
rsf_timeout--;
}
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
/* Setting RTC Interrupts-Seconds interrupt enabled */
/* Enable the RTC Second */
RTC_INT_Enable(RTC_INT_SF , ENABLE);
/* Wait until last write operation on RTC registers has finished */
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
lsifrequency = GetLSIFrequency();
/* Set RTC prescaler: set RTC period to 1 sec */
RTC_SetPrescaler(lsifrequency); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
/* Prescaler is set to 32766 instead of 32768 to compensate for
lower as well as higher frequencies*/
/* Wait until last write operation on RTC registers has finished */
//RTC_WaitLWOFF();
lwoff_timeout = LSE_STARTUP_TIMEOUT;
/* Loop until RTOFF flag is set */
while (((RTC->CTLR2 & RTC_FLAG_LWOFF) == (uint16_t)RESET)&&(lwoff_timeout))
{
lwoff_timeout--;
}
Day = (rtc_monitor.get_day == 0)?(DEFAULT_DAY):(rtc_monitor.get_day);
Month = (rtc_monitor.get_month == 0)?(DEFAULT_MONTH):(rtc_monitor.get_month);
Year = rtc_monitor.get_year;
Hour = rtc_monitor.get_hour;
Minute = rtc_monitor.get_minute;
Second = rtc_monitor.get_second;
Set_RTCTime();//set counter
}
uint32_t GetLSIFrequency(void)
{
TIMER_BaseInitPara TimerBaseStructure;
TIMER_ICInitPara TIMInput_Config;
NVIC_InitPara NVIC_InitStructure;
extern __IO uint32_t uwLsiFreq;
extern __IO uint32_t uwCaptureNumber;
RCC_APB1PeriphClock_Enable(RCC_APB1PERIPH_TIMER5, ENABLE);
RCC_LSI_Enable(ENABLE);//´ò¿ªLSI
while(RCC_GetBitState(RCC_FLAG_LSISTB)==RESET);//µÈ´ýÖ±µ½LSIÎȶ¨
TIMER_Enable(TIMER5, DISABLE);
RCC_GetClocksFreq(&RCC_Clocks);
/* Configure the Priority Group to 2 bits */
NVIC_PRIGroup_Enable(NVIC_PRIGROUP_4);
/* Enable the TIMER5 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQ = TIMER5_IRQn;
NVIC_InitStructure.NVIC_IRQPreemptPriority = 0;
NVIC_InitStructure.NVIC_IRQSubPriority = 0;
NVIC_InitStructure.NVIC_IRQEnable = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TimerBaseStructure.TIMER_Prescaler = 0;
TimerBaseStructure.TIMER_Period = 0xffff;
TimerBaseStructure.TIMER_ClockDivision = TIMER_CDIV_DIV1;
TimerBaseStructure.TIMER_CounterMode = TIMER_COUNTER_UP;
TIMER_BaseInit(TIMER5, &TimerBaseStructure);
RCC_APB2PeriphClock_Enable(RCC_APB2PERIPH_AF, ENABLE);
GPIO_PinRemapConfig(GPIO_REMAP_TIMER5CH4_LSI,ENABLE);
/* Configure the Input Capture of TIM_CHANNEL_4 */
TIMInput_Config.TIMER_CH = TIMER_CH_4;
TIMInput_Config.TIMER_ICPolarity = TIMER_IC_POLARITY_RISING;
TIMInput_Config.TIMER_ICSelection = TIMER_IC_SELECTION_DIRECTTI;
TIMInput_Config.TIMER_ICPrescaler = TIMER_IC_PSC_DIV8;
TIMInput_Config.TIMER_ICFilter = 0;
TIMER_ICInit(TIMER5,&TIMInput_Config);
uwCaptureNumber = 0;
TIMER_INTConfig(TIMER5,TIMER_INT_CH4,ENABLE);
TIMER_Enable(TIMER5, ENABLE);
/* Wait until the TIM5 get 2 LSI edges */
while(uwCaptureNumber != 2)
{
}
TIMER_INTConfig(TIMER5,TIMER_INT_CH4,DISABLE);
/* Disable the TIMER5 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQ = TIMER5_IRQn;
NVIC_InitStructure.NVIC_IRQPreemptPriority = 0;
NVIC_InitStructure.NVIC_IRQSubPriority = 0;
NVIC_InitStructure.NVIC_IRQEnable = DISABLE;
NVIC_Init(&NVIC_InitStructure);
return uwLsiFreq;
}
void init_rtc_monitor(void)
{
rtc_monitor.monitor_on = 1;
rtc_monitor.rtcclk_source = 0;
rtc_monitor.rtc_backsecond = Second;
rtc_monitor.rtc_second = Second;
rtc_monitor.timer_period = 50;//50ms
rtc_monitor.sysrun_bytimer = 0;
rtc_monitor.sysrun_byrtc = 0;
}
void rtc_monitor_on(void)
{
if(rtc_monitor.rtc_backsecond != Second)
{
rtc_monitor.rtc_backsecond = Second;
rtc_monitor.sysrun_byrtc++;
}
rtc_monitor.sysrun_bytimers = (rtc_monitor.sysrun_bytimer*rtc_monitor.timer_period)/1000;
//compare system runtime by timer and rtc only in lse condition
if(rtc_monitor.rtcclk_source == 0)
{
//only if sysrun_byrtc == 0 and bytimer >= 3,indicate that lse donot work, turn into lsi mode
if((rtc_monitor.sysrun_byrtc == 0)&&(rtc_monitor.sysrun_bytimers >= 3))
{
rtc_monitor.rtcclk_source = 1;
RTC_LSI_Configuration();
rtc_monitor.sysrun_byrtc = (rtc_monitor.sysrun_bytimer*rtc_monitor.timer_period)/1000;
}
}
}
需要配合2个TIMER实时监控RTC的运行情况
void TIMER3_IRQHandler(void)
{
if(TIMER_GetIntBitState(TIMER3, TIMER_INT_UPDATE) == SET)
{
TIMER_ClearIntBitState(TIMER3, TIMER_INT_UPDATE); rtc_monitor.sysrun_bytimer++; } } uint16_t tmpCCTIM_CHANNEL_4[2] = {0, 0};
__IO uint32_t uwLsiFreq = 0;
__IO uint32_t uwCaptureNumber = 0;
__IO uint32_t uwPeriodValue = 0;
void TIMER5_IRQHandler(void)
{
if(TIMER_GetIntBitState(TIMER5, TIMER_INT_CH4) == SET)
{
TIMER_ClearIntBitState(TIMER5, TIMER_INT_CH4);
/* Get the Input Capture value */
tmpCCTIM_CHANNEL_4[uwCaptureNumber++] = TIMER_GetCapture4(TIMER5);//HAL_TIM_ReadCapturedValue(&Input_Handle, TIM_CHANNEL_4);
if (uwCaptureNumber >= 2)
{
if ( tmpCCTIM_CHANNEL_4[0] > tmpCCTIM_CHANNEL_4[1] )
{
/* Compute the period length */
uwPeriodValue = (uint16_t)(0xFFFF - tmpCCTIM_CHANNEL_4[0] + tmpCCTIM_CHANNEL_4[1] + 1);
}
else
{
/* Compute the period length */
uwPeriodValue = (uint16_t)(tmpCCTIM_CHANNEL_4[1] - tmpCCTIM_CHANNEL_4[0] + 1);
}
/* Frequency computation */
uwLsiFreq = (uint32_t) SystemCoreClock / uwPeriodValue;
uwLsiFreq *= 8;
}
}
}
|