bs_bcu_app/drv/drv_stm32f4xx/drv_rtc.c

286 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "drv_rtc.h"
#include "drv_clk.h"
#include "bsp_task.h"
#include "kit_time.h"
#include "kit_data.h"
#include "kit_debug.h"
#define LSE_NOT_READY 0
#define RCC_BDCR_RTCEN_POS KIT_CREAT_BIT(15)
#define RCC_BDCR_LSEDY_POS ((uint32_t)0x00000002)
#define RCC_BDCR_LSEON_POS KIT_CREAT_BIT(0)
#define RCC_RTCCLKSource_LSE KIT_CREAT_BIT(8)
#define RTC_FLAG_RTOFF ((uint16_t)0x0020) /*!< RTC Operation OFF flag */
/******************************************************************************************
1.写RTC寄存器前必须使能PWR_CR中的DBP,且必须等待操作完成才能清0 DBP
2.stm32f10x RTC 进行写操作前必须判断上一次操作是否完成(RTOFF)
3.写RTC_CNT、RTC_ALR或RTC_PRL寄存器时必须先置位CNF写完后必须清0才会执行写操作
4.读RTC_CNT、RTC_ALR或RTC_PRL寄存器时前必须清0RSF等其被硬件置位时表示同步完成可以读取
5.低速时钟起振时间1-5s
******************************************************************************************/
#define RTC_INIT_MASK ((uint32_t)0xFFFFFFFF)
bool drv_rtc_enable_init_mode(void)
{
uint32_t dly = 0;
// //对RTC寄存器操作前先要使能备份区
// PWR->CR |= PWR_CR_DBP;
//关闭RTC寄存器写保护
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
//进入RTC初始化模式
if((RTC->ISR &= RTC_ISR_INITF) == 0)
{
RTC->ISR = RTC_INIT_MASK;
//等待进入RTC初始化模式成功
while(((RTC->ISR & RTC_ISR_INITF) == 0x00) && (dly++ < 100))
{
bsp_task_delay_ms(1);
}
}
return (dly < 100);
}
void drv_rtc_disable_init_mode(void)
{
RTC->ISR &= ~RTC_ISR_INIT; //退出RTC初始化模式
RTC->WPR = 0xFF; //使能RTC寄存器写保护
}
//由于低速时钟起振较慢其他任务初始化后再初始化RTC
bool drv_rtc_init(void)
{
bool res = false;
uint32_t dly = 0;
//if((RCC->BDCR & RCC_BDCR_RTCEN_POS) != RCC_BDCR_RTCEN_POS)
{
KIT_DEBUG_PRINTF("rtc init\r\n");
RCC->APB1ENR |= RCC_APB1Periph_PWR;
//使能允许写入RTC和后备寄存器
PWR->CR |= PWR_CR_DBP;
//开启LSE
RCC->BDCR |= RCC_BDCR_LSEON_POS;
while((RCC->BDCR & RCC_BDCR_LSEDY_POS) == LSE_NOT_READY)
{
bsp_task_delay_ms(10);
if(dly++ > 500)
{
KIT_DEBUG_PRINTF("rtc fail \r\n");
return res;
}
}
KIT_DEBUG_PRINTF("rtc dly %d\r\n", dly);
RCC->BDCR |= (RCC_RTCCLKSource_LSE | RCC_BDCR_RTCEN_POS);
//RTC配置使用默认配置
//设置同步分频系数和异步分频系数默认为1Hz = 32768/(同步分频 + 1)/(异步分频 + 1)
res = drv_rtc_enable_init_mode();
if(res == true)
{
RTC->PRER = 0x001F03FF;
}
drv_rtc_disable_init_mode();
//PWR->CR &= ~PWR_CR_DBP_POS;
}
return res;
}
//ampm:AM/PM,0=AM/24H,1=PM.
bool drv_rtc_set_time(uint8_t hour, uint8_t min, uint8_t sec)
{
bool res;
//关闭RTC寄存器写保护
res = drv_rtc_enable_init_mode();
if(res == true)
{
RTC->TR = ((uint32_t)kit_dec_to_bcd(hour) << 16) | ((uint32_t)kit_dec_to_bcd(min) << 8) | (kit_dec_to_bcd(sec));
}
drv_rtc_disable_init_mode();
return res;
}
//year 20xx, month 1-12, day 1-31
bool drv_rtc_set_date(uint16_t year, uint8_t month, uint8_t day)
{
bool res;
//关闭RTC寄存器写保护
res = drv_rtc_enable_init_mode();
if((res == true) && (year >= 2000))
{
RTC->DR = ((uint32_t)kit_dec_to_bcd(year - 2000) << 16) | ((uint32_t)kit_dec_to_bcd(month) << 8) | (kit_dec_to_bcd(day));
}
drv_rtc_disable_init_mode();
return res;
}
bool drv_rtc_wait_sync(void)
{
bool res = true;
int32_t retry = 0;
//关闭RTC寄存器写保护
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
RTC->ISR &= ~(1 << 5); //清除RSF位
while((retry++ < 0XFFFFF) && ((RTC->ISR & (1 << 5)) == 0x00)) //等待影子寄存器同步
{}
if(retry >= 0XFFFFF)
{
res = false;
}
RTC->WPR = 0xFF; //使能RTC寄存器写保护
return res;
}
bool drv_rtc_get_time(int32_t *hour, int32_t *min, int32_t *sec)
{
uint32_t temp = 0;
if(drv_rtc_wait_sync() == true)
{
temp = RTC->TR;
*hour = kit_dcb_to_dec((temp >> 16) & 0x3F);
*min = kit_dcb_to_dec((temp >> 8) & 0x7F);
*sec = kit_dcb_to_dec(temp & 0x7F);
return true;
}
else
{
*hour = *min = *sec = 0;
return false;
}
}
//year 20xx, month 1-12, day 1-31
bool drv_rtc_get_date(int32_t *year, int32_t *month, int32_t *day)
{
uint32_t temp = 0;
if(drv_rtc_wait_sync() == true)
{
temp = RTC->DR;
*year = kit_dcb_to_dec((temp >> 16) & 0xFF) + 2000;
*month = kit_dcb_to_dec((temp >> 8) & 0x1F);
*day = kit_dcb_to_dec(temp & 0x3F);
return true;
}
else
{
*year = 2000;
*month = *day = 1;
return false;
}
}
uint32_t drv_rtc_get_tick(void)
{
struct tm tmp;
uint32_t res = 0;
tmp.tm_year = 0;
if((drv_rtc_get_time(&tmp.tm_hour, &tmp.tm_min, &tmp.tm_sec) == true)
&& (drv_rtc_get_date(&tmp.tm_year, &tmp.tm_mon, &tmp.tm_mday) == true))
{
tmp.tm_mon--;
tmp.tm_year = (tmp.tm_year > 2018) ? (tmp.tm_year - 1900) : 119;
res = kit_time_get_stamp(2019, &tmp);
}
return res;
}
bool drv_rtc_set_tick(uint32_t tick)
{
struct tm *tmp;
bool res = false;
if(drv_rtc_get_tick() != tick)
{
tmp = kit_time_get_date(2019, tick);
//标准库月0-11 ST月为1-12ST年从2000开始只保留十位和各位
if((tmp->tm_year >= 119) && (drv_rtc_set_time(tmp->tm_hour, tmp->tm_min, tmp->tm_sec) == true)
&& (drv_rtc_set_date((tmp->tm_year + 1900), tmp->tm_mon + 1, tmp->tm_mday) == true))
{
res = true;
}
}
else
{
res = true;
}
return res;
}
uint16_t drv_rtc_get_ms(void)
{
uint32_t tmp = 0;
/* Get sub seconds values from the correspondent registers*/
tmp = (uint32_t)(RTC->SSR);
/* Read DR register to unfroze calendar registers */
(void)(RTC->DR);
tmp = (0x03FF - tmp) * 1000 / (0x03FF + 1);
return tmp;
}
bool drv_rtc_set_ms(uint16_t ms)
{
bool res = false;
uint32_t cur_ms, cnt = 0;
/* Disable the write protection for RTC registers */
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
cur_ms = drv_rtc_get_ms();
if(ms != cur_ms)
{
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
/* Check if a Shift is pending*/
while(((RTC->ISR & RTC_ISR_SHPF) != RESET) && (cnt++ < 1000));
/* Check if the Shift pending is completed or if there is no Shift operation at all*/
if((RTC->ISR & RTC_ISR_SHPF) == RESET)
{
/* check if the reference clock detection is disabled */
if((RTC->CR & RTC_CR_REFCKON) == RESET)
{
if(cur_ms > ms)
{
cur_ms = (cur_ms - ms) * (0x3FF + 1) / 1000;
}
else
{
cur_ms = (1000 - ms + cur_ms) * (0x3FF + 1) / 1000;
}
RTC->SHIFTR = cur_ms;
res = drv_rtc_wait_sync();
}
}
/* Enable the write protection for RTC registers */
RTC->WPR = 0xFF;
}
return res;
}
#include "stdio.h"
char rtc_time_str[20];
char *drv_rtc_get_time_string(void)
{
struct tm tmp;
drv_rtc_get_time(&tmp.tm_hour, &tmp.tm_min, &tmp.tm_sec);
sprintf(rtc_time_str, "%2d:%2d:%2d", tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
return rtc_time_str;
}