• 驱动开发,stm32mp157a开发板的led灯控制实验


    1.实验目的

            编写LED灯的驱动,在应用程序中编写控制LED灯亮灭的代码逻辑实现LED灯功能的控制;

    2.LED灯相关寄存器分析

    LED1->PE10 LED1亮灭:

    RCC寄存器[4]->1 0X50000A28

    GPIOE_MODER[21:20]->01 (输出) 0X50006000

    GPIOE_ODR[10]->1(输出高电平) 0(输出低电平)0X50006014

    LED2->PF10 LED2亮灭:

    RCC寄存器[5]->1 0X50000A28

    GPIOE_MODER[21:20]->01 (输出) 0X50006000

    GPIOE_ODR[10]->1(输出高电平) 0(输出低电平)0X50006014

    LED3->PE8 LED3亮灭:

    RCC寄存器[4]->1 0X50000A28

    GPIOE_MODER[17:16]->01 (输出) 0X50006000

    GPIOE_ODR[8]->1(输出高电平) 0(输出低电平)0X50006014

    GPIOE_OTYPER默认为00

    GPIOE_PUPDR默认为0

    GPIOE_OSPEEDR默认为00

    3.编写代码

    ---Makefile---工程管理文件

    1. modname?=demo
    2. arch?=arm
    3. ifeq ($(arch),arm)
    4. KERNELDIR:= /home/ubuntu/FSMP1A/linux-stm32mp-5.10.61-stm32mp-r2-r0/linux-5.10.61 #编译生成ARM架构
    5. else
    6. KERNELDIR:=/lib/modules/$(shell uname -r)/build #编译生成X86架构
    7. endif
    8. PWD:=$(shell pwd) #模块化编译文件路径
    9. all:
    10. make -C $(KERNELDIR) M=$(PWD) modules
    11. clean:
    12. make -C $(KERNELDIR) M=$(PWD) clean
    13. obj-m:=$(modname).o

    ---head.h---头文件

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. typedef struct
    4. {
    5. unsigned int MODER;
    6. unsigned int OTYPER;
    7. unsigned int OSPEEDR;
    8. unsigned int PUPDR;
    9. unsigned int IDR;
    10. unsigned int ODR;
    11. }gpio_t;
    12. //LED1和LED3寄存器地址
    13. #define LED1_ADDR 0x50006000
    14. #define LED2_ADDR 0x50007000
    15. #define LED3_ADDR 0x50006000
    16. #define RCC_ADDR 0x50000A28
    17. #endif

    ---mychrdev.c---驱动程序

    1. #include <linux/init.h>
    2. #include <linux/module.h>
    3. #include <linux/fs.h>
    4. #include <linux/uaccess.h>
    5. #include <linux/io.h>
    6. #include "head.h"
    7. #include<linux/device.h>
    8. char kbuf[128] = {0};
    9. unsigned int major;
    10. gpio_t *vir_led1;
    11. gpio_t *vir_led2;
    12. gpio_t *vir_led3;
    13. unsigned int *vir_rcc;
    14. struct class *cls;
    15. struct device *dev;
    16. //封装操作方法
    17. int mycdev_open(struct inode *inode, struct file *file)
    18. {
    19. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    20. return 0;
    21. }
    22. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    23. {
    24. int ret;
    25. if(size > sizeof(kbuf))
    26. {
    27. size = sizeof(kbuf);
    28. }
    29. ret = copy_to_user(ubuf,kbuf,size);
    30. if(ret)
    31. {
    32. printk("copy_to_user err\n");
    33. return -EIO;
    34. }
    35. return 0;
    36. }
    37. ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
    38. {
    39. unsigned long ret;
    40. if(size > sizeof(kbuf))
    41. {
    42. size = sizeof(kbuf);
    43. }
    44. ret = copy_from_user(kbuf,ubuf,size);
    45. if(ret)
    46. {
    47. printk("copy_from_user err\n");
    48. return -EIO;
    49. }
    50. switch(kbuf[0])
    51. {
    52. case '1':
    53. if(kbuf[1] == '1') //开灯
    54. vir_led1->ODR |= (0x1 << 10);
    55. else if(kbuf[1] == '0') //关灯
    56. vir_led1->ODR &= (~(0x1 << 10));
    57. break;
    58. case '2':
    59. if(kbuf[1] == '1') //开灯
    60. vir_led2->ODR |= (0x1 << 10);
    61. else if(kbuf[1] == '0') //关灯
    62. vir_led2->ODR &= (~(0x1 << 10));
    63. break;
    64. case '3':
    65. if(kbuf[1] == '1') //开灯
    66. vir_led3->ODR |= (0x1 << 8);
    67. else if(kbuf[1] == '0') //关灯
    68. vir_led3->ODR &= (~(0x1 << 8));
    69. break;
    70. default:
    71. printk("输入错误\n");
    72. }
    73. return 0;
    74. }
    75. int mycdev_close(struct inode *inode, struct file *file)
    76. {
    77. printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    78. return 0;
    79. }
    80. struct file_operations fops={
    81. .open=mycdev_open,
    82. .read=mycdev_read,
    83. .write=mycdev_write,
    84. .release=mycdev_close,
    85. };
    86. //相关寄存器地址映射及初始化
    87. int all_led_init(void)
    88. {
    89. //相关寄存器的内存映射
    90. vir_led1=ioremap(LED1_ADDR,sizeof(gpio_t));
    91. if(vir_led1 == NULL)
    92. {
    93. printk("物理内存映射失败%d\n",__LINE__);
    94. return -ENOMEM;
    95. }
    96. vir_led2=ioremap(LED2_ADDR,sizeof(gpio_t));
    97. if(vir_led2 == NULL)
    98. {
    99. printk("物理内存映射失败%d\n",__LINE__);
    100. return -ENOMEM;
    101. }
    102. vir_led3 = vir_led1;
    103. vir_rcc=ioremap(RCC_ADDR,4);
    104. if(vir_rcc == NULL)
    105. {
    106. printk("物理内存映射失败%d\n",__LINE__);
    107. return -ENOMEM;
    108. }
    109. printk("寄存器内存映射成功\n");
    110. //硬件寄存器的初始化
    111. (*vir_rcc) |= (0x3 << 4);
    112. //LED1
    113. vir_led1->MODER &= (~(0x3 << 20));
    114. vir_led1->MODER |= (0x1 << 20);
    115. vir_led1->ODR &= (~(0x1 << 10));
    116. //LED2
    117. vir_led2->MODER &= (~(0x3 << 20));
    118. vir_led2->MODER |= (0x1 << 20);
    119. vir_led2->ODR &= (~(0x1 << 10));
    120. //LED3
    121. vir_led3->MODER &= (~(0x3 << 16));
    122. vir_led3->MODER |= (0x1 << 16);
    123. vir_led3->ODR &= (~(0x1 << 8));
    124. printk("寄存器初始化成功\n");
    125. return 0;
    126. }
    127. //入口函数
    128. static int __init mycdev_init(void)
    129. {
    130. major = register_chrdev(0,"mychrdev",&fops);
    131. if(major < 0)
    132. {
    133. printk("字符设备驱动注册失败\n");
    134. return major;
    135. }
    136. printk("字符设备驱动注册成功:major=%d\n",major);
    137. //寄存器映射及初始化
    138. all_led_init();
    139. //向上提交目录
    140. cls = class_create(THIS_MODULE,"mychrdev");
    141. if(IS_ERR(cls))
    142. {
    143. printk("向上提交目录失败\n");
    144. return -PTR_ERR(cls);
    145. }
    146. printk("向上提交目录成功\n");
    147. //向上提交设备节点信息
    148. int i;
    149. for(i=0; i<3; i++)
    150. {
    151. dev = device_create(cls,NULL,MKDEV(major,i),NULL,"mychrdev%d",i);
    152. if(IS_ERR(dev))
    153. {
    154. printk("向上提交设备节点信息失败\n");
    155. return -PTR_ERR(dev);
    156. }
    157. }
    158. printk("向上提交设备节点信息成功\n");
    159. return 0;
    160. }
    161. //出口函数
    162. static void __exit mycdev_exit(void)
    163. {
    164. //销毁设备节点信息
    165. int i;
    166. for(i=0; i<3; i++)
    167. {
    168. device_destroy(cls,MKDEV(major,i));
    169. }
    170. //销毁目录信息
    171. class_destroy(cls);
    172. //取消物理内存的映射
    173. iounmap(vir_led1);
    174. iounmap(vir_led2);
    175. iounmap(vir_rcc);
    176. //字符设备驱动注销
    177. unregister_chrdev(major,"mychrdev");
    178. }
    179. //声明
    180. //入口函数地址
    181. module_init(mycdev_init);
    182. //出口函数地址
    183. module_exit(mycdev_exit);
    184. //遵循的GPL协议
    185. MODULE_LICENSE("GPL");

    ---test.c---应用程序测试程序

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

    4.测试

  • 相关阅读:
    蓝桥杯Python组知识点
    SpringBoot 玩一玩代码混淆,防止反编译代码泄露!
    DBeaverUE Mac版:数据库管理新纪元,一键掌控所有数据
    双十一期间高预算广告增加,开发者如何精细化运营才能达到抢量增收目标?
    数据结构与算法之一道题感受算法(算法入门)
    nesp实验八 路由器RIP协议路由实验
    vue项目做菜单权限时动态路由出现死循环的问题以及刷新页面store数据丢失页面空白问题
    厉害了,腾讯云云巢荣获信通院“云原生技术创新案例”奖!
    ElasticSearch-Mapping详解
    博客园美化教程
  • 原文地址:https://blog.csdn.net/weixin_46260677/article/details/132800373