查看: 1859|回复: 1

【米尔MYD-C8MMX开发板】+ 6、gpio驱动led灯linux驱动程序

[复制链接]
  • TA的每日心情
    开心
    昨天 21:13
  • 签到天数: 1057 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2020-6-23 15:14:16 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 TLLED 于 2020-6-23 15:14 编辑

            开始学习在米尔MYD-C8MMX开发板linux开发环境下编写驱动程序。开发板使用的linxu版本是linux4.14板,给予linux4版本下的驱动都是基于设备树结构进行驱动程序开发的。下面使用板卡上的LED灯,使用GPIO 来驱动LED。


        一、硬件电路
       
        开发板上的LED灯对应的端口,这次使用的端口是GPIO5_4,LED1指示灯,LED2用指示系统运行就不在改动LED2。
        003.png
          004.png
       

        一、驱动程序


        1.1、驱动测试的设备树文件在/MYIR-i.MX8MM-Linux/arch/arm64/boot/dts/freescale/下面,找到对应开发板的dts文件   myb-fsl-imx8mm-evk.dts   查找有关开发板上有关LED1的设备,厂家已经把LED灯端口都配置好了。
        002.png
        001.png

        1.2、驱动程序源码
        1.2.1、userled.c

    1. #include <linux/types.h>
    2. #include <linux/kernel.h>
    3. #include <linux/delay.h>
    4. #include <linux/ide.h>
    5. #include <linux/init.h>
    6. #include <linux/module.h>
    7. #include <linux/errno.h>
    8. #include <linux/gpio.h>
    9. #include <linux/cdev.h>
    10. #include <linux/device.h>
    11. #include <linux/of.h>
    12. #include <linux/of_address.h>
    13. #include <linux/of_gpio.h>
    14. #include <asm/uaccess.h>
    15. #include <asm/io.h>


    16. #define GPIOLED_CNT                        1                           
    17. #define GPIOLED_NAME                "userled"         
    18. #define LEDOFF                                 0                        
    19. #define LEDON                                 1                        


    20. struct userled_dev{
    21.         dev_t devid;                        
    22.         struct cdev cdev;                 
    23.         struct class *class;         
    24.         struct device *device;
    25.         int major;                                 
    26.         int minor;                                 
    27.         struct device_node        *nd;  
    28.         int led_gpio;                        
    29. };

    30. struct userled_dev userled;         

    31. //led open
    32. static int led_open(struct inode *inode, struct file *filp)
    33. {
    34.         filp->private_data = &userled;
    35.         return 0;
    36. }
    37. //led read
    38. static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
    39. {
    40.         return 0;
    41. }
    42. //led write
    43. static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
    44. {
    45.         int retvalue;
    46.         unsigned char databuf[1];
    47.         unsigned char ledstat;
    48.         struct userled_dev *dev = filp->private_data;

    49.         retvalue = copy_from_user(databuf, buf, cnt);
    50.         if(retvalue < 0)
    51.         {
    52.                 printk("kernel write failed!\r\n");
    53.                 return -EFAULT;
    54.         }

    55.         ledstat = databuf[0];        

    56.         if(ledstat == LEDON)
    57.         {        
    58.                 gpio_set_value(dev->led_gpio, 0);        
    59.         }
    60.         else if(ledstat == LEDOFF)
    61.         {
    62.                 gpio_set_value(dev->led_gpio, 1);        
    63.         }
    64.         return 0;
    65. }
    66. //led release
    67. static int led_release(struct inode *inode, struct file *filp)
    68. {
    69.         return 0;
    70. }
    71. //fops
    72. static struct file_operations userled_fops = {
    73.         .owner = THIS_MODULE,
    74.         .open = led_open,
    75.         .read = led_read,
    76.         .write = led_write,
    77.         .release =         led_release,
    78. };
    79. //led init
    80. static int __init led_init(void)
    81. {
    82.         int ret = 0;

    83.         userled.nd = of_find_node_by_path("/leds/user");
    84.         if(userled.nd == NULL)
    85.         {
    86.                 printk("userled node not find!\r\n");
    87.                 return -EINVAL;
    88.         } else
    89.         {
    90.                 printk("userled node find!\r\n");
    91.         }

    92.         userled.led_gpio = of_get_named_gpio(userled.nd, "gpios", 0);
    93.         if(userled.led_gpio < 0)
    94.         {
    95.                 printk("can't get usergpio");
    96.                 return -EINVAL;
    97.         }

    98.         ret = gpio_direction_output(userled.led_gpio, 1);
    99.         if(ret < 0)
    100.         {
    101.                 printk("can't set usergpio!\r\n");
    102.         }
    103.         if (userled.major)
    104.         {               
    105.                 userled.devid = MKDEV(userled.major, 0);
    106.                 register_chrdev_region(userled.devid, GPIOLED_CNT, GPIOLED_NAME);
    107.         } else
    108.         {                                                
    109.                 alloc_chrdev_region(&userled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);        
    110.                 userled.major = MAJOR(userled.devid);        
    111.                 userled.minor = MINOR(userled.devid);        
    112.         }
    113.         printk("userled major=%d,minor=%d\r\n",userled.major, userled.minor);        
    114.         
    115.         userled.cdev.owner = THIS_MODULE;
    116.         cdev_init(&userled.cdev, &userled_fops);
    117.         cdev_add(&userled.cdev, userled.devid, GPIOLED_CNT);
    118.         userled.class = class_create(THIS_MODULE, GPIOLED_NAME);
    119.         if (IS_ERR(userled.class))
    120.         {
    121.                 return PTR_ERR(userled.class);
    122.         }

    123.         userled.device = device_create(userled.class, NULL, userled.devid, NULL, GPIOLED_NAME);
    124.         if (IS_ERR(userled.device))
    125.         {
    126.                 return PTR_ERR(userled.device);
    127.         }
    128.         return 0;
    129. }

    130. //led exit
    131. static void __exit led_exit(void)
    132. {
    133.         cdev_del(&userled.cdev);
    134.         unregister_chrdev_region(userled.devid, GPIOLED_CNT);  

    135.         device_destroy(userled.class, userled.devid);
    136.         class_destroy(userled.class);
    137. }

    138. module_init(led_init);
    139. module_exit(led_exit);
    140. MODULE_LICENSE("GPL");
    141. MODULE_AUTHOR("author");
    复制代码
       
         1.2.2、Makefile文件

    1. KERNELDIR :=  /opt/04-Sources/MYIR-i.MX8MM-Linux
    2. CURRENT_PATH := $(shell pwd)

    3. obj-m := userled.o

    4. build: kernel_modules

    5. kernel_modules:
    6.         $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules

    7. clean:
    8.         $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
    复制代码

        1.2.3、编译程序


        设置编译环境
        >/opt/04-Sources/example/userled# source /opt/myir-imx-xwayland/4.14-sumo/environment-setup-aarch64-poky-linux
        >/opt/04-Sources/example/userled# LDFLAGS="" CC="$CC"   
        >make
        编译完成后,会生成userled.ko文件,
        005.png


       二、应用程序

        通过应用测试来测试驱动程序的运行情况。

        2.1、userledApp.c

    1. #include <stdio.h>
    2. #include <unistd.h>
    3. #include <sys/types.h>
    4. #include <sys/stat.h>
    5. #include <fcntl.h>
    6. #include <stdlib.h>
    7. #include <string.h>

    8. #define LED_DELAY_US    (200*1000) /* 200 ms */

    9. #define LEDOFF         0
    10. #define LEDON         1

    11. int main(int argc, char *argv[])
    12. {
    13.         int fd, retvalue;
    14.         char *filename;
    15.         unsigned char databuf[1];
    16.         unsigned char databuf1[1];
    17.         
    18.         if(argc != 3){
    19.                 printf("Error Usage!\r\n");
    20.                 return -1;
    21.         }

    22.         filename = argv[1];

    23.         fd = open(filename, O_RDWR);
    24.         if(fd < 0)
    25.         {
    26.                 printf("file %s open failed!\r\n", argv[1]);
    27.                 return -1;
    28.         }

    29.         for(;;)
    30.         {
    31.                 databuf[0] = 0x01;
    32.                 retvalue = write(fd, databuf, sizeof(databuf));
    33.                  usleep(LED_DELAY_US );
    34.                 databuf[0] = 0x00;
    35.                 retvalue = write(fd, databuf, sizeof(databuf));
    36.                 usleep(LED_DELAY_US );
    37.                 printf("LED Control test!\r\n");

    38.         }
    39.         
    40.         retvalue = close(fd);
    41.         if(retvalue < 0)
    42.         {
    43.                 printf("file %s close failed!\r\n", argv[1]);
    44.                 return -1;
    45.         }
    46.         return 0;
    47. }
    复制代码
             
        2.2、Makefile

    1. include ../env.mk
    2. TARGET = userledApp
    3. SRC =  $(TARGET).c
    4. OBJS = $(patsubst %.c ,%.o ,$(SRC))
    5. .PHONY: all
    6. all: $(TARGET)
    7. $(TARGET) : $(OBJS)
    8.         $(CC) -o $@ $^
    9. %.o : %.c
    10.         $(CC) -c [        DISCUZ_CODE_421        ]lt; -o $@
    11. clean:
    12.         $(RM) *.o $(TARGET)
    复制代码
       
        2.3、编译程序
       
        执行make命令生成文件。
        006.png
       
        三、测试程序

        3.1、将上面生成的两个文件复制到开发板上
        007.png


        3.2、加载模块
        008.png
       
        3.3、运行测试程序
        009.png


        3.4、测试结果
        蓝色的LED闪烁运行。


        100.gif
       
         




    回复

    使用道具 举报

    该用户从未签到

    发表于 2021-1-12 09:54:47 | 显示全部楼层
    修改了设备树后,怎么重新替换设备树呢?大佬
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

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

    手机版|小黑屋|与非网

    GMT+8, 2024-4-27 04:06 , Processed in 0.125706 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.