注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
cer1991的个人空间 https://home.eeworld.com.cn/space-uid-414872.html [收藏] [复制] [分享] [RSS]
日志

参与HLEPER2416开发板助学计划——GPIO驱动

已有 593 次阅读2014-9-15 08:47 |个人分类:chaos

刚开学有点忙,没有来得及提交心得。今天把之前的GPIO驱动发上来给大家参考下。@spacexplorer 由于第一次学linux所以学的比较忙,还请boss多指点指点。
本驱动参考了《linux 设备驱动开发技术及应用》这本书,大家可以去看看。虽然书里用的是2.6的内核,君益兴提供了3.2的内核,但代码基本都能实现,可能部分代码需要改动。
先上GPIO驱动的代码
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include
  7. #include
  8. #include

  9. #include
  10. //#include

  11. #define RDWR_DEV_NAME "rdwrdev"
  12. #define RDWR_DEV_MAJOR 240

  13. //#define GPBCON 0x56000010
  14. //#define GPBDAT 0x56000014

  15. //static void *GPB_CON;
  16. //static void *GPB_DAT;
  17. volatile unsigned long *GPBCON,*GPBDAT;

  18. //#define RDWR_WRITE_CONFIG_ADDR *GPBCON
  19. //#define RDWR_WRITE_ADDR *GPBDAT
  20. //#define RDWR_READ_ADDR  *GPBDAT
  21. //#define RDWR_READ_CONFIG_ADD   *GPBCON


  22. int rdwr_open(struct inode *inode,struct file *filp)
  23. {
  24. //    RDWR_WRITE_CONFIG_ADD = 0x00000004;
  25. //    GPB_CON= 0x00000004;
  26.     (*GPBCON) = 0x00000004;
  27.     printk("dev open finished\n");
  28.     return 0;
  29. }

  30. ssize_t rdwr_read(struct file *filp,char *buf,size_t count,loff_t *f_pos )
  31. {
  32.     unsigned int status;
  33.     int loop;
  34.    
  35.     for(loop = 0;loop < count ;loop++)
  36.     {
  37. //        status = RDWR_READ_ADD & 0x00000004;
  38. //        status = GPB_DAT& 0x00000004;
  39.         status = ((*GPBDAT)&0x00000004);
  40. //        copy_to_user()
  41.         put_user(status,(char  *)&buf[loop]);   
  42.     }
  43.     return count;
  44. }

  45. ssize_t rdwr_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos)
  46. {
  47.     unsigned int status;
  48.     int loop;
  49.     for(loop = 0;loop < count;loop++)
  50.     {
  51.         get_user(status,(char *)buf);
  52. //        RDWR_WRITE_ADDR = status;
  53.         (*GPBDAT) = status;
  54.     }
  55.     return count;
  56. }

  57. int rdwr_release(struct inode *inode,struct file *filp)
  58. {
  59.     return 0;
  60. }

  61. struct file_operations rdwr_fops =
  62. {
  63.     .owner = THIS_MODULE,
  64.     .read  = rdwr_read,
  65.     .write = rdwr_write,
  66.     .open  = rdwr_open,
  67.     .release =  rdwr_release,
  68. };

  69. int rdwr_init(void)
  70. {
  71.     int result;
  72.    
  73.     result = register_chrdev(RDWR_DEV_MAJOR,RDWR_DEV_NAME,&rdwr_fops);
  74.     if(result < 0)
  75.     {
  76.         printk("rdwr init failed\n");
  77.         return result;
  78.     }
  79.     GPBCON = (volatile unsigned long *)ioremap(0x56000010,0x00000004);
  80.     GPBDAT = (volatile unsigned long *)ioremap(0x56000014,0x00000004);
  81.    // GPB_CON = ioremap(GPBCON,0x00000004);
  82.    // GPB_DAT = ioremap(GPBDAT,0x00000004);
  83.     printk("rdwr init success\n");
  84.     return 0;
  85. }

  86. void rdwr_exit(void)
  87. {
  88.     unregister_chrdev(RDWR_DEV_MAJOR,RDWR_DEV_NAME);
  89.     printk("rdwr exit success\n");
  90. }

  91. module_init(rdwr_init);
  92. module_exit(rdwr_exit);

  93. MODULE_LICENSE("Dual BSD/GPL");
复制代码
重点讲解其中几个比较重要的函数1.get_user,put_user这两个宏的效果是内核空间数据和用户空间数据的交换。
2(volatile unsigned long *)ioremap(0x56000010,0x00000004)这个函数的效果是把0x56000010这个物理地址映射到虚拟地址里。可能有人会问0x00000004是什么意思?我的理解是:arm是32位的,每个地址都是8位的,8*4=32正好是一个寄存器的长度。
3.rdwr_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos)这个函数的效果是把buf里的数据写到GPBDAT里,count决定写几次。




下面贴上应用程序的代码
  1. #include
  2. #include
  3. #include
  4. #include
  5. #include
  6. #include

  7. #define DEVICE_FILENAME "/dev/rdwrdev"

  8. int main()
  9. {
  10.     int dev;
  11.     char buff[128];
  12.     int loop;
  13.    
  14.     dev = open(DEVICE_FILENAME,O_RDWR|O_NDELAY);
  15.   
  16.     if(dev >= 0)
  17.     {
  18.         printf("Please wait input\n");
  19.         
  20. /*        while(1)
  21.         {
  22.             if(read(dev,buff,1)== 1)
  23.             {
  24.                     printf("read data [%02X]\n",buff[0]&0xff);
  25.                 if(buff[0]== 0x04)
  26.                 {
  27.                     break;
  28.                 }
  29.             }            
  30.         }*/
  31.         printf("input ok...\n");
  32.         printf("led flashing...\n");
  33.         for(loop = 0;loop < 5;loop++)
  34.         {
  35.             buff[0]= 0x02;
  36.             write(dev,buff,1);
  37.             sleep(1);
  38.             buff[0]= 0x00;
  39.             write(dev,buff,1);
  40.             sleep(1);
  41.         }
  42.         //buff[0] = 0x02;
  43.         //write(dev,buff,1);
  44.         close(dev);
  45.         printf("ioctl test finished\n");
  46.     }
  47.     else
  48.     {
  49.         printf("open dev failed\n");
  50.     }
  51.     return 0;
  52. }
复制代码
这个应用的效果是让led灭1s,亮1s如此反复5次。

makefile文件大家可以参考我之前写的关于hello_world的驱动。

编译过后把生成的.ko 和app文件传到开发板。

首先输入
  1. [root@jyxtec /]# mknod /dev/rdwrdev c 240 0
复制代码
创建设备文件
然后到达上传之前2个文件的文件夹
  1. [root@jyxtec /]# cd home/test
  2. [root@jyxtec test]# ls
  3. ioctl_test_app        ioctl_test_module.ko
复制代码
然后安装驱动
  1. [root@jyxtec test]# insmod ioctl_test_module.ko
  2. rdwr init success
复制代码
接着运行应用程序
  1. [root@jyxtec test]# ./ioctl_test_app
复制代码
  1. [root@jyxtec test]# ./ioctl_test_app
  2. dev open finished
  3. Please wait input
  4. input ok...
  5. led flashing...
  6. ioctl test finished
复制代码
就可以看到led闪烁5次。

原来我的渣像素,不过代码绝对可用。

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章