打印

(转)gd32的rtc使用心得

[复制链接]
1852|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wakayi|  楼主 | 2018-7-27 10:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
RTC, TI, se, ni, TE

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;
}
}
}


沙发
木木guainv| | 2018-7-27 10:42 | 只看该作者
以前是这样 现在是不是已经改善了啊

使用特权

评论回复
板凳
jerow| | 2018-7-27 11:00 | 只看该作者
对晶振要求太高,不容易起振。不应该吧,RTC应该是很容易起振的。

使用特权

评论回复
地板
磨砂| | 2018-7-28 09:45 | 只看该作者
楼主辛苦了  感谢分享

使用特权

评论回复
5
观海| | 2018-7-28 09:55 | 只看该作者
好全 楼主辛苦了

使用特权

评论回复
6
heimaojingzhang| | 2018-8-7 12:47 | 只看该作者
rtc怎么会这么麻烦呢

使用特权

评论回复
7
wakayi|  楼主 | 2018-8-7 13:04 | 只看该作者
heimaojingzhang 发表于 2018-8-7 12:47
rtc怎么会这么麻烦呢

我是说在这种情况下的rtc这样用

使用特权

评论回复
8
heimaojingzhang| | 2018-8-8 10:57 | 只看该作者
wakayi 发表于 2018-8-7 13:04
我是说在这种情况下的rtc这样用

哦哦 我没看仔细

使用特权

评论回复
9
wakayi|  楼主 | 2018-8-8 12:59 | 只看该作者

没关系的 呵呵呵

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

78

主题

3853

帖子

1

粉丝