394 lines
10 KiB
C
394 lines
10 KiB
C
#include "bsp_rtc.h"
|
||
|
||
|
||
|
||
/* 时钟精度ppm值,根据实测RTC时钟精度填写 */
|
||
#define FRTC_PPM (-20L)
|
||
#define TIMES_TO_GET_TR (0x03) /* 两次读日历不一致后再次循环次数 */
|
||
|
||
/**
|
||
* @brief RTC中断服务函数
|
||
* @retval 无
|
||
*/
|
||
void RTC_TAMP_IRQHandler(void)
|
||
{
|
||
/* enter interrupt */
|
||
rt_interrupt_enter();
|
||
|
||
/* 校准周期中断处理流程 */
|
||
if (std_rtc_get_calib_interrupt_enable() && std_rtc_get_interrupt_flag(RTC_INTERRUPT_FLAG_CALIBRATION))
|
||
{
|
||
/* 清除校准周期标志 */
|
||
std_rtc_clear_flag(RTC_CLEAR_CALIBRATION);
|
||
}
|
||
/* TAMP IN中断处理流程 */
|
||
if (std_tamp_get_interrupt_enable(TAMP_INTERRUPT_TAMP_IN) && std_tamp_get_interrupt_flag(TAMP_INTERRUPT_FLAG_TAMP_IN))
|
||
{
|
||
/* 清除外部入侵检测(外部引脚)的标志 */
|
||
std_tamp_clear_flag(TAMP_CLEAR_FLAG_TAMP_IN);
|
||
}
|
||
/* 闹钟中断处理流程 */
|
||
if (std_rtc_get_alarm_interrupt_enable() && std_rtc_get_interrupt_flag(RTC_INTERRUPT_FLAG_ALARM))
|
||
{
|
||
/* 清除闹钟标志 */
|
||
std_rtc_clear_flag(RTC_CLEAR_ALARM);
|
||
}
|
||
/* 周期中断处理流程 */
|
||
if (std_rtc_get_wut_interrupt_enable(RTC_WUT_INTERRUPT_MIN) && std_rtc_get_interrupt_flag(RTC_INTERRUPT_FLAG_MIN))
|
||
{
|
||
/* 清除周期中断标志 */
|
||
std_rtc_clear_flag(RTC_INTERRUPT_FLAG_MIN);
|
||
}
|
||
/* leave interrupt */
|
||
rt_interrupt_leave();
|
||
}
|
||
|
||
/**
|
||
* @brief RTC日期时间配置
|
||
* @retval 无 BCD输入
|
||
*/
|
||
void BSP_Rtc_DateTime_Cfg(uint8_t years, uint8_t months, uint8_t days, uint8_t hour, uint8_t minute, uint8_t second, uint8_t week)
|
||
{
|
||
std_rtc_time_t rtc_time = {0};
|
||
std_rtc_date_t rtc_date = {0};
|
||
std_status_t status = STD_ERR;
|
||
|
||
/* RTC日期(BCD码)初始化 */
|
||
// rtc_date.weekday = RTC_WEEKDAY_FRIDAY;
|
||
// rtc_date.month = RTC_MONTH_AUGUST;
|
||
|
||
rtc_date.weekday = week;
|
||
rtc_date.month = months;
|
||
rtc_date.day = days;
|
||
rtc_date.year = years;
|
||
|
||
status = std_rtc_date_init(&rtc_date);
|
||
while (status != STD_OK)
|
||
{
|
||
/* RTC日期初始化失败处理代码 */
|
||
}
|
||
|
||
/* RTC时间(BCD码)初始化 */
|
||
rtc_time.hours = hour;
|
||
rtc_time.minutes = minute;
|
||
rtc_time.seconds = second;
|
||
|
||
status = std_rtc_time_init(&rtc_time);
|
||
while (status != STD_OK)
|
||
{
|
||
/* RTC时间初始化失败处理代码 */
|
||
}
|
||
}
|
||
MSH_CMD_EXPORT(BSP_Rtc_DateTime_Cfg, " BCD格式输入 RTC日期时间配置:y,m,d,h,m,s,w ");
|
||
|
||
/**
|
||
* @brief RTC_OUT输出信号配置
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_OutPut_Config(void)
|
||
{
|
||
/* 关闭RTC寄存器写保护 */
|
||
std_rtc_write_protection_disable();
|
||
|
||
/* 配置RTC_OUT输出1Hz */
|
||
std_rtc_out_config(RTC_OUTPUT_SPRE_1HZ);
|
||
|
||
/* 配置RTC_OUT输出使能 */
|
||
std_rtc_output_enable();
|
||
|
||
/* 使能RTC寄存器写保护 */
|
||
std_rtc_write_protection_enable();
|
||
}
|
||
|
||
/**
|
||
* @brief RTC_OUT输出信号配置
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_Output_Cfg(void)
|
||
{
|
||
/* 配置RTC_OUT输出1Hz */
|
||
std_rtc_out_config(RTC_OUTPUT_SPRE_1HZ);
|
||
/* 配置RTC_OUT输出使能 */
|
||
std_rtc_output_enable();
|
||
}
|
||
|
||
/**
|
||
* @brief 外部引脚入侵检测TAMP IN配置
|
||
* @retval 无
|
||
*/
|
||
void bsp_rtc_tamp_in_config(void)
|
||
{
|
||
/* 关闭RTC寄存器写保护 */
|
||
std_rtc_write_protection_disable();
|
||
|
||
/* 关闭RTC_OUT信号输出 */
|
||
std_rtc_output_disable();
|
||
|
||
/* RTC寄存器写保护使能 */
|
||
std_rtc_write_protection_enable();
|
||
|
||
/* 禁止外部入侵检测 */
|
||
std_tamp_disable(TAMP_SOURCE_TAMP_IN);
|
||
|
||
/* 设置入侵检测触发方式 */
|
||
std_tamp_set_trigger(TAMP_TRIGGER_FALLING_EDGE);
|
||
|
||
/* 设置入侵检测引脚数字滤波参数 */
|
||
std_tamp_set_filter(TAMP_FILTER_DISABLE);
|
||
|
||
/* 使能入侵检测引脚上拉电阻 */
|
||
std_tamp_pullup_enable();
|
||
|
||
/* 使能外部入侵检测中断 */
|
||
std_tamp_interrupt_enable(TAMP_INTERRUPT_TAMP_IN);
|
||
|
||
/* 使能外部入侵检测 */
|
||
std_tamp_enable(TAMP_SOURCE_TAMP_IN);
|
||
|
||
/* 配置中断优先级 */
|
||
NVIC_SetPriority(RTC_TAMP_IRQn, NVIC_PRIO_0);
|
||
/* 使能中断 */
|
||
NVIC_EnableIRQ(RTC_TAMP_IRQn);
|
||
}
|
||
|
||
/**
|
||
* @brief RTC闹钟配置
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_Alarm_Config(uint8_t hours, uint8_t minutes, uint8_t seconds)
|
||
{
|
||
std_rtc_alarm_t rtc_alarm = {0};
|
||
|
||
/* 禁止闹钟 */
|
||
std_rtc_write_protection_disable();
|
||
std_rtc_alarm_disable();
|
||
std_rtc_write_protection_enable();
|
||
|
||
/* 闹钟初始化 */
|
||
rtc_alarm.time.hours = std_rtc_convert_bin2bcd(hours);
|
||
rtc_alarm.time.minutes = std_rtc_convert_bin2bcd(minutes);
|
||
rtc_alarm.time.seconds = std_rtc_convert_bin2bcd(seconds);
|
||
rtc_alarm.time_mask = RTC_ALARM_MASK_NONE;
|
||
|
||
std_rtc_alarm_init(&rtc_alarm);
|
||
|
||
/* 使能闹钟,开启闹钟中断 */
|
||
std_rtc_write_protection_disable();
|
||
std_rtc_alarm_interrupt_enable();
|
||
std_rtc_alarm_enable();
|
||
std_rtc_write_protection_enable();
|
||
|
||
/* 配置中断优先级 */
|
||
NVIC_SetPriority(RTC_TAMP_IRQn, NVIC_PRIO_0);
|
||
/* 使能中断 */
|
||
NVIC_EnableIRQ(RTC_TAMP_IRQn);
|
||
}
|
||
|
||
/**
|
||
* @brief RTC唤醒定时器配置
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_Wakeup_Config(void)
|
||
{
|
||
/* 关闭RTC寄存器写保护 */
|
||
std_rtc_write_protection_disable();
|
||
|
||
/* 使能分钟周期定时中断 */
|
||
std_rtc_wut_interrupt_enable(RTC_WUT_INTERRUPT_MIN);
|
||
|
||
/* 使能RTC寄存器写保护 */
|
||
std_rtc_write_protection_enable();
|
||
|
||
/* 配置中断优先级 */
|
||
NVIC_SetPriority(RTC_TAMP_IRQn, NVIC_PRIO_0);
|
||
/* 使能中断 */
|
||
NVIC_EnableIRQ(RTC_TAMP_IRQn);
|
||
}
|
||
|
||
/**
|
||
* @brief 使能PMU低功耗配置
|
||
* @retval 无
|
||
*/
|
||
void BSP_Pmu_LowPower_Config(void)
|
||
{
|
||
std_rcc_apb1_clk_enable(RCC_PERIPH_CLK_PMU);
|
||
|
||
/* 使能超低功耗配置 */
|
||
std_pmu_ultra_lowpower_enable();
|
||
}
|
||
|
||
/**
|
||
* @brief 获取日历日期与时间
|
||
* @param rtcdate 输出日期信息
|
||
* @param rtctime 输出时间信息
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_Get_Calendar(uint8_t *rtcdate, uint8_t *rtctime)
|
||
{
|
||
uint32_t i, read_ok = 0;
|
||
uint32_t temp_time1 = 0, temp_time2 = 0;
|
||
uint32_t temp_date1 = 0, temp_date2 = 0;
|
||
|
||
/* 读取日历 */
|
||
for (i = 0; i < TIMES_TO_GET_TR; i++)
|
||
{
|
||
/* 读一次日历时间 */
|
||
temp_time1 = std_rtc_time_get_time();
|
||
temp_date1 = std_rtc_date_get_date();
|
||
|
||
/* 再读一次日历时间 */
|
||
temp_time2 = std_rtc_time_get_time();
|
||
temp_date2 = std_rtc_date_get_date();
|
||
|
||
/* 连续两次读取结果比对 */
|
||
if ((temp_time1 == temp_time2) && (temp_date1 == temp_date2))
|
||
{
|
||
/* 两者一致,表示读取成功 */
|
||
read_ok = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
/* 时间读取正确 */
|
||
if (read_ok)
|
||
{
|
||
/* 获取时间 */
|
||
rtctime[0] = (temp_time1 >> RTC_OFFSET_HOUR) & 0xFF;
|
||
rtctime[1] = (temp_time1 >> RTC_OFFSET_MINUTE) & 0xFF;
|
||
rtctime[2] = temp_time1 & 0xFF;
|
||
|
||
/* 获取日期 */
|
||
rtcdate[0] = (temp_date1 >> RTC_OFFSET_YEAR) & 0xFF;
|
||
rtcdate[1] = (temp_date1 >> RTC_OFFSET_MONTH) & 0xFF;
|
||
rtcdate[2] = temp_date1 & 0xFF;
|
||
}
|
||
|
||
/* 时间读取不正确 */
|
||
else
|
||
{
|
||
while (1)
|
||
{
|
||
/* 时间读取不正确处理代码 */
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 获取时间戳日期与时间
|
||
* @param timestamp_date 输出时间戳日期信息
|
||
* @param timestamp_time 输出时间戳时间信息
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_Get_Timestamp(uint8_t *timestamp_date, uint8_t *timestamp_time)
|
||
{
|
||
/* 等待时间戳标志TSF置1 */
|
||
while (!std_rtc_get_flag(RTC_FLAG_TIMESTAMP));
|
||
|
||
/* 读取时间戳时间 */
|
||
timestamp_time[0] = std_rtc_timestamp_get_hour();
|
||
timestamp_time[1] = std_rtc_timestamp_get_minute();
|
||
timestamp_time[2] = std_rtc_timestamp_get_second();
|
||
|
||
/* 读取时间戳日期 */
|
||
timestamp_date[0] = std_rtc_timestamp_get_day();
|
||
timestamp_date[1] = std_rtc_timestamp_get_month();
|
||
|
||
/* 清除时间戳标志 */
|
||
std_rtc_clear_flag(RTC_CLEAR_TIMESTAMP);
|
||
}
|
||
|
||
/**
|
||
* @brief 配置RTC时钟数字平滑校准参数
|
||
* @param calib_plus_pulses 插入时钟脉冲控制
|
||
* @arg RTC_SMOOTH_CALIB_PLUS_PULSES_RESET
|
||
* @arg RTC_SMOOTH_CALIB_PLUS_PULSES_SET
|
||
* @param calib_minus_pulses 屏蔽时钟脉冲个数
|
||
* @retval 无
|
||
*/
|
||
void BSP_Rtc_Calib_Cfg(uint32_t calib_plus_pulses, uint32_t calib_minus_pulses)
|
||
{
|
||
/* 开启校准周期中断 */
|
||
std_rtc_calib_interrupt_enable();
|
||
|
||
/* 配置数字平滑校准参数 */
|
||
while (std_rtc_cal_get_status());
|
||
std_rtc_cal_config(calib_plus_pulses, calib_minus_pulses);
|
||
|
||
/* 配置中断优先级 */
|
||
NVIC_SetPriority(RTC_TAMP_IRQn, NVIC_PRIO_0);
|
||
/* 使能中断 */
|
||
NVIC_EnableIRQ(RTC_TAMP_IRQn);
|
||
}
|
||
|
||
/**
|
||
* @brief RTC时钟设置 RTC在VCORE_AON域,可使用VCORE_AON复位清除所有寄存器状态
|
||
* @retval 无
|
||
*/
|
||
void rtc_clock_config(void)
|
||
{
|
||
/* RTC APB时钟使能 */
|
||
std_rcc_apb1_clk_enable(RCC_PERIPH_CLK_RTC);
|
||
|
||
/* 使能PMU时钟,开启VCORE_AON写使能 */
|
||
std_rcc_apb1_clk_enable(RCC_PERIPH_CLK_PMU);
|
||
std_pmu_vaon_write_enable();
|
||
|
||
/* 使能LXTAL时钟 */
|
||
std_rcc_lxtal_drive_mode_config(RCC_LXTAL_DRIVE_MODE_ENHANCE);
|
||
std_rcc_lxtal_drive_config(RCC_LXTAL_DRIVE_LEVEL2);
|
||
std_rcc_lxtal_enable(RCC_LXTAL_ON);
|
||
while (!std_rcc_get_lxtal_ready());
|
||
|
||
/* 选择LXTAL作为RTC时钟源
|
||
|
||
注意: 选择RTC时钟源后,以下情况可重新配置RTC时钟源:
|
||
- VCORE_AON域复位
|
||
*/
|
||
std_rcc_set_rtcclk_source(RCC_RTC_ASYNC_CLK_SRC_LXTAL);
|
||
|
||
/* RTC外设时钟使能 */
|
||
std_rcc_rtc_enable();
|
||
}
|
||
|
||
int BSP_RTC_Init(void)
|
||
{
|
||
float calp_val = 0, calm_val = 0;
|
||
|
||
/* RTC时钟源选择LXTAL */
|
||
rtc_clock_config();
|
||
/* RTC在VCORE_AON域,可使用VCORE_AON复位清除所有寄存器状态 */
|
||
|
||
/* 关闭RTC寄存器写保护 */
|
||
std_rtc_write_protection_disable();
|
||
|
||
/* RTC_OUT输出预分频的时钟信号1Hz */
|
||
BSP_Rtc_Output_Cfg();
|
||
|
||
/* 等待3s */
|
||
rt_thread_mdelay(3000);
|
||
|
||
if (FRTC_PPM > 0)
|
||
{
|
||
calp_val = RTC_SMOOTH_CALIB_PLUS_PULSES_RESET;
|
||
calm_val = FRTC_PPM / 0.954 + 0.5;
|
||
}
|
||
else if (FRTC_PPM < 0)
|
||
{
|
||
calp_val = RTC_SMOOTH_CALIB_PLUS_PULSES_SET;
|
||
calm_val = (512 + (FRTC_PPM / 0.954) + 0.5);
|
||
}
|
||
|
||
/* 设置校准参数 */
|
||
BSP_Rtc_Calib_Cfg((uint32_t)calp_val, (uint32_t)calm_val);
|
||
|
||
/* 使能RTC寄存器写保护 */
|
||
std_rtc_write_protection_enable();
|
||
|
||
/* RTC日期时间配置 */
|
||
BSP_Rtc_DateTime_Cfg(0x24, 0x08, 0x23, 0x14, 0x03, 0x05, 0x05);
|
||
|
||
|
||
return RT_EOK;
|
||
}
|
||
INIT_PREV_EXPORT(BSP_RTC_Init);
|