• 驱动操作控制LED灯


    控制LED灯:

    驱动如何操作寄存器

    rgb_led灯的寄存器是物理地址,在linux内核启动之后,

    在使用地址的时候,操作的全是虚拟地址。需要将物理地址

    转化为虚拟地址。在驱动代码中操作的虚拟地址就相当于

    操作实际的物理地址。

    物理地址<------>虚拟地址

    void * ioremap(phys_addr_t offset, unsigned long size)

    功能:将物理地址映射成虚拟地址

    参数:

    @offset :要映射的物理地址

    @size   :大小(字节)

    返回值:成功返回虚拟地址,失败返回NULL; 

    void iounmap(void  *addr)

    功能:取消映射

    参数:

    @addr :虚拟地址

    返回值:无

    RGB_led 

    red  :gpioa28

    GPIOXOUT   :控制高低电平的   0xC001A000

    GPIOxOUTENB:输入输出模式    0xC001A004

    GPIOxALTFN1:function寄存器  0xC001A024

    green:gpioe13

    0xC001e000

    blue :gpiob12

    0xC001b000

    指针类型加1是加的他的类型大小

    驱动控制灯

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int major=0;
    8. #define CNAME "hello"
    9. char kbuf[128]={0};
    10. int dev=0;
    11. #define RED_BASE 0XC001A000
    12. #define BLUE_BASE 0XC001B000
    13. #define GREEN_BASE 0XC001E000
    14. unsigned int *red_base=NULL;
    15. unsigned int *blue_base=NULL;
    16. unsigned int *green_base=NULL;
    17. ssize_t mycdev_read (struct file *file, char __user *user, size_t size, loff_t * loff)
    18. {
    19. //printk("this is read");
    20. if(size>128){
    21. size=128;
    22. }
    23. dev=copy_to_user(user,kbuf,size);
    24. if(dev)
    25. {
    26. printk("copy to user errer");
    27. return dev;
    28. }
    29. return 0;
    30. }
    31. ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
    32. {
    33. //printk("this is write");
    34. if(size>128){
    35. size=128;
    36. }
    37. dev=copy_from_user(kbuf,user,size);
    38. return 0;
    39. }
    40. int mycdev_open (struct inode *inode, struct file *file)
    41. {
    42. printk("this is open");
    43. return 0;
    44. }
    45. int mycdev_release (struct inode *inode, struct file *file)
    46. {
    47. printk("this is close");
    48. return 0;
    49. }
    50. const struct file_operations fops={
    51. .open=mycdev_open,
    52. .read=mycdev_read,
    53. .write=mycdev_write,
    54. .release=mycdev_release,
    55. };
    56. static int __init hello_init(void)//入口
    57. {
    58. major=register_chrdev(major,CNAME,&fops);
    59. if(major<0)
    60. {
    61. printk("register chrdev error");
    62. }
    63. red_base=ioremap(RED_BASE,36);
    64. if(red_base==NULL)
    65. {
    66. printk("red ioremap error\n");
    67. return -ENOMEM;
    68. }
    69. blue_base=ioremap(BLUE_BASE,36);
    70. if(blue_base==NULL)
    71. {
    72. printk("blue ioremap error\n");
    73. return -ENOMEM;
    74. }
    75. green_base=ioremap(GREEN_BASE,36);
    76. if(green_base==NULL)
    77. {
    78. printk("green ioremap error\n");
    79. return -ENOMEM;
    80. }
    81. *red_base &=~(1<<28);
    82. *(red_base+1) |=1<<28;
    83. *(red_base+9) |=3<<24;
    84. return 0;
    85. }
    86. static void __exit hello_exit(void)//出口
    87. {
    88. iounmap(green_base);
    89. iounmap(blue_base);
    90. iounmap(red_base);
    91. unregister_chrdev(major,CNAME);
    92. }
    93. module_init(hello_init);//告诉内核驱动的入口
    94. module_exit(hello_exit);//告诉内核驱动的出口
    95. MODULE_LICENSE("GPL");

    应用层控制灯

    驱动层(只有部分程序)

    1. #define RED_ON *red_base |= 1<<28
    2. #define RED_OF *red_base &= ~(1<<28)
    3. ssize_t mycdev_write (struct file *file, const char __user *user, size_t size, loff_t *loff)
    4. {
    5. //printk("this is write");
    6. if(size>128){
    7. size=128;
    8. }
    9. dev=copy_from_user(kbuf,user,size);
    10. if(kbuf[0]==1)
    11. {
    12. RED_ON;
    13. }
    14. else{
    15. RED_OF;
    16. }
    17. return 0;
    18. }

    应用层(部分)

    1. sleep(1);
    2. buf[0]=buf[0]?0:1;
    3. while(1)
    4. {
    5. write(fd,buf,sizeof(buf));
    6. sleep(1);
    7. buf[0]=buf[0]?0:1;
    8. }

    详细步骤

    1.写宏定义灯的基地址

     2.虚拟地址声明

     3.去注册驱动下做地址映射

     物理地址 长度一个占四个 四九三十六

     

     其他灯同理去映射虚拟地址

     偏移地址

     int四字节 +1等于+4

     #include

    取消地址

     

    vi MAKEFILE

     打开开发板,关闭内核的

    再make

    放到nfs里

     

     进行应用:

    内核层:

     

     

     

     应用层

     make一下

    vi test.c

     

     

     

     

     

     vi MAKEFILE

     

     

     

     

     打开nfs

     

     

     

     

    自动创建设备节点

    #include 

    自动创建设备节点:

    struct class *cls;

    cls = class_create(owner, name) /void class_destroy(struct class *cls)

    功能:向用户空间提交目录信息

    参数:

    @owner :THIS_MODULE

    @name  :目录名字

    返回值:成功返回struct class *指针

    失败返回错误码指针 int (-5)

    if(IS_ERR(cls)){

    }

    struct device *device_create(struct class *class, struct device *parent,

                               dev_t devt, void *drvdata, const char *fmt, ...)

    /void device_destroy(struct class *class, dev_t devt)

    功能:向用户空间提交文件信息

    参数:

               @class :目录名字(向用户空间提交目录信息时产生的返回值)

               @parent:NULL

               @devt  :设备号    MKDEV(major,0)

               @drvdata :NULL

               @fmt   :文件的名字

    返回值:成功返回struct device *指针

                  失败返回错误码指针 int (-5)

    1. struct class*cls;
    2. struct device *dev;
    3. //自动创建设备节点
    4. cls = class_create(THIS_MODULE,CNAME);
    5. if(IS_ERR(cls)){
    6. printk("class create error\n");
    7. return PTR_ERR(cls);
    8. }
    9. dev = device_create(cls,NULL,MKDEV(major,0),NULL
    10. ,CNAME);
    11. if(IS_ERR(dev)){
    12. printk("device create error\n");
    13. return PTR_ERR(dev);
    14. }
    1. //出口-》这里写了卸载时注销的函数
    2. static void __exit hello_exit(void)//出口
    3. {
    4. device_destroy(devc,MKDEV(major,1));//注销内容
    5. class_destroy(cls);//注销目录
    6. iounmap(green_base);
    7. iounmap(blue_base);
    8. iounmap(red_base);
    9. unregister_chrdev(major,CNAME);
    10. }

    注意:MKDEV(major,0)为一个宏用于配置主设备号和次设备号

    详细步骤

    写在入口

    声明:

     在入口处

     改为

     

     

     

     

     

     make

     自动创建设备节点建立在dev里

    ioctl函数

    用户:

       #include 

       int ioctl(int fd, int request, ...);

    (让点灯的代码变得简洁)

       参数:

    @fd     : 打开文件产生的文件描述符

    @request: 请求码(读写|第三个参数传递的字节的个数),

    :在sys/ioctl.h中有这个请求码的定义方式。

    @...    :可写、可不写,如果要写,写一个内存的地址

    内核:

     long (*unlocked_ioctl) (struct file *, unsigned int,unsigned long)

    作用:此函数指针原型位于struct file_operations结构体当中,配合应用层ioctl函数实现指令传递的功能

     

     vi test.c

     

     

     

     

     

     

     

  • 相关阅读:
    C++ 类和对象 (5) 析构函数
    Redis高可用
    C++基础知识:冒泡排序(利用C++实现冒泡排序)
    java计算机毕业设计酒店管理系统设计与实现源码+mysql数据库+系统+lw文档+部署
    React动态生成二维码和毫米(mm)单位转像素(px)单位
    软件工程复习
    OpenHarmony社区运营报告(2023年8月)
    Vue3多介绍使用
    SpringCloud全系列知识(3)——Http客户端Feign
    如何解决if...else,9条锦囊妙计,助你写出更优雅的代码(荣耀典藏版)
  • 原文地址:https://blog.csdn.net/Summer_taotao/article/details/131084198