您的位置:首页 > 路由器知识路由器知识
OK210试用体验第十一篇:实时时钟(RTC)驱动开发实践与问题解析
2025-06-18人已围观
【OK210试用体验】第十一篇:实时时钟(RTC)驱动开发实践与问题解析
杨永胜
当前离线
经验2386
窥视卡
雷达卡
杨永胜
(楼主)
201594 23:00:59??只看该作者
3397|2|倒序浏览
本帖最后由iysheng于201595 00:00编辑
前几天因未携带家用路由器,一直使用NFS挂载根文件系统的我,今日终于收到新淘的路由器(图1)。迫不及待想测试前几天编写的程序,却碰上数据乱码问题。经反复排查,最终定位到RTC驱动源码的rtc_read函数——内核与用户空间数据传递处理不当是主因。通过针对性调整,问题得以解决,现将完整开发过程与解决思路整理如下。
(312.46KB,下载6次)
驱动开发关键问题与解决
首版驱动的乱码问题
首次运行程序时,读取的时钟数据出现乱码。经分析,问题出在rtc_read函数设计:内核空间与用户空间数据传递需通过特定接口完成,而我早期代码未正确处理这一过程。
首版rtc_read函数(存在缺陷):
```c
ssize_t rtc_read (struct file *filp, char __user *buff, size_t size, loff_t *ppos)
{
int i;
unsigned int ad_base=BCDSEC;
for(i=0; i<7; i++){//依次读取秒、分、时、日、星期、月、年(共7组数据)
unsigned int *adv=ioremap(ad_base, 4);//物理地址映射为虚拟地址
copy_to_user(buff, adv, 4);//尝试拷贝32位数据到用户空间
ad_base +=4;
buff +=4;
}
return 0;
}
```
此版本虽意识到需使用copy_to_user完成跨空间数据传递,但对32位时间数据的处理逻辑仍不完善。经多次调整,最终优化为:
优化后rtc_read函数(初步解决乱码):
```c
ssize_t rtc_read (struct file *filp, char __user *buff, size_t size, loff_t *ppos)
{
int i;
unsigned int ad_base=BCDSEC;
for(i=0; i<7; i++){
unsigned int *adv=ioremap(ad_base, 4);
copy_to_user(buff, adv, 4);
ad_base +=4;
buff +=4;
}
return 0;
}
```
此次调整重点解决了32位数据的完整拷贝问题,确保时间信息从内核到用户空间的准确传输。
完整驱动与用户程序实现
驱动核心代码
结合硬件特性,驱动代码需完成设备初始化、时间配置及数据读取功能。以下为核心代码片段(关键参数与寄存器地址详见表1):
```c
include
include
include
include"rtc.h"
unsigned int *rtccon;
unsigned int *rtcalm;
unsigned int *bcdyear,*bcdmon,*bcdday,*bcdweek,*bcdhour,*bcdmin,*bcdsec;
typedef struct INIT_TIME {
unsigned long year;
unsigned long mon;
unsigned long day;
unsigned long week;
unsigned long hour;
unsigned long min;
unsigned long sec;
}ITIME;
struct cdev rtcdev;
dev_t devnum;
int rtc_open (struct inode *inode, struct file *filp)
{
ITIME itime={0x15,0x8,0x30,0x7,0x21,0x57,0x27};//初始化时间参数
rtccon=ioremap(RTCCON,4);
readl(rtccon)|(1<<0); // 使能RTCCON
bcdyear=ioremap(BCDYEAR,4);writel(itime.year,bcdyear);
bcdmon=ioremap(BCDMON,4);writel(itime.mon,bcdmon);
bcdday=ioremap(BCDDAY,4);writel(itime.day,bcdday);
bcdweek=ioremap(BCDWEEK,4);writel(itime.week,bcdweek);
bcdhour=ioremap(BCDHOUR,4);writel(itime.hour,bcdhour);
bcdmin=ioremap(BCDMIN,4);writel(itime.min,bcdmin);
bcdsec=ioremap(BCDSEC,4);writel(itime.sec,bcdsec);
printk(KERN_INFO"RTC驱动初始化完成
");
return 0;
}
ssize_t rtc_read (struct file *filp, char __user *buff, size_t size, loff_t *ppos)
{
int i;
for(i=0; i<7; i++){
switch(i){
case 0: copy_to_user(buff, bcdsec,4); break;
case 1: copy_to_user(buff, bcdmin,4); break;
case 2: copy_to_user(buff, bcdhour,4); break;
case 3: copy_to_user(buff, bcdday,4); break;
case 4: copy_to_user(buff, bcdweek,4); break;
case 5: copy_to_user(buff, bcdmon,4); break;
case 6: copy_to_user(buff, bcdyear,4); break;
}
buff +=4;
}
return 0;
}
static struct file_operations rtcfops={
.open=rtc_open,
.owner=THIS_MODULE,
.read=rtc_read,
};
static int rtc_init(void)
{
cdev_init(&rtcdev,&rtcfops);
alloc_chrdev_region(&devnum,0,1,"ysrtc");
cdev_add(&rtcdev,devnum,1);
return 0;
}
static void rtc_exit(void)
{
cdev_del(&rtcdev);
unregister_chrdev_region(devnum,1);
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SIMON YANG");
module_init(rtc_init);
module_exit(rtc_exit);
```
用户程序实现
用户程序需通过设备文件与驱动交互,实现时间数据读取功能。以下为测试代码:
```c
include
include
include
include
include"rtc.h"
void mdelay(unsigned long a)
{
unsigned long b,c;
最新发布
- 2024最详细T12焊台制作指南:从元件到PID算法,新手也能看懂的STM32实战教程
- 2025年SEO实战数据复盘:持续系统性投入如何让企业站排名稳增120%
- 2025TCP异常处理完全指南:从崩溃恢复到性能调优
- 2025年家庭网络完全指南:从入门到进阶的实战手册
- 2025最新Docker容器访问宿主机网络全攻略:3大方案+10个避坑技巧,新手也能秒懂
- 2026年超全解析:ThinkCMF框架50+核心公共函数,新手小白也能秒懂的实用指南
- 2026路由器配置完全指南:从路由策略到PBR实战,小白也能看懂的网络优化手册
- 2026年超全IPv4协议实战指南:从基础原理到网络优化
- 2025物联网芯片选购指南:一文读懂ESP32-C6系列的4大核心优势与10项实用技巧
- 2025年OpenWrt完全开发指南:从源码编译到多系统部署的7大核心技能
相关文章
- 2024最详细T12焊台制作指南:从元件到PID算法,新手也能看懂的STM32实战教程
- 2025TCP异常处理完全指南:从崩溃恢复到性能调优
- 2025年家庭网络完全指南:从入门到进阶的实战手册
- 2025最新Docker容器访问宿主机网络全攻略:3大方案+10个避坑技巧,新手也能秒懂
- 2026年超全解析:ThinkCMF框架50+核心公共函数,新手小白也能秒懂的实用指南
- 2026路由器配置完全指南:从路由策略到PBR实战,小白也能看懂的网络优化手册
- 2026年超全IPv4协议实战指南:从基础原理到网络优化
- 2025物联网芯片选购指南:一文读懂ESP32-C6系列的4大核心优势与10项实用技巧
- 2025年OpenWrt完全开发指南:从源码编译到多系统部署的7大核心技能
- 2025年搞定虚拟机网络:桥接NATHost-Only实战指南(附10个避坑技巧)