【OK210试用体验】+第十一篇☞RTC(实时时钟)驱动,一些问题和解决方法。 - 在线问答 - 电子技术论坛 - 最好最受欢迎电子论坛!

【OK210试用体验】+第十一篇☞RTC(实时时钟)驱动,一些问题和解决方法。

杨永胜 ( 楼主 ) 2015-9-4 23:00:59  只看该作者 倒序浏览
本帖最后由 iysheng 于 2015-9-5 00:00 编辑

前几天开学,由于没有从家里把路由器带来,我又是一直使用的NFS挂载的跟文件系统,所以几天前,我在网上淘了一个路由器,今天下午到了,我也拍了张照片:
黄色框中所示,就是我淘的路由器。
赶紧把我几天前编写的程序运行试一试了,谁知道第一次并没有成功,主要是读取回来的数据,明显是乱码,通过不断的修改,问题主要是驱动源码中的rtc_read函数,我忘记了不能直接在内核空间和用户空间之间传递数据,最后通过多次的修改,我使用了copy_to_usr函数,还有一些对读取的数据进行的一些操作,我开始一直纠结在char __user *buff,这个地方,因为,很明显我要读取回来的时间数据不是8bit的,而是unsigned int 32bit的,通过仔细的分析,最后有点明白了,修改我的rtc_read函数如下:第一次修改后的rtc_read函数:
  1. ssize_t rtc_read (struct file *filp, char __user *buff, size_t size, loff_t *ppos)
  2. {
  3.         int i;
  4.         unsigned int ad_base =BCDSEC;
  5.         for(i=0; i<7; i++){//从秒,分,时,天,星期,月,年,刚好七组数据
  6.         unsigned int *adv = ioremap(ad_base, 4);//物理地址到虚拟地址的转换
  7.         copy_to_user(buff, adv, 4);//指名要读取32bit数据
  8.         ad_base += 4;//增加地址4,刚好读取8bit*4=32bit数据
  9.         buff += 4;//用户的数据地址也要相应的添加4
  10.         }
  11.         return 0;
  12. }
复制代码
解决了,这个问题后,我们就可以放出来所有的源代码了:
驱动部分:
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include "rtc.h"
  8. #include
  9. unsigned int *rtccon;
  10. unsigned int *rtcalm;
  11. unsigned int *bcdyear;
  12. unsigned int *bcdmon;
  13. unsigned int *bcdday;
  14. unsigned int *bcdweek;
  15. unsigned int *bcdhour;
  16. unsigned int *bcdmin;
  17. unsigned int *bcdsec;

  18. typedef struct INIT_tiME {
  19.         unsigned long year;
  20.         unsigned long mon;
  21.         unsigned long day;
  22.         unsigned long week;
  23.         unsigned long hour;
  24.         unsigned long min;
  25.         unsigned long sec;
  26. }ITIME;

  27. struct cdev rtcdev;//定义结构体
  28. dev_t devnum;//定义设备号

  29. /*定义open函数*/
  30. int rtc_open (struct inode *inode, struct file *filp)
  31. {
  32.         unsigned long temp1,temp2;
  33.         ITIME itime;
  34.         itime.year = 0x15;
  35.         itime.mon = 0x8;
  36.         itime.day = 0x30;
  37.         itime.week = 0x7;
  38.         itime.hour = 0x21;
  39.         itime.min = 0x57;
  40.         itime.sec = 0x27;
  41.                
  42.         rtccon = ioremap(RTCCON, 4);
  43.         temp1 = readl(rtccon);
  44.         temp2 = temp1 |(1<<0);
  45.         writel(temp2, rtccon);//使能RTCCON
  46.         
  47.         bcdyear = ioremap(BCDYEAR, 4);
  48.         writel(itime.year, bcdyear);
  49.         
  50.         bcdmon = ioremap(BCDMON, 4);
  51.         writel(itime.mon, bcdmon);
  52.         
  53.         bcdday = ioremap(BCDDAY, 4);
  54.         writel(itime.day, bcdday);
  55.         
  56.         bcdweek = ioremap(BCDWEEK, 4);
  57.         writel(itime.week, bcdweek);
  58.         
  59.         bcdhour = ioremap(BCDHOUR, 4);
  60.         writel(itime.hour, bcdhour);
  61.         
  62.         bcdmin = ioremap(BCDMIN, 4);
  63.         writel(itime.min, bcdmin);
  64.         
  65.         bcdsec = ioremap(BCDSEC, 4);
  66.         writel(itime.sec, bcdsec);
  67.         
  68.         printk(KERN_INFO"welcome to ysrtcn");
  69.         return 0;
  70. }
  71. ssize_t rtc_read (struct file *filp, char __user *buff, size_t size, loff_t *ppos)
  72. {
  73.         int i;
  74.         unsigned int ad_base =BCDSEC;
  75.         for(i=0; i<7; i++){
  76.         unsigned int *adv = ioremap(ad_base, 4);
  77.         copy_to_user(buff, adv, 4);
  78.         ad_base += 4;
  79.         buff += 4;
  80.         }
  81.         return 0;
  82. }

  83. /*声明函数操作集*/
  84. static struct file_operations rtcfops = {
  85.         .open = rtc_open,
  86.         .owner = THIS_MODULE,
  87.         .read = rtc_read,
  88. };

  89. static int rtc_init(void)//定义驱动入口函数
  90. {
  91.         cdev_init(&rtcdev, &rtcfops);//联系起来结构体和文件操作集
  92.         alloc_chrdev_region(&devnum, 0, 1, "ysrtc");//分配空间
  93.         cdev_add(&rtcdev, devnum, 1);//注册驱动
  94.         return 0;
  95. }

  96. static void rtc_exit(void)
  97. {
  98.         cdev_del(&rtcdev);//删除空间
  99.         unregister_chrdev_region(devnum, 1);//取消注册
  100. }

  101. MODULE_LICENSE("GPL");//声明LICENSE,防止安装时出现警告
  102. MODULE_AUTHOR("SIMON YANG");//声明驱动作者

  103. module_init(rtc_init);//声明驱动入口
  104. module_exit(rtc_exit);//声明驱动出口
复制代码
用户程序部分:
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include "rtc.h"
  7. #include //和ioctl函数相关的头文件声明也可以是/sys/ioctl.h

  8. void mdelay(unsigned long a)
  9. {
  10.         unsigned long b,c;
  11.         for(b=0; b
  12.         for(c=0; c<0xffff; c++);
  13. }

  14. int main(void)
  15. {
  16.         int fd = 0;
  17.         int i,temp;
  18.         unsigned int buff[7];       
  19.         fd = open("/dev/ysrtc", O_RDWR);//以读写方式打开设备
  20.        
  21.         if (fd == 0xffffffff){
  22.                 printf("open the keydev failed! the errno is %dn",errno);
  23.                 return errno;}
  24.         while(1){       
  25.         temp = buff[0];
  26.         for(i=0; i<7; i++)
  27.         read (fd, buff, sizeof(unsigned int)*7);
  28.         if(temp != buff[0]){
  29.         printf("year:%x mon:%x week:%x day:%x hour:%x min:%x sec:%xn",buff[6],buff[5],buff[4],buff[3],buff[2],buff[1],buff[0]);}
  30.         mdelay(1000);
  31.         }
  32.         return 0;
  33. }
复制代码


由于,我自己定义了一个mdelay函数,开始的时候,mdelay(1000)这段时间小于1s,所以读取回来的数据会有重复的部分:

于是,我修改为现在的,在每次输出之前都进行一次对秒数据的比较,如过不一样,则输出,否则继续读取数据,如上面的代码所示,修改之后效果如下:



这样就不会输出重复的数据了,
但是,等了一会之后,程序就崩溃了,如下图所示:


显示到了hour:21 min:58 sec:5的时候就提示我说什么空间分配不足的问题,这个就是一个大bug啊。通过思考,我发现还是rtc_read函数的问题,因为,在这个函数中,我一直不断地ioremap,这就相当于我是在不断地分配,占有内存空间,这不就是造成了资源的浪费吗?于是我修改了rtc_read函数,如下图所示:最后修改后的rtc_read:
  1. ssize_t rtc_read (struct file *filp, char __user *buff, size_t size, loff_t *ppos)
  2. {
  3.         int i;
  4.         for(i=0; i<7; i++){
  5.         switch(i){
  6.         case 0:
  7.         copy_to_user(buff, bcdsec, 4);
  8.         break;
  9.         case 1:
  10.         copy_to_user(buff, bcdmin, 4);
  11.         break;
  12.         case 2:
  13.         copy_to_user(buff, bcdhour, 4);
  14.         break;
  15.         case 3:
  16.         copy_to_user(buff, bcdday, 4);
  17.         break;
  18.         case 4:
  19.         copy_to_user(buff, bcdweek, 4);
  20.         break;
  21.         case 5:
  22.         copy_to_user(buff, bcdmon, 4);
  23.         break;
  24.         case 6:
  25.         copy_to_user(buff, bcdyear, 4);
  26.         break;
  27.         }
  28.         buff += 4;
  29.         }
  30.         return 0;
  31. }
复制代码
在这次修改中,我放弃了不断的ioremap,一直使用rtc_open函数中的虚拟地址,因为它是全局变量啊,最后很顺利的成功的运行了,如下图所示:



从上图中可以看到,本次已经顺利的运行到了hour:22 min:0 sec:6,此时我按下了Ctrl+z,中断了继续的显示,因为,此时已经可以证明修改后的驱动程序是可以顺利并且正常的输出的。
通过我的思考和尝试,终与解决了这些问题,真的很开心。最后附上我的头文件(就是一些寄存器的物理地址):
  1. #define RTC_BASE 0Xe2800000
  2. #define INTP RTC_BASE+0X30
  3. #define RTCCON RTC_BASE+0X40
  4. #define TICCNT RTC_BASE+0X44
  5. #define RTCALM RTC_BASE+0X50
  6. #define ALMSEC RTC_BASE+0X54
  7. #define ALMMIN RTC_BASE+0X58
  8. #define ALMHOUR RTC_BASE+0X5C
  9. #define ALMDATE RTC_BASE+0X60
  10. #define ALMMON RTC_BASE+0X64
  11. #define ALMYEAR RTC_BASE+0X68
  12. #define RTCRST RTC_BASE+0X6C
  13. #define BCDSEC RTC_BASE+0X70
  14. #define BCDMIN RTC_BASE+0X74
  15. #define BCDHOUR RTC_BASE+0X78
  16. #define BCDDAY RTC_BASE+0X7C
  17. #define BCDWEEK RTC_BASE+0X80
  18. #define BCDMON RTC_BASE+0X84
  19. #define BCDYEAR RTC_BASE+0X88
  20. #define CURTICCNT RTC_BASE+0X90
  21. #define RTCLVD RTC_BASE+0X94
复制代码
还有我的思维导图:

这都是为了养成好的习惯,至此RTC驱动程序也告一段落了







2个回复

mrbushy 发表于 2015-9-13 12:35:37
不错的分享........
回复 1

举报 使用道具

杨永胜 发表于 2015-9-13 15:22:14
mrbushy 发表于 2015-9-13 12:35
不错的分享........

谢谢额,,,
您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /6 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-11-21 20:00 , Processed in 0.638799 second(s), Total 51, Slave 36 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表