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

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 = ;

led0: user {

label = "user";

gpios = ;

default-state = "off";

};

led1: cpu {

label = "cpu";

gpios = ;

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控制都是选择灌电流。这样逻辑上是反向的,低电平亮,高电平灭。

上图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值