#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);