Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
硬件RTC驱动
RTC
ENV中硬件RTC如何选择HSE时钟源
发布于 2022-10-09 12:59:35 浏览:1064
订阅该版
[tocm] **前景提要** 1. 我的板上LSE没有外接晶振,ENV中无奈只能选择LSI 2. LSI时钟源精度太差,不去改分频值的前提下,每1s有127ms的误差,难以接受 3. STM32是支持HSE时钟为RTC的时钟源 4. 主要是用在ulog上,方便后续看日志找对应的时间点 **先看结论** 1. 使用LSI时钟源 ![LSI时钟源.png](https://oss-club.rt-thread.org/uploads/20221009/9bfc6e9db5d63be57bd342930616258c.png "LSI时钟源.png") uart帧间隔为333ms,但ulog显示间隔为293ms tcpsend帧间隔为2s,但ulog显示间隔为1.746s 这误差实在是有点大呀。。。 2.使用HSE时钟源 ![HSE时钟源.png](https://oss-club.rt-thread.org/uploads/20221009/1aae18ea0d2e532925d5befe3ee02cbb.png "HSE时钟源.png") 虽然误差还是有1~2ms的误差,但已经足够使用了 如果还要提高精度,hal库里有相应的校准函数,这里就不深入了 # **修改过程如下** ## 1. 修改board/kconfig 为了跟原来的程序兼容,这里添加一些自己的宏 ```c menuconfig BSP_USING_ONCHIP_RTC bool "Enable RTC" select RT_USING_RTC default n if BSP_USING_ONCHIP_RTC choice prompt "Select clock source" default BSP_RTC_USING_LSE config BSP_RTC_USING_LSE bool "RTC USING LSE" config BSP_RTC_USING_LSI bool "RTC USING LSI" config BSP_RTC_USING_HSE_8M25DIV bool "RTC USING HSE 8M 25DIV" endchoice endif ``` 增加宏选择 `BSP_RTC_USING_HSE_8M25DIV` 然后ENV进memuconfig,选择新增加的宏,保存退出 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221009/3a6c01d7f64c26700aa634fb2175778f.png) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221009/7b69539b75a80889fd26c5da98dbe9ce.png) ## 2. 修改cubemax RTC时钟源 我的板子是F4,晶振8M,看官自行选择 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221009/2350d80ed234035f7c9e51ad30ed86e3.png) 配置完后,右上角生成代码即可 ## 3. 修改drv_rtc.c ### 1. 修改 stm32_rtc_init 修改点:22行,HSE时钟已经起振,这里主要是屏蔽LSE和LSI ```c static rt_err_t stm32_rtc_init(void) { #if !defined(SOC_SERIES_STM32H7) && !defined(SOC_SERIES_STM32WL) && !defined(SOC_SERIES_STM32WB) __HAL_RCC_PWR_CLK_ENABLE(); #endif RCC_OscInitTypeDef RCC_OscInitStruct = {0}; #ifdef BSP_RTC_USING_LSI #ifdef SOC_SERIES_STM32WB RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.LSIState = RCC_LSI_ON; HAL_RCC_OscConfig(&RCC_OscInitStruct); #else RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.LSIState = RCC_LSI_ON; HAL_RCC_OscConfig(&RCC_OscInitStruct); #endif #elif defined(BSP_RTC_USING_HSE_8M25DIV) #else RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.LSIState = RCC_LSI_OFF; HAL_RCC_OscConfig(&RCC_OscInitStruct); #endif if (rt_rtc_config() != RT_EOK) { LOG_E("rtc init failed."); return -RT_ERROR; } return RT_EOK; } ``` ### 2. 修改 rt_rtc_config() 这里要着重注意分频系数 配置出1HZ的RTC时钟源就可以了 公式: `HSE/DIV = AsynchPrediv * SynchPrediv` 如:`8M/25 = 125 * 2560` 修改点:9~10行,50~52行 ```c static rt_err_t rt_rtc_config(void) { RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; HAL_PWR_EnableBkUpAccess(); PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; #ifdef BSP_RTC_USING_LSI PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; #elif defined(BSP_RTC_USING_HSE_8M25DIV) PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_HSE_DIV25; #else PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; #endif HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); #if defined(SOC_SERIES_STM32WL) __HAL_RCC_RTCAPB_CLK_ENABLE(); #endif /* Enable RTC Clock */ __HAL_RCC_RTC_ENABLE(); RTC_Handler.Instance = RTC; #if defined(SOC_SERIES_STM32F1) RTC_Handler.Init.OutPut = RTC_OUTPUTSOURCE_NONE; RTC_Handler.Init.AsynchPrediv = RTC_AUTO_1_SECOND; #elif defined(SOC_SERIES_STM32F0) /* set the frequency division */ #ifdef BSP_RTC_USING_LSI RTC_Handler.Init.AsynchPrediv = 0XA0; RTC_Handler.Init.SynchPrediv = 0xFA; #else RTC_Handler.Init.AsynchPrediv = 0X7F; RTC_Handler.Init.SynchPrediv = 0x0130; #endif /* BSP_RTC_USING_LSI */ RTC_Handler.Init.HourFormat = RTC_HOURFORMAT_24; RTC_Handler.Init.OutPut = RTC_OUTPUT_DISABLE; RTC_Handler.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RTC_Handler.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; #elif defined(SOC_SERIES_STM32F2) || defined(SOC_SERIES_STM32F4) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32H7) || defined (SOC_SERIES_STM32WB) /* set the frequency division */ #ifdef BSP_RTC_USING_LSI RTC_Handler.Init.AsynchPrediv = 0x7D; RTC_Handler.Init.SynchPrediv = 0xFF; #elif defined(BSP_RTC_USING_HSE_8M25DIV) RTC_Handler.Init.AsynchPrediv = 0x7D-1; //125 RTC_Handler.Init.SynchPrediv = 0xA00-1; //2560 #else RTC_Handler.Init.AsynchPrediv = 0X7F; RTC_Handler.Init.SynchPrediv = 0xFF; #endif /* BSP_RTC_USING_LSI */ RTC_Handler.Init.HourFormat = RTC_HOURFORMAT_24; RTC_Handler.Init.OutPut = RTC_OUTPUT_DISABLE; RTC_Handler.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH; RTC_Handler.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; #endif if (HAL_RTCEx_BKUPRead(&RTC_Handler, RTC_BKP_DR1) != BKUP_REG_DATA) { LOG_I("RTC hasn't been configured, please use
command to config."); if (HAL_RTC_Init(&RTC_Handler) != HAL_OK) { return -RT_ERROR; } } #ifdef SOC_SERIES_STM32F1 else { /* F1 series need update by bkp reg datas */ rt_rtc_f1_bkp_update(); } #endif return RT_EOK; } ``` ### 3. 修改 get_rtc_timeval() 这里是ulog能否显示ms的关键 STM32的RTC是支持ms显示的,但不明白的是为什么原drv_rtc选择屏蔽 这里只需要将算出的 ms值传入 tv->tv_usec 即可 修改点:19~26行 ```c static void get_rtc_timeval(struct timeval *tv) { RTC_TimeTypeDef RTC_TimeStruct = {0}; RTC_DateTypeDef RTC_DateStruct = {0}; struct tm tm_new = {0}; HAL_RTC_GetTime(&RTC_Handler, &RTC_TimeStruct, RTC_FORMAT_BIN); HAL_RTC_GetDate(&RTC_Handler, &RTC_DateStruct, RTC_FORMAT_BIN); tm_new.tm_sec = RTC_TimeStruct.Seconds; tm_new.tm_min = RTC_TimeStruct.Minutes; tm_new.tm_hour = RTC_TimeStruct.Hours; tm_new.tm_mday = RTC_DateStruct.Date; tm_new.tm_mon = RTC_DateStruct.Month - 1; tm_new.tm_year = RTC_DateStruct.Year + 100; tv->tv_sec = timegm(&tm_new); #if defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32F4) #if defined(BSP_RTC_USING_HSE_8M25DIV) tv->tv_usec = (RTC_Handler.Init.SynchPrediv - RTC_TimeStruct.SubSeconds * 1.0) / RTC_Handler.Init.SynchPrediv * 1000.0 * 1000.0; #else tv->tv_usec = (255.0 - RTC_TimeStruct.SubSeconds * 1.0) / 256.0 * 1000.0 * 1000.0; #endif #endif } ``` ** 无意义的补充 ** 上面的误差,更多的是来自线程消耗的,同一个时间源,按理说应该不会有多少误差 加一个绝对延时,这个“误差" 就被抵消了。 ```c void tcpserv_send(void *parameter) { uint32_t LastTime; extern void proto_auto_poll(void); while(1) { //绝对延时 LastTime = rt_tick_get() - LastTime; rt_thread_mdelay(LastTime>2000 ? 0 : (2000-LastTime)); LastTime = rt_tick_get(); proto_auto_poll(); } } ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20221009/2640ed6edb20dee7ea15de2d7196a334.png)
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
aingsu
这家伙很懒,什么也没写!
文章
1
回答
3
被采纳
0
关注TA
发私信
相关文章
1
RTC驱动框架几点建议
2
求助:RTT在STM32F407上使用内置的RTC设置日期需重启生效,设置时间即时生效,有遇到同样问题的吗?
3
[新人试水] LPC1768 Nano3_9 添加RTC
4
STM32 关于RTC的问题
5
stm32f4xx-HAL BSP的RTC设置不对
6
关于STM32的RTC设置年份不正确的问题
7
RTT的RTC驱动调试
8
rtc驱动中的bkp模块起不到防止时间的重新设置
9
rtc时钟跑十几个小时后,比实际时间快几秒怎么解决
10
stm32如何断电之后开发板rtc时间继续往前跑
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部