Linux内核LED子系统、请务必看
发布日期:2021-06-30 18:45:59 浏览次数:3 分类:技术文章

本文共 4727 字,大约阅读时间需要 15 分钟。

前言

LED子系统你要是说很难嘛,但是它就是控制一些简单的GPIO口,但是你要是说它很简单嘛,但是我也不见得一个初学者很快就能掌握,你如果是刚入门这部分的话,我觉得你还是要去仔细研究下这些驱动。前两天在网上看到一句话,初学者喜欢研究语法,大牛喜欢研究数据结构,Linux下的数据结构非常多,把这些东西搞明白对你非常有帮助。

简单说下LED子系统

  • 应用的话不是很想解释,应用就是调用驱动的接口,打开、关闭、设置等等操作。

  • 核心是为驱动和效果和应用服务的,所以我们很多东西都依赖于核心,所以会有一些基本的数据结构,注册、卸载等函数。

  • 驱动的用法很简单,但是在简单的用法后面蕴藏着巨大的秘密,Linux下的很多驱动都是如此,填充好一些数据结构,然后调用register函数注册,这样之后,就能把驱动注册起来。

  • trigger指的是一种效果,比如亮、灭、是一个效果,驱动里面就做成了default-on的效果,还有闪烁、呼吸等,都是不同的效果。


AW9110 LED驱动芯片

我们分析下这个芯片的硬件连接吧,先分析下硬件有啥特点。

这是一款I2C接口的LED驱动IC,默认的驱动电流大小是37mA,有256个驱动等级,读到这里我们应该可以知道,我们可以用这个IC做呼吸的功能。

看一个驱动的流程理解

我吹几句

我们写程序的时候,需要注意的是在dts里面可以设置什么,这个应该是关键,如果这个是一个LED灯驱动,那么,在dts里面就需要设置LED的属性,比如这个LED灯有什么效果,默认效果是什么。

还有就是要注意led_classdev,因为register注册的时候就是把这个结构体填充的东西给注册起来的。

dts

+       aw9110b: aw9110b@5b {+               compatible = "aw9110b-leds";+               gpio_out_drv = 
;+               shdn-gpio = <&pio 19 GPIO_ACTIVE_HIGH>;+               reg = <0x5b>;+               #address-cells = <1>;+               #size-cells = <0>;+               status = "okay";++               led1: led@1 {+                               label = "led_cam1";+                               reg = <1>;+                               flags = 
;+                               led-max-microamp = <10000>;+                               linux,default-trigger = "default-on";+               };}

led_classdev 结构体

struct led_classdev { const char  *name; enum led_brightness  brightness; enum led_brightness  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)#define LED_BLINK_ONESHOT (1 << 17)#define LED_BLINK_ONESHOT_STOP (1 << 18)#define LED_BLINK_INVERT (1 << 19)#define LED_SYSFS_DISABLE (1 << 20)#define SET_BRIGHTNESS_ASYNC (1 << 21)#define SET_BRIGHTNESS_SYNC (1 << 22)#define LED_DEV_CAP_FLASH (1 << 23) /* Set LED brightness level */ /* Must not sleep, use a workqueue if needed */ void  (*brightness_set)(struct led_classdev *led_cdev,       enum led_brightness brightness); /*  * Set LED brightness level immediately - it can block the caller for  * the time required for accessing a LED device register.  */ int  (*brightness_set_sync)(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 milliseconds  * and if both are zero then a sensible default should be chosen.  * The call should adjust the timings in that case and if it can't  * match the values specified exactly.  * Deactivate blinking again when the brightness is set to a fixed  * value via the brightness_set() callback.  */ int  (*blink_set)(struct led_classdev *led_cdev,         unsigned long *delay_on,         unsigned long *delay_off); struct device  *dev; const struct attribute_group **groups; struct list_head  node;   /* LED Device list */ const char  *default_trigger; /* Trigger to use */ unsigned long   blink_delay_on, blink_delay_off; struct timer_list  blink_timer; int    blink_brightness; void   (*flash_resume)(struct led_classdev *led_cdev); struct work_struct set_brightness_work; int   delayed_set_value;#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; /* true if activated - deactivate routine uses it to do cleanup */ bool   activated;#endif /* Ensures consistent access to the LED Flash Class device */ struct mutex  led_access;};


LED trigger 的理解

我这里打开的是呼吸的trigger,这个trigger是用来实现呼吸效果的,但是我们这个IC没有自主呼吸的功能,所以我们需要实现呼吸的话,肯定是离不开定时器的,我们使用一个定时器在一个时间段内不断的改变输出的电流,以此来改变输出的亮度。这样让用户就看到呼吸的效果了。

我简单的说下这个呼吸曲线,因为人眼对亮度的观察并不是线性的,举个例子,理想的做法是,我们的曲线在一个时间内递增一样大小的电流,这样输出看到的亮度也是曲线增加的,但是因为我们人眼对亮度观察并不是理想的,所以我们可能看到的是突然变亮,变灭的过程也会极其尴尬。

赠送一段不健全的呼吸曲线

static const uint8_t s_breath_effect[] = {    0, 0, 0, 0, 1, 2, 3, 4, 6, 8,    10, 12, 14, 16, 19, 22, 25, 28, 32, 36,    40, 44, 48, 52, 57, 62, 67, 72, 78, 84,    90, 96, 102, 108, 115, 122, 129, 136, 144, 152,    160, 168, 176, 184, 193, 202, 211, 220, 230, 240,    250, 240, 230, 220, 211, 202, 193, 184, 176, 168,    160, 152, 144, 136, 129, 122, 115, 108, 102, 96,    90, 84, 78, 72, 67, 62, 57, 52, 48, 44,    40, 36, 32, 28, 25, 22, 19, 16, 14, 12,    10, 8, 6, 4, 3, 2, 1, 0, 0, 0,};

LED sys节点

节点

android:/sys/class/leds # lsblue          led_cam_b led_key1 

属性

android:/sys/class/leds/led_key1 # lsbrightness device max_brightness power subsystem trigger uevent

trigger

android:/sys/class/leds/led_key1 # cat trigger[none] rc-feedback nand-disk mmc0 timer oneshot heartbeat breath

  推荐阅读:

嵌入式Linux

微信扫描二维码,关注我的公众号

转载地址:https://linus.blog.csdn.net/article/details/107293508 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:多线程的使用
下一篇:SensorKernel层框架分析

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月29日 22时32分41秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

tensorflow使用tensorboard进行可视化 2019-04-30
神经网络调参实战(二)—— activation & initializer & optimizer 2019-04-30
凸优化 convex optimization 2019-04-30
数据库索引 & 为什么要对数据库建立索引 / 数据库建立索引为什么会加快查询速度 2019-04-30
IEEE与APA引用格式 2019-04-30
research gap 2019-04-30
pytorch训练cifar10数据集查看各个种类图片的准确率 2019-04-30
Python鼠标点击图片,获取点击点的像素坐标 2019-04-30
路径规划(一) —— 环境描述(Grid Map & Feature Map) & 全局路径规划(最优路径规划(Dijkstra&A*star) & 概率路径规划(PRM&RRT)) 2019-04-30
神经网络调参实战(四)—— 加深网络层次 & 批归一化 batch normalization 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(1)—— 假设检验(μ&卡方检验&方差检验(F检验))&相关系数(皮尔逊&斯皮尔曼) 2019-04-30
RRT算法(快速拓展随机树)的Python实现 2019-04-30
路径规划(二) —— 轨迹优化(样条法) & 局部规划(人工势能场法) & 智能路径规划(生物启发(蚁群&RVO) & 强化学习) 2019-04-30
D*算法 2019-04-30
强化学习(四) —— Actor-Critic演员评论家 & code 2019-04-30
RESTful API 2019-04-30
优化算法(四)——粒子群优化算法(PSO) 2019-04-30
数据挖掘与数据分析(三)—— 探索性数据分析EDA(多因子与复合分析) & 可视化(2)——回归分析(最小二乘法&决定系数&残差不相关)&主成分分析&奇异值分解 2019-04-30
数据在Oracle中的存储 2019-04-30
优化算法(五)—人工蜂群算法Artificial Bee Colony Algorithm(ABC) 2019-04-30