i.MX283开发板——LED子系统

Vicki ·
更新时间:2024-11-13
· 805 次阅读

前面的文章有讲过LED字符设备驱动,用户可以open “/dev/xxxLED”驱动文件,通过write或者ioctl接口去访问LED设备,实际

上,在Linux中,控制LED还有一种简便的方式,它不需要用户写程序,用户通过几个指令就可以控制,而且功能十分强大。这

就是本文接下来要讲的LED子系统。

LED 子系统的可以分为三部分:触发器、LED 设备和核心模块,如下图所示:

LED核心模块:管理LED设备和触发器,并为LED设备和触发器提供注册和注销接口。 LED设备:具体的设备,需要提供LED的控制接口。 触发器:LED触发方式,内核提供了none、mmc、nand-disk、heartbeat、timer等触发方式,none表示无触发,mmc表示插入SD卡时会触发LED这些触发器可在配置内核时开启。 属性文件:LED 类会为每个挂在它下面的LED设备自动创建属性文件,用户操作这些属性文件就可以控制LED。

LED子系统框架以及与用户层对应关系如下图所示:

LED子系统的代码位于内核源码/driver/leds文件夹下,其中:

led-class.c:是LED子系统的核心代码,其作用有两个:

维护 LED 子系统的所有触发器,为触发器的注册/注销提供操作函数; 维护 LED 子系统的所有 LED 设备,并为每个 LED 设备在/sys/class/leds/目录下实现操作接口;为 LED 设备的注册/注销提供操作函数。

 ledtrig-*.c:触发器的代码,例如 ledtrig-heartbeat.c 文件是心跳触发器的代码文件。这些触发器的代码文件的主要任务是初始化各自的触发器,然后注册到核心模块。

LED子系统还有个非常重要的结构体struct led_classdev:

struct led_classdev { const char *name; int brightness; int max_brightness; int flags; /* Lower 16 bits reflect status */ #define LED_SUSPENDED (1 << 0) /* Upper 16 bits reflect control information */ #define LED_CORE_SUSPENDRESUME (1 << 16) /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ void (*brightness_set)(struct led_classdev *led_cdev, enum led_brightness brightness); /* Get LED brightness level */ enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); /* Activate hardware accelerated blink, delays are in * miliseconds and if none is provided then a sensible default * should be chosen. The call can adjust the timings if it can't * match the values specified exactly. */ int (*blink_set)(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off); struct device *dev; struct list_head node; /* LED Device list */ const char *default_trigger; /* Trigger to use */ #ifdef CONFIG_LEDS_TRIGGERS /* Protects the trigger data below */ struct rw_semaphore trigger_lock; struct led_trigger *trigger; struct list_head trig_list; void *trigger_data; #endif };

我们就是通过这个结构体描述一个具体的LED设备,然后利用led-class.c中提供的注册方法,把LED设备注册到内核中去。

下图是led_classdev结构体主要成员功能说明:

LED设备子系统的调用流程如下:

注意:上图提到的show、store、brightness_set和brightness_get都是函数指针,其中show和store方法在led-class中已经

实现,它们最终调用的都是brightness_get或者brightness_set方法,这两个函数需要我们根据硬件去实现。

下面就开始编写一个LED设备,具体步骤如下:

根据硬件实现brightness_setbrightness_get方法; 定义一个led_classdev结构体,并填充主要成员; 编写init函数,注册LED设备; 编写exit函数,注销设备。

led_subsystem.c:

#include #include #include #include #include #include #include #include #include #include #define LED_GPIO MXS_PIN_TO_GPIO(PINID_LCD_D23) void mybrightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { gpio_direction_output(LED_GPIO, !brightness); } static struct led_classdev myled_dev = { .name = "myled", .brightness_set = mybrightness_set, .max_brightness = LED_FULL, .default_trigger = "none", //触发器设置无 }; static int __init led_subsys_init(void) { int ret; ret = led_classdev_register(NULL,&myled_dev); if(ret < 0) { printk("led_classdev_register error %d \n",ret); return ret; } gpio_free(LED_GPIO); ret = gpio_request(LED_GPIO,"LED"); if(ret < 0) { printk("gpio_request error %d \n",ret); led_classdev_unregister(&myled_dev); return ret; } return 0; } static void __exit led_subsys_exit(void) { gpio_free(LED_GPIO); led_classdev_unregister(&myled_dev); } module_init(led_subsys_init); module_exit(led_subsys_exit); MODULE_AUTHOR("xzx2020"); MODULE_DESCRIPTION("led subsystem test"); MODULE_LICENSE("GPL");

由于开发板上的led是直接接IO口的,LED的状态也只有亮和不亮两种状态,所以也就不存在设置亮度和获取亮度这一说,brightness_get不需要实现,brightness_set控制IO口拉低或者拉高即可,而且这里没有设置任何触发器。

将led_subsystem.c编译成.ko文件,在开发板上加载mod。

加载成功后,/sys/class/leds下面应该有我们刚刚添加的led设备,名字就是上面结构体的name字段——“myled”,进入myled目录下:

echo 1 > brightness //点亮LED echo 0 > brightness //熄灭LED cat brightness //查看亮度值 cat max_brightness //查看最大亮度 cat trigger //查看触发器

上面的例子是没有使用触发器的,下面就讲下触发器的使用。

1.首先需要配置内核,开启相关触发器。

make menuconfig ------> Device Drivers ------->LED support ---------> LED Triggers

开启LED Timer Trigger 和 LED Heartbeat Trigger

  ↵

2.为我们的LED添加触发器

方法一:修改led_classdev 结构体中default_trigger 字段,可选配置为“timer” 、“heartbeat”。 static struct led_classdev myled_dev = { .name = "myled", .brightness_set = mybrightness_set, .max_brightness = LED_FULL, .default_trigger = "none", //触发器设置无 }; 方法二:用户层通过trigger属性修改 echo heartbeat > trigger //系统心跳触发 echo timer > trigger //定时器来控制闪烁 echo mmc > trigger //SD卡触发

如果选择timer触发,也就是通过软件定时器控制LED,myled下会生成delay_on和delay_off两个文件,分别表示LED亮和灭的

时间,单位是毫秒。可以通过 echo 指令向这两个文件写入时间值来控制LED闪烁。但是如果实现了led_classdev 结构体中

blink_set函数时,就会执行blink_set函数控制LED闪烁。

 参考文档和一些写的比较好的LED子系统的帖子:

1.周立功LED 子系统驱动简介

2.(linux)LED子系统


作者:Ruler.



mx2 系统 mx

需要 登录 后方可回复, 如果你还没有账号请 注册新账号