• 驱动开发2 CoetexA7核 字符设备驱动(LED亮灯)(单独映射寄存器实现+封装结构体映射实现)


    一、单独映射寄存器实现

    可参考arm点灯C语言 cortex-A7核 点LED灯 (附 汇编实现、使用C语言 循环实现、使用C语言 封装函数实现【重要、常用】)-CSDN博客

    1 应用程序 test.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main(int argc, char const *argv[])
    8. {
    9. char buf[128]={0};
    10. int fd = open("/dev/mychrdev",O_RDWR);
    11. if(fd < 0)
    12. {
    13. printf("打开设备文件失败\n");
    14. return -1;
    15. }
    16. printf("打开设备文件成功\n");
    17. while(1)
    18. {
    19. printf("请输入要进行的操作:0(关灯) 1(开灯) >>> ");
    20. fgets(buf,sizeof(buf),stdin);//在终端读一个字符串
    21. buf[strlen(buf) - 1] = '\0';
    22. write(fd, buf, sizeof(buf));//将数据传递给内核
    23. }
    24. close(fd);
    25. return 0;
    26. }

    2 头文件head.h

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. //GPIOE
    4. #define PHY_LED1_MODER 0X50006000
    5. #define PHY_LED1_ODR 0x50006014
    6. //GPIOF
    7. #define PHY_LED2_MODER 0X50007000
    8. #define PHY_LED2_ODR 0x50007014
    9. //RCC
    10. #define PHY_RCC 0x50000A28
    11. #endif

    3 驱动程序 demo.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include "head.h"
    7. unsigned int major;
    8. char kbuf[128] = {};
    9. //定义三个指针指向映射后的虚拟内存
    10. unsigned int *vir_moder_E;
    11. unsigned int *vir_odr_E;
    12. unsigned int *vir_moder_F;
    13. unsigned int *vir_odr_F;
    14. unsigned int *vir_rcc;
    15. //封装操作方法
    16. int mycdev_open(struct inode *inode, struct file *file)
    17. {
    18. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    19. return 0;
    20. }
    21. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size,loff_t *lof)
    22. {
    23. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    24. int ret;
    25. ret = copy_to_user(ubuf,kbuf,size);
    26. if (ret)
    27. {
    28. printk("copy_to_user filed\n");
    29. return -EIO;
    30. }
    31. return 0;
    32. }
    33. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size,loff_t *lof)
    34. {
    35. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    36. int ret;
    37. ret = copy_from_user(kbuf,ubuf,size);
    38. if (ret)
    39. {
    40. printk("copy_from_user filed\n");
    41. return -EIO;
    42. }
    43. if(kbuf[0] == '0') //关灯
    44. {
    45. //关灯逻辑
    46. (*vir_odr_E) &= (~(0x1 << 10)); //LED1默认关灯
    47. (*vir_odr_F) &= (~(0x1 << 10)); //LED2默认关灯
    48. (*vir_odr_E) &= (~(0x1 << 8)); //LED3默认关灯
    49. }
    50. else if(kbuf[0] == '1') //开灯
    51. {
    52. //开灯逻辑
    53. (*vir_odr_E) |= (0x1 << 10); //LED1
    54. (*vir_odr_F) |= (0x1 << 10); //LED2
    55. (*vir_odr_E) |= (0x1 << 8); //LED3
    56. }
    57. return 0;
    58. }
    59. int mycdev_close(struct inode *inode, struct file *file)
    60. {
    61. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    62. return 0;
    63. }
    64. //定义操作方法结构体对象
    65. struct file_operations fops = {
    66. .open = mycdev_open,
    67. .read = mycdev_read,
    68. .write = mycdev_write,
    69. .release = mycdev_close,
    70. };
    71. static int __init mycdev_init(void)
    72. {
    73. //注册字符设备驱动
    74. major = register_chrdev(0,"mychrdev",&fops);
    75. if(major < 0)
    76. {
    77. printk("字符设备驱动注册失败\n");
    78. return major;
    79. }
    80. printk("字符设备驱动注册成功major=%d\n",major);
    81. //进行寄存器的地址映射
    82. //GPIOE
    83. vir_moder_E = ioremap(PHY_LED1_MODER,4);
    84. if(vir_moder_E == NULL)
    85. {
    86. printk("物理内存地址映射失败%d\n",__LINE__);
    87. return -EFAULT;
    88. }
    89. vir_odr_E = ioremap(PHY_LED1_ODR,4);
    90. if(vir_odr_E == NULL)
    91. {
    92. printk("物理内存地址映射失败%d\n",__LINE__);
    93. return -EFAULT;
    94. }
    95. //GPIOF
    96. vir_moder_F = ioremap(PHY_LED2_MODER,4);
    97. if(vir_moder_F == NULL)
    98. {
    99. printk("物理内存地址映射失败%d\n",__LINE__);
    100. return -EFAULT;
    101. }
    102. vir_odr_F = ioremap(PHY_LED2_ODR,4);
    103. if(vir_odr_F == NULL)
    104. {
    105. printk("物理内存地址映射失败%d\n",__LINE__);
    106. return -EFAULT;
    107. }
    108. //RCC
    109. vir_rcc = ioremap(PHY_RCC,4);
    110. if(vir_rcc == NULL)
    111. {
    112. printk("物理内存地址映射失败%d\n",__LINE__);
    113. return -EFAULT;
    114. }
    115. printk("寄存器内存映射成功\n");
    116. //LED1寄存器初始化
    117. (*vir_rcc) |= (0x1 << 4); //GPIOE控制器时钟使能
    118. (*vir_moder_E) &= (~(0x3 << 20)); //MODER[21:20]->00
    119. (*vir_moder_E) |= (0x1 << 20); //MODER[21:20]->01
    120. (*vir_odr_E) &= (~(0x1 << 10)); //默认关灯
    121. //LED2寄存器初始化
    122. (*vir_rcc) |= (0x1 << 5); //GPIOF控制器时钟使能
    123. (*vir_moder_F) &= (~(0x3 << 20)); //MODER[21:20]->00
    124. (*vir_moder_F) |= (0x1 << 20); //MODER[21:20]->01
    125. (*vir_odr_F) &= (~(0x1 << 10)); //默认关灯
    126. //LED3寄存器初始化
    127. (*vir_rcc) |= (0x1 << 4); //GPIOE控制器时钟使能
    128. (*vir_moder_E) &= (~(0x3 << 16)); //MODER[17:16]->00
    129. (*vir_moder_E) |= (0x1 << 16); //MODER[17:16]->01
    130. (*vir_odr_E) &= (~(0x1 << 8)); //默认关灯
    131. return 0;
    132. }
    133. static void __exit mycdev_exit(void)
    134. {
    135. //取消内存映射
    136. iounmap(vir_moder_E);
    137. iounmap(vir_odr_E);
    138. iounmap(vir_moder_F);
    139. iounmap(vir_odr_F);
    140. iounmap(vir_rcc);
    141. //注册字符设备驱动
    142. unregister_chrdev(major,"mychrdev");
    143. }
    144. module_init(mycdev_init);
    145. module_exit(mycdev_exit);
    146. MODULE_LICENSE("GPL");

    编写好代码后,make成arm架构

    make arch=arm modname=demo

    使用交叉编译工具链

    arm-linux-gnueabihf-gcc test.c 

    将文件通过tftp传输到开发板中

    cp demo.ko ~/nfs/rootfs/
    cp a.out ~/nfs/rootfs/

    4 效果呈现

    二、封装结构体映射实现

    kbuf[0] 控制灯

    kbuf[1] 控制状态

    1 头文件head.h

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. typedef struct{
    4. unsigned int MODER;
    5. unsigned int OTYPER;
    6. unsigned int OSPEEDR;
    7. unsigned int PUPDR;
    8. unsigned int IDR;
    9. unsigned int ODR;
    10. }gpio_t;
    11. #define PHY_LED1_ADDR 0X50006000
    12. #define PHY_LED2_ADDR 0X50007000
    13. #define PHY_LED3_ADDR 0X50006000
    14. #define PHY_RCC_ADDR 0X50000A28
    15. #endif

    2 驱动程序 demo.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include"head.h"
    6. int major;
    7. char kbuf[128]={0};
    8. gpio_t *vir_led1;
    9. gpio_t *vir_led2;
    10. gpio_t *vir_led3;
    11. unsigned int *vir_rcc;
    12. int mycdev_open(struct inode *inode, struct file *file)
    13. {
    14. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    15. return 0;
    16. }
    17. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    18. {
    19. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    20. unsigned long ret;
    21. //向用户空间读取拷贝
    22. if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    23. size=sizeof(kbuf);
    24. ret=copy_to_user(ubuf,kbuf,size);
    25. if(ret)//拷贝失败
    26. {
    27. printk("copy_to_user filed\n");
    28. return ret;
    29. }
    30. return 0;
    31. }
    32. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    33. {
    34. unsigned long ret;
    35. //从用户空间读取数据
    36. if(size>sizeof(kbuf))//用户空间期待读取的大小内核满足不了,那就给内核支持的最大大小
    37. size=sizeof(kbuf);
    38. ret=copy_from_user(kbuf,ubuf,size);
    39. if(ret)//拷贝失败
    40. {
    41. printk("copy_to_user filed\n");
    42. return ret;
    43. }
    44. switch(kbuf[0]){
    45. case '1'://LED1
    46. if(kbuf[1]=='0')//关灯
    47. vir_led1->ODR &= (~(1<<10));
    48. else//开灯
    49. vir_led1->ODR |= 1<<10;
    50. break;
    51. case '2'://LED2
    52. if(kbuf[1]=='0')//关灯
    53. vir_led2->ODR &= (~(1<<10));
    54. else//开灯
    55. vir_led2->ODR |= 1<<10;
    56. break;
    57. case '3'://LED3
    58. if(kbuf[1]=='0')//关灯
    59. vir_led3->ODR &= (~(1<<8));
    60. else//开灯
    61. vir_led3->ODR |= 1<<8;
    62. break;
    63. }
    64. return 0;
    65. }
    66. int mycdev_close(struct inode *inode, struct file *file)
    67. {
    68. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    69. return 0;
    70. }
    71. //定义操作方法结构体变量并赋值
    72. struct file_operations fops={
    73. .open=mycdev_open,
    74. .read=mycdev_read,
    75. .write=mycdev_write,
    76. .release=mycdev_close,
    77. };
    78. int all_led_init(void)
    79. {
    80. //寄存器地址的映射
    81. vir_led1=ioremap(PHY_LED1_ADDR,sizeof(gpio_t));
    82. if(vir_led1==NULL)
    83. {
    84. printk("ioremap filed:%d\n",__LINE__);
    85. return -ENOMEM;
    86. }
    87. vir_led2=ioremap(PHY_LED2_ADDR,sizeof(gpio_t));
    88. if(vir_led2==NULL)
    89. {
    90. printk("ioremap filed:%d\n",__LINE__);
    91. return -ENOMEM;
    92. }
    93. vir_led3=vir_led1;
    94. vir_rcc=ioremap(PHY_RCC_ADDR,4);
    95. if(vir_rcc==NULL)
    96. {
    97. printk("ioremap filed:%d\n",__LINE__);
    98. return -ENOMEM;
    99. }
    100. printk("物理地址映射成功\n");
    101. //寄存器的初始化
    102. //rcc
    103. (*vir_rcc) |= (3<<4);
    104. //led1
    105. vir_led1->MODER &= (~(3<<20));
    106. vir_led1->MODER |= (1<<20);
    107. vir_led1->ODR &= (~(1<<10));
    108. //led2
    109. vir_led2->MODER &= (~(3<<20));
    110. vir_led2->MODER |= (1<<20);
    111. vir_led2->ODR &= (~(1<<10));
    112. //led3
    113. vir_led3->MODER &= (~(3<<16));
    114. vir_led1->MODER |= (1<<16);
    115. vir_led1->ODR &= (~(1<<8));
    116. printk("寄存器初始化成功\n");
    117. return 0;
    118. }
    119. static int __init mycdev_init(void)
    120. {
    121. //字符设备驱动注册
    122. major=register_chrdev(0,"mychrdev",&fops);
    123. if(major<0)
    124. {
    125. printk("字符设备驱动注册失败\n");
    126. return major;
    127. }
    128. printk("字符设备驱动注册成功:major=%d\n",major);
    129. //寄存器映射以及初始化
    130. all_led_init();
    131. return 0;
    132. }
    133. static void __exit mycdev_exit(void)
    134. {
    135. //取消地址映射
    136. iounmap(vir_led1);
    137. iounmap(vir_led2);
    138. iounmap(vir_rcc);
    139. //注销字符设备驱动
    140. unregister_chrdev(major,"mychrdev");
    141. }
    142. module_init(mycdev_init);
    143. module_exit(mycdev_exit);
    144. MODULE_LICENSE("GPL");

    3 应用程序 test.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. int main(int argc, char const *argv[])
    9. {
    10. char buf[128]={0};
    11. int fd=open("/dev/mychrdev",O_RDWR);
    12. if(fd<0)
    13. {
    14. printf("打开设备文件失败\n");
    15. exit(-1);
    16. }
    17. while(1)
    18. {
    19. //从终端读取
    20. printf("请输入两个字符\n");
    21. printf("第一个字符:1(LED1) 2(LED2) 3(LED3)\n");
    22. printf("第二个字符:0(关灯) 1(开灯)\n");
    23. printf("请输入>");
    24. fgets(buf,sizeof(buf),stdin);
    25. buf[strlen(buf)-1]='\0';
    26. //向设备文件中写
    27. write(fd,buf,sizeof(buf));
    28. }
    29. close(fd);
    30. return 0;
    31. }

  • 相关阅读:
    方案设计|汽车轮胎数显胎压计方案
    MATLAB 边界点排序(最近邻域搜索算法)
    man 1 2 3的区别
    10张流程图+部署图,讲透单点登录原理与简单实现
    Java题目汇总(二)
    Maven生命周期
    MySQL学习笔记(七)——数据处理之增删改
    合合信息财务自动化解决方案亮相腾讯全球数字生态大会,助力企业财务合规建设
    centos安装kingbase(人大进仓)数据库
    协程: Flow 异步流 /
  • 原文地址:https://blog.csdn.net/Smallxu_/article/details/133953396