Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread
RTC
在GD32F470Z的RTC适配笔记
发布于 2024-12-08 22:54:43 浏览:262
订阅该版
执行scons --menuconfig打开使能rtc(该过程太简单,略) 原有代码编译有错: ![编译错误.png](https://oss-club.rt-thread.org/uploads/20241208/cbe5165df63a5e5bd260045d1b8fd147.png) 编码不认识RCU_BKPI 从开发板的例程代码(购买开发板时厂商提供了一部分非rt-thread的代码)里参考一部分代码,重写函数rt_hw_rtc_init的开始部分: ```c rcu_periph_clock_enable(RCU_PMU); pmu_backup_write_enable(); rtc_pre_config(); if(BKP_VALUE != RTC_BKP0) { rtc_setup(); } else { if(RESET != rcu_flag_get(RCU_FLAG_PORRST))/**< 检测复位时钟源 */ { LOG_I("power on reset occurred ..."); } else if(RESET != rcu_flag_get(RCU_FLAG_EPRST)) { LOG_I("external reset occurred ..."); } LOG_I("no need to configure RTC ..."); } rcu_all_reset_flag_clear(); ``` 函数的全部内容如下: ```c static int rt_hw_rtc_init(void) { rcu_periph_clock_enable(RCU_PMU); pmu_backup_write_enable(); rtc_pre_config(); if(BKP_VALUE != RTC_BKP0) { rtc_setup(); } else { if(RESET != rcu_flag_get(RCU_FLAG_PORRST))/**< 检测复位时钟源 */ { LOG_I("power on reset occurred ..."); } else if(RESET != rcu_flag_get(RCU_FLAG_EPRST)) { LOG_I("external reset occurred ..."); } LOG_I("no need to configure RTC ..."); } rcu_all_reset_flag_clear(); #ifdef RT_USING_DEVICE_OPS g_gd32_rtc_dev.rtc_dev.ops = &g_gd32_rtc_ops; #else g_gd32_rtc_dev.rtc_dev.init = RT_NULL; g_gd32_rtc_dev.rtc_dev.open = RT_NULL; g_gd32_rtc_dev.rtc_dev.close = RT_NULL; g_gd32_rtc_dev.rtc_dev.read = RT_NULL; g_gd32_rtc_dev.rtc_dev.write = RT_NULL; g_gd32_rtc_dev.rtc_dev.control = rt_gd32_rtc_control; #endif g_gd32_rtc_dev.rtc_dev.type = RT_Device_Class_RTC; g_gd32_rtc_dev.rtc_dev.rx_indicate = RT_NULL; g_gd32_rtc_dev.rtc_dev.tx_complete = RT_NULL; g_gd32_rtc_dev.rtc_dev.user_data = RT_NULL; rt_err_t ret = rt_device_register(&g_gd32_rtc_dev.rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR); if (ret != RT_EOK) { LOG_E("failed register internal rtc device, err=%d", ret); } return ret; } ``` 再次编译,出现了链接错误: ![链接错误.png](https://oss-club.rt-thread.org/uploads/20241208/8d195f2ca8626832cae4b28b274c288d.png) 函数set_rtc_timestamp改造成如下样子: ```c static rt_err_t set_rtc_timestamp(time_t time_stamp) { time_t stamp = time_stamp; struct tm *timeinfo = gmtime(&stamp); return RT_EOK; } ``` set_rtc_timestamp函数用于设置时间,这个时间最终会转换成芯片所支持的方式。不过此处的函数其实是一个空架子,它并没有将时间写入到芯片内部(暂时不支持时间设置吧)。 结合开发板厂家的rtc例程的代码,函数get_rtc_timestamp改造成如下样子: ```c static time_t get_rtc_timestamp(void) { rtc_parameter_struct para; rtc_current_time_get(¶); struct tm timeinfo = { .tm_year = para.year, .tm_mon = para.month, .tm_mday = para.date, .tm_wday = para.day_of_week, //.tm_yday = , .tm_hour = para.hour, .tm_min = para.minute, .tm_sec = para.second, .tm_isdst = -1, // 自动判断是否是夏令时 }; time_t rawtime = mktime(&timeinfo); return rawtime; } ``` 在应用程序的终端执行date命令,每次都显示同一个时间(说明还是有问题呗): ![时间执行显示固定值.png](https://oss-club.rt-thread.org/uploads/20241208/2d78796d726cfb81e109e2ea19165e2c.png) 代码跟踪,在函数get_rtc_timestamp里加断点, ![调试图片1.png](https://oss-club.rt-thread.org/uploads/20241208/ce7249fbc3b05d52f911858a2e4aeeb7.png) 执行date命令时并没有进入到函数!!! 进一步,在调用get_rtc_timestamp函数的rt_gd32_rtc_control里增加断点,这次执行date时,进入了rt_gd32_rtc_control函数,但是没有进入get_rtc_timestamp函数 ![调试图片2.png](https://oss-club.rt-thread.org/uploads/20241208/8c827bde6b336f72e0186791f4e0f52f.png) ![调试图片3.png](https://oss-club.rt-thread.org/uploads/20241208/1dda1ded80ed737335a26903cf7e891e.png) 此时的cmd值为0x603, 对比发现,原来是函数rt_gd32_rtc_control代码的case语句有问题!!! 应该将 RT_DEVICE_CTRL_RTC_GET_TIME 修改为 RT_DEVICE_CTRL_RTC_GET_TIMEVAL 修改之后,编译的代码执行,这次能够进入函数get_rtc_timestamp了 但是,终端显示的信息有问题: ![时间执行显示错误.png](https://oss-club.rt-thread.org/uploads/20241208/2ef459a5ce8d7b8405437506b0747b81.png) 年份都到了2106年了,而且系统明显提示,时间戳为负数,它有问题。 现在从GD32F4xx手册上寻找信息,以下时手册的rtc的部分内容: ![芯片手册截图.png](https://oss-club.rt-thread.org/uploads/20241208/4cde029acfa0adf5d403811c5a017dbd.png.webp) 可见函数get_rtc_timestamp里没有将原始的BCD格式的时间信息转换为struct tm 所要求的方式(原始的rtt代码没有注意这个区别!!!),由此导致mktime转换出错。 因此将get_rtc_timestamp函数修改成如下所示: ```c static time_t get_rtc_timestamp(void) { rtc_parameter_struct para; rtc_current_time_get(¶); struct tm timeinfo = { .tm_year = 10*((para.year )>>4) + ((para.year ) & 0x0F), //para.year, .tm_mon = 10*((para.month )>>4) + ((para.month ) & 0x01), //para.month, .tm_mday = 10*((para.date )>>4) + ((para.date ) & 0x03), //para.date, .tm_wday = (para.day_of_week)&0x07, //.tm_yday = , .tm_hour = 10*((para.hour )>>4) + ((para.hour ) & 0x03), //para.hour, .tm_min = 10*((para.minute )>>4) + ((para.minute ) & 0x07), //para.minute, .tm_sec = 10*((para.second )>>4) + ((para.second ) & 0x07), //para.second, .tm_isdst = -1, // 自动判断是否是夏令时 }; time_t rawtime = mktime(&timeinfo); return rawtime; } ``` 修正之后的代码,执行情况: ![时间执行显示错误2.png](https://oss-club.rt-thread.org/uploads/20241208/2040a74cf3c89be22a9a96211826551f.png) 再次修改,直接给timeinfo变量赋值(固定的): ```c static time_t get_rtc_timestamp(void) { rtc_parameter_struct para; rtc_current_time_get(¶); struct tm timeinfo = { #if 0 .tm_year = 10*((para.year )>>4) + ((para.year ) & 0x0F), //para.year, .tm_mon = 10*((para.month )>>4) + ((para.month ) & 0x01), //para.month, .tm_mday = 10*((para.date )>>4) + ((para.date ) & 0x03), //para.date, .tm_wday = (para.day_of_week)&0x07, //.tm_yday = , .tm_hour = 10*((para.hour )>>4) + ((para.hour ) & 0x03), //para.hour, .tm_min = 10*((para.minute )>>4) + ((para.minute ) & 0x07), //para.minute, .tm_sec = 10*((para.second )>>4) + ((para.second ) & 0x07), //para.second, .tm_isdst = -1, // 自动判断是否是夏令时 #else .tm_year = 2024-1900, .tm_mon = 12-1, .tm_mday = 2, .tm_hour = 1, .tm_min = 50, .tm_sec = 11, .tm_isdst = -1, #endif }; time_t rawtime = mktime(&timeinfo); return rawtime; } ``` 这次显示的时间正确了,但是时间一直固定(笔者不贴图了),说明使用mktime转换时间本身没有问题。 所以这次修改函数rtc_setup,将当前的时间装载进去: ```c static void rtc_setup(void) { struct tm timeinfo = { .tm_year = 2024-1900, .tm_mon = 12-1, .tm_mday = 2, .tm_hour = 1, .tm_min = 50, .tm_sec = 11, .tm_isdst = -1, }; rtc_parameter_struct para = { .factor_asyn = prescaler_a, .factor_syn = prescaler_s, .year = (timeinfo.tm_year/10)*16 + (timeinfo.tm_year%10), .day_of_week = RTC_SATURDAY, .month = RTC_APR, .date = 0x30, .display_format = RTC_24HOUR, .hour = (timeinfo.tm_hour/10)*16 + (timeinfo.tm_hour%10), .minute = (timeinfo.tm_min/10 )*16 + (timeinfo.tm_min%10), .second = (timeinfo.tm_sec/10 )*16 + (timeinfo.tm_sec%10), .am_pm = RTC_AM, }; if(ERROR == rtc_init(¶)) { LOG_E("RTC time configuration failed !!!"); } else { RTC_BKP0 = BKP_VALUE; } } ``` 同时函数get_rtc_timestamp修改成如下: ```c static time_t get_rtc_timestamp(void) { rtc_parameter_struct para; rtc_current_time_get(¶); struct tm timeinfo = { .tm_year = 10*((para.year )>>4) + ((para.year ) & 0x0F), //para.year, .tm_mon = 10*((para.month )>>4) + ((para.month ) & 0x01), //para.month, .tm_mday = 10*((para.date )>>4) + ((para.date ) & 0x03), //para.date, .tm_wday = (para.day_of_week)&0x07, //.tm_yday = , .tm_hour = 10*((para.hour )>>4) + ((para.hour ) & 0x03), //para.hour, .tm_min = 10*((para.minute )>>4) + ((para.minute ) & 0x07), //para.minute, .tm_sec = 10*((para.second )>>4) + ((para.second ) & 0x07), //para.second, .tm_isdst = -1, // 自动判断是否是夏令时 }; time_t rawtime = mktime(&timeinfo); return rawtime; } ``` 这次系统启动之后,时间显示正常,也能够行走: ![时间执行显示正确.png](https://oss-club.rt-thread.org/uploads/20241208/a0628de158c30a8c4666da841a60d30d.png) 仿照rtc_setup函数完善set_rtc_timestamp函数,内容如下: ```c static rt_err_t set_rtc_timestamp(time_t time_stamp) { time_t stamp = time_stamp; struct tm *timeinfo = localtime(&stamp); rtc_parameter_struct para = { .factor_asyn = prescaler_a, .factor_syn = prescaler_s, .year = (timeinfo->tm_year/10)*16 + (timeinfo->tm_year%10), .day_of_week = RTC_SATURDAY, .month = RTC_APR, .date = 0x30, .display_format = RTC_24HOUR, .hour = (timeinfo->tm_hour/10)*16 + (timeinfo->tm_hour%10), .minute = (timeinfo->tm_min/10 )*16 + (timeinfo->tm_min%10), .second = (timeinfo->tm_sec/10 )*16 + (timeinfo->tm_sec%10), .am_pm = RTC_AM, }; if(ERROR == rtc_init(¶)) { LOG_E("RTC time configuration failed !!!"); return -RT_EINVAL; } else { RTC_BKP0 = BKP_VALUE; } return RT_EOK; } ``` 实测可以用date设置时间,以下是设置时间的命令: ```c date 2024 12 02 11 24 30 ``` 命令格式要求: ```c please input: date [year month day hour min sec] or date e.g: date 2018 01 01 23 59 59 or date ``` 总结: 1. 开发板厂商提供的代码有一定的参考意义(但是要识别出与自己目标的异同) 2. 灵活使用调试跟踪,观察代码分支的执行情况 3. 芯片手册(特别是有寄存器的那种手册)是编码的基本来源,如果厂商的代码也存在问题,寄存器手册就是最根本的保障。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
大龄码农
这家伙很懒,什么也没写!
文章
3
回答
1
被采纳
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
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
xusiwei1236
8
个答案
2
次被采纳
踩姑娘的小蘑菇
1
个答案
2
次被采纳
用户名由3_15位
7
个答案
1
次被采纳
bernard
4
个答案
1
次被采纳
RTT_逍遥
3
个答案
1
次被采纳
本月文章贡献
聚散无由
2
篇文章
15
次点赞
catcatbing
2
篇文章
5
次点赞
Wade
2
篇文章
4
次点赞
Ghost_Girls
1
篇文章
6
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部