• imx6ul linux4.1.15 LED驱动配置及heartbeat源码分析【转】


    本文转载自:https://blog.csdn.net/u010444107/article/details/78328807

    1)查看内核配置
    wujun@wj-vBox:~/freescale/linux-imx$ cat arch/arm/configs/imx_v7_defconfig | grep LEDS
    CONFIG_NEW_LEDS=y
    CONFIG_LEDS_CLASS=y
    CONFIG_LEDS_GPIO=y
    CONFIG_LEDS_TRIGGERS=y
    CONFIG_LEDS_TRIGGER_TIMER=y
    CONFIG_LEDS_TRIGGER_ONESHOT=y
    CONFIG_LEDS_TRIGGER_HEARTBEAT=y
    CONFIG_LEDS_TRIGGER_BACKLIGHT=y
    CONFIG_LEDS_TRIGGER_GPIO=y
    已经开启了LED并且使能了几种触发模式:timer oneshot heartbeat backlight gpio

    (2)设备树增加LED相关设定
    wujun@wj-vBox:~/freescale/linux-imx$ vi arch/arm/boot/dts/imx6ul-14x14-evk.dts
    leds {
    compatible = “gpio-leds”;
    pinctrl-names = “default”;
    pinctrl-0 = <&pinctrl_leds>;

    led0: user {
    label = "user";
    gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
    default-state = "off";
    };

    led1: cpu {
    label = "cpu";
    gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
    default-state = "on";
    linux,default-trigger = "heartbeat";
    };
    };
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    pinctrl放在 &iomuxc下
    pinctrl_leds: ledgrp {
    fsl,pins = <
    MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x1b0b0
    MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02 0x1b0b0

    ;
    };

    共设定两个灯,
    一个是GPIO5 IO01 用户灯
    一个是GPIO5 IO02 CPU心跳灯

    (3)查找驱动
    wujun@wj-vBox:~/freescale/linux-imxgrep−rn“gpio−leds”driversdrivers/leds/leds−gpio.c:237:.compatible=“gpio−leds”,,触发方式源码在trigger目录下wujun@wj−vBox: /freescale/linux−imx/drivers/ledsgrep−rn“gpio−leds”driversdrivers/leds/leds−gpio.c:237:.compatible=“gpio−leds”,,触发方式源码在trigger目录下wujun@wj−vBox: /freescale/linux−imx/drivers/leds ls trigger/
    built-in.o ledtrig-cpu.c ledtrig-heartbeat.c ledtrig-timer.o
    Kconfig ledtrig-cpu.o ledtrig-heartbeat.o ledtrig-transient.c
    ledtrig-backlight.c ledtrig-default-on.c ledtrig-ide-disk.c ledtrig-transient.o
    ledtrig-backlight.o ledtrig-default-on.o ledtrig-oneshot.c Makefile
    ledtrig-camera.c ledtrig-gpio.c ledtrig-oneshot.o modules.builtin
    ledtrig-camera.o ledtrig-gpio.o ledtrig-timer.c modules.order
    这些的编译时通过内核配置项来确定的。

    (4)启动系统
    通过查看LED的trigger文件,就能知道当前LED支持的触发器和目前设定的触发器
    root@imx6ulevk:~# cat /sys/class/leds/user/trigger
    [none] rc-feedback nand-disk mmc0 mmc1 timer oneshot heartbeat backlight gpio
    root@imx6ulevk:~# cat /sys/class/leds/cpu/trigger
    none rc-feedback nand-disk mmc0 mmc1 timer oneshot [heartbeat] backlight gpio

    user led没有设定trigger
    cpu led设定为heartbeat trigger

    设置触发器也很简单,使用echo将触发器名称写入trigger文件即可。
    写入的字符串一定是trigger文件已经存在的,否则会提示参数非法。
    这里将user灯也设定为心跳灯。
    root@imx6ulevk:~# echo heartbeat > /sys/class/leds/user/trigger
    此时user灯与cpu灯同时闪烁。不过不是同步的。

    再次查看用户灯的触发方式
    root@imx6ulevk:~# cat /sys/class/leds/user/trigger
    none rc-feedback nand-disk mmc0 mmc1 timer oneshot [heartbeat] backlight gpio
    已经设定成心跳灯了。

    (5)心跳灯控制源码
    因为比较好奇心跳灯闪的频率,查看了驱动源码。
    wujun@wj-vBox:~/freescale/linux-imx/drivers/leds$ vi trigger/ledtrig-heartbeat.c
    找到了控制闪灯时序的代码。

    static void led_heartbeat_function(unsigned long data)
    {
    struct led_classdev led_cdev = (struct led_classdev ) data;
    struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
    unsigned long brightness = LED_OFF;
    unsigned long delay = 0;

    if (unlikely(panic_heartbeats)) {
    led_set_brightness(led_cdev, LED_OFF);
    return;
    }

    /* acts like an actual heart beat -- ie thump-thump-pause... */
    switch (heartbeat_data->phase) {
    case 0:
    /*
    * The hyperbolic function below modifies the
    * heartbeat period length in dependency of the
    * current (1min) load. It goes through the points
    * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
    */
    heartbeat_data->period = 300 +
    (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
    heartbeat_data->period =
    msecs_to_jiffies(heartbeat_data->period);
    delay = msecs_to_jiffies(70);
    heartbeat_data->phase++;
    brightness = led_cdev->max_brightness;
    break;
    case 1:
    delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
    heartbeat_data->phase++;
    break;
    case 2:
    delay = msecs_to_jiffies(70);
    heartbeat_data->phase++;
    brightness = led_cdev->max_brightness;
    break;
    default:
    delay = heartbeat_data->period - heartbeat_data->period / 4 -
    msecs_to_jiffies(70);
    heartbeat_data->phase = 0;
    break;
    }

    led_set_brightness_async(led_cdev, brightness);
    mod_timer(&heartbeat_data->timer, jiffies + delay);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    }

    代码比较简单,不过里面有个细节
    /* acts like an actual heart beat – ie thump-thump-pause… */
    这个意思是说,模拟人的心跳,从这点上看,写这段代码的工程师是具有追求极致的精神。心跳灯都要模拟心跳的频率。
    另外一个点就是周期的计算方法。
    /*
    * The hyperbolic function below modifies the
    * heartbeat period length in dependency of the
    * current (1min) load. It goes through the points
    * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
    */
    heartbeat_data->period = 300 +
    (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
    从代码的意思上看,是根据当前的系统load来决定周期。
    如果系统load是0,周期就是1260,其他类推。
    300 + (6270 << 11) / (5 * 0) + (7 << 11) = 300 + 6270 / 7 = 300 + 960 = 1260;

    其中FSHIFT可以从下面路径找到定义
    wujun@wj-vBox:~/freescale/linux-imx/include/linux$ grep -rn “FSHIFT” .
    ./sched.h:153:#define FSHIFT 11 /* nr of bits of precision */
    这个是因为linux内核避免使用浮点运算所以用整数来计算。

    linux内核定义了unsigned long avenrun[3];三个长整型数据。
    wujun@wj-vBox:~/freescale/linux-imx$ vi ./kernel/sched/proc.c +61
    61 unsigned long avenrun[3];
    在32位的cpu上,long对应的就是32bit,其中低11位用于存放负载的小数部分,高21位用于存放整数部分。
    之所以是三个变量,是因为内核要记录cpu的load有三个变量,分别是1min,5min和15min。
    运行top的时候能够看到这三个变量的值。
    load average: 0.00, 0.02, 0.00

    运行uptime也可以看到
    wujun@wj-vBox:~/freescale/linux-imx$ uptime
    11:44:08 up 21:23, 1 user, load average: 0.00, 0.02, 0.00

    这三个值是从/proc/loadavg中获得的。
    wujun@wj-vBox:~/freescale/linux-imx$ cat /proc/loadavg
    0.00 0.02 0.00 1/167 5038

    得出结论是在cpu load为0的情况下,闪灯周期是1260ms。
    总共闪两次,每次亮70ms,两次亮之间的时间差是周期的1/4.
    也就是在cpu load = 0情况下:
    |70 | |70 |
    | 415ms |
    | 415ms | 415ms | 415ms | 415ms |

    (6)最后用示波器看一下波形是否如预期。
    因为GPIO的驱动能力有限,一般LED控制都是选择灌电流。这样逻辑上是反向的,低电平亮,高电平灭。
    上图

  • 相关阅读:
    Android自动化测试框架UIAutomator原理浅析
    UiAutomator和Appium之间的区别2
    UiAutomator、UiAutomator2、Bootstrap的关系
    好的博客和网站
    appium介绍和工作原理
    UiAutomator1.0 与 UiAutomator2.0
    Jenkins之配置GitHub-Webhook2
    jenkins部署github项目持续集成
    Windows下安装的Jenkins修改默认端口号8080(修改配置文件的方式)
    Git使用教程
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/10182520.html
Copyright © 2020-2023  润新知