基于RK3399Pro的LED驱动开发

您所在的位置:网站首页 安卓底层驱动开发教程 基于RK3399Pro的LED驱动开发

基于RK3399Pro的LED驱动开发

2024-07-07 16:27| 来源: 网络整理| 查看: 265

目录

原理图

添加设备树

编写驱动程序

设备节点

文件入口函数

杂项设备

文件操作集

控制函数

完整驱动代码

测试代码

Makefile文件

测试步骤

编译源码

加载驱动

执行测试程序

实验现象

原理图

发光二极管与普通二极管一样是由一个PN结组成,也具有单向导电性。当给发光二极管加上正向电压后,从P区注入到N区的空穴和由N区注入到P区的电子,在PN结附近数微米内分别与N区的电子和P区的空穴复合,产生自发辐射的荧光。

问题1:如何判断正负极?

尺寸大的LED 在极片引脚附近做有一些标记,如切角、涂色、或引脚大小不一样,一般有标志的、引脚小的、短的 一边是阴极(即负极),尺寸小的0805、0603封装的在底部有“T”字形 或 倒三角形符号“T”字一横的一边是正极; 三角形符号的“边”靠近的极性正,“角”靠近的是负极。

添加设备树

在设备树

arch/arm64/boot/dts/rockchip/rk3399pro-toybrick-prop-linux.dts

中添加

gpio-led{ status = "okay"; compatible = "gpio-led"; gpio-led1 = ; gpio-led2 = ; }; 编写驱动程序 设备节点 static const struct of_device_id of_gec_leder_match[] = { { .compatible = "gpio-led", }, //compatible 兼容属性名,需与设备树节点的属性一致 {}, }; ​ static struct platform_driver gec3399_led_driver = { ​ .driver = { .name ="gpio-led", .owner = THIS_MODULE, .of_match_table = of_gec_leder_match, //设备树设备匹配 }, .probe = gec3399_led_probe, //驱动探测 .remove = gec3399_led_remove, //驱动移除 }; ​ 文件入口函数 static int gec3399_led_probe(struct platform_device *pdev) { int ret; struct device_node *led_node = pdev->dev.of_node; //第一步:获取GPIO引脚号 gpio_led1 = of_get_named_gpio(led_node,"gpio-led1", 0); //从设备树获取GPIO号 if (!gpio_is_valid(gpio_led1)) { printk("gpio-led1: %d is invalid\n",gpio_led1); ret = -ENODEV; goto err_get_gpio1; } printk("gpio-led1 = %d\n",gpio_led1); gpio_led2 = of_get_named_gpio(led_node,"gpio-led2", 0); //从设备树获取GPIO号 if (!gpio_is_valid(gpio_led2)) { printk("gpio-led2: %d is invalid\n",gpio_led2); ret = -ENODEV; goto err_get_gpio1; } printk("gpio-led2 = %d\n",gpio_led2); //第二步:申请GPIO引脚 gpio_free(gpio_led1); ret = gpio_request(gpio_led1,"GPIO_LED1"); //申请gpio_led引脚为GPIO模式 if(ret < 0){ printk("gpio_request gpio = GPIO_LED1 error\n"); goto err_get_gpio1; } gpio_free(gpio_led2); ret = gpio_request(gpio_led2,"GPIO_LED2"); //申请gpio_led引脚为GPIO模式 if(ret < 0){ printk("gpio_request gpio = GPIO_LED1 error\n"); goto err_get_gpio2; } //第三步:设置LED引脚的初始化电平 ret = gpio_direction_output(gpio_led1,0); //初始化LED1为关闭状态 if(ret < 0){ printk("gpio direction input gpio = LED1 error\n"); goto err_gpio_direction; } ret = gpio_direction_output(gpio_led2,0); //初始化LED2为关闭状态 if(ret < 0){ printk("gpio direction input gpio = LED2 error\n"); goto err_gpio_direction; } //第四步:通过杂项设备注册LED灯 ret = misc_register(&gec3399_led_misc); //注册字符设备 if(ret < 0){ printk("misc register error\n"); goto err_misc_register; } printk( KERN_ALERT "led dirve install succee\n"); return 0; err_misc_register: err_gpio_direction: gpio_free(gpio_led2); err_get_gpio2: gpio_free(gpio_led1); err_get_gpio1: return ret; } 杂项设备 static struct miscdevice gec3399_led_misc = { .minor = MISC_DYNAMIC_MINOR, .fops = &gec3399_led_fops, .name = "led_drv", }; //混杂设备结构体定义和初始化 文件操作集 static struct miscdevice gec3399_led_misc = { .minor = MISC_DYNAMIC_MINOR, .fops = &gec3399_led_fops, .name = "led_drv", }; //混杂设备结构体定义和初始化 控制函数 static long gec3399_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case LED_ON: gpio_set_value(gpio_led1,1); gpio_set_value(gpio_led2,1); break; case LED_OFF: gpio_set_value(gpio_led1,0); gpio_set_value(gpio_led2,0); break; } return 0; } ​ 完整驱动代码 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ​ #define LED_ON _IO('B',0) #define LED_OFF _IO('B',1) ​ int gpio_led1,gpio_led2; ​ ​ static long gec3399_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { switch(cmd) { case LED_ON: gpio_set_value(gpio_led1,1); gpio_set_value(gpio_led2,1); break; case LED_OFF: gpio_set_value(gpio_led1,0); gpio_set_value(gpio_led2,0); break; } return 0; } ​ static int gec3399_led_release(struct inode *inode, struct file *file) { gpio_set_value(gpio_led1,0); //应用程序退出时,关闭蜂鸣器 gpio_set_value(gpio_led2,0); //应用程序退出时,关闭蜂鸣器 return 0; } ​ static const struct file_operations gec3399_led_fops = { .owner = THIS_MODULE, .unlocked_ioctl = gec3399_led_ioctl, .release = gec3399_led_release, }; //文件操作集结构体 ​ ​ static struct miscdevice gec3399_led_misc = { .minor = MISC_DYNAMIC_MINOR, .fops = &gec3399_led_fops, .name = "led_drv", }; //混杂设备结构体定义和初始化 ​ ​ ​ static int gec3399_led_probe(struct platform_device *pdev) { int ret; struct device_node *led_node = pdev->dev.of_node; //enum of_gpio_flags flag; printk(KERN_ALERT"gpio-led math succee\n"); ​ gpio_led1 = of_get_named_gpio(led_node,"gpio-led1", 0); //从设备树获取GPIO号 if (!gpio_is_valid(gpio_led1)) { printk("gpio-led1: %d is invalid\n",gpio_led1); ret = -ENODEV; goto err_get_gpio1; } printk("gpio-led1 = %d\n",gpio_led1); gpio_led2 = of_get_named_gpio(led_node,"gpio-led2", 0); //从设备树获取GPIO号 if (!gpio_is_valid(gpio_led2)) { printk("gpio-led2: %d is invalid\n",gpio_led2); ret = -ENODEV; goto err_get_gpio1; } printk("gpio-led2 = %d\n",gpio_led2); gpio_free(gpio_led1); ret = gpio_request(gpio_led1,"GPIO_LED1"); //申请gpio_led引脚为GPIO模式 if(ret < 0){ printk("gpio_request gpio = GPIO_LED1 error\n"); goto err_get_gpio1; } gpio_free(gpio_led2); ret = gpio_request(gpio_led2,"GPIO_LED2"); //申请gpio_led引脚为GPIO模式 if(ret < 0){ printk("gpio_request gpio = GPIO_LED1 error\n"); goto err_get_gpio2; } ret = gpio_direction_output(gpio_led1,0); //初始化LED1为关闭状态 if(ret < 0){ printk("gpio direction input gpio = ak8963c_DYDR error\n"); goto err_gpio_direction; } ret = gpio_direction_output(gpio_led2,0); //初始化LED2为关闭状态 if(ret < 0){ printk("gpio direction input gpio = ak8963c_DYDR error\n"); goto err_gpio_direction; } ​ ret = misc_register(&gec3399_led_misc); //注册字符设备 if(ret < 0){ printk("misc register error\n"); goto err_misc_register; } printk( KERN_ALERT "led dirve install succee\n"); return 0; err_misc_register: err_gpio_direction: gpio_free(gpio_led2); err_get_gpio2: gpio_free(gpio_led1); err_get_gpio1: return ret; } ​ ​ static int gec3399_led_remove(struct platform_device *pdev) { gpio_free(gpio_led1); gpio_free(gpio_led2); misc_deregister(&gec3399_led_misc); printk(KERN_ALERT "led dirve rmove succee\n"); return 0; } ​ ​ static const struct of_device_id of_gec_leder_match[] = { { .compatible = "gpio-led", }, //compatible 兼容属性名,需与设备树节点的属性一致 {}, }; ​ static struct platform_driver gec3399_led_driver = { ​ .driver = { .name ="gpio-led", .owner = THIS_MODULE, .of_match_table = of_gec_leder_match, //设备树设备匹配 }, .probe = gec3399_led_probe, //驱动探测 .remove = gec3399_led_remove, //驱动移除 }; ​ module_platform_driver(gec3399_led_driver); ​ //module的描述,不是必需的。#modinfo led_drv.ko MODULE_DESCRIPTION("led driver for RK3399"); MODULE_LICENSE("GPL"); //符合GPL协议 MODULE_VERSION("V1.0"); 测试代码

测试代码主要实现LED的闪烁功能

#include #include #include #include #include #include #include ​ //宏定义 #define LED_ON _IO('B',0) #define LED_OFF _IO('B',1) ​ int main(void) { int fd_led; int ret; //第一步:打开设备节点 fd_led = open("/dev/led_drv", O_WRONLY); if(fd_led < 0) { perror("open led driver"); return -1; } while(1) { //第二步:点亮LED灯 ret = ioctl(fd_led,LED_ON); if(ret < 0) perror("write led driver "); sleep(1); //第三步:关闭LED灯 ret = ioctl(fd_led,LED_OFF); if(ret < 0 ) perror("write led driver "); sleep(1); } //第四步:关闭设备节点 close(fd_led); return 0; } Makefile文件 obj-m += led_drv.o KERNELDIR:=/file/RK3399Pro/rk3399pro_git_repo/kernel PWD:=$(shell pwd) ​ default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules test: aarch64-linux-gnu-gcc led_test.c -o led_test ​ clean: rm -rf *.o *.order .*.cmd *.ko *.mod.c *.symvers *.tmp_versions led_test

测试步骤 编译源码

在ubuntu中输入:

make

得到驱动目标文件led_drv.ko

输入:

make test

得到测试目标文件:led_test

加载驱动

在开发板命令终端输入:

insmod led_drv.ko 执行测试程序

在开发板命令终端输入:

chmod 777 led_test ./led_test

实验现象

实现LED的闪烁



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3