不敲一行代碼,實現Linux下的LED驅動!

前言

如果要實現一個設備的驅動,一行驅動代碼都不用寫,這聽起來是不是天方夜譚呢?

但這并不是不可實現的,因為全世界的內核開發者都非常熱心,只要是能寫的驅動,他們基本都已經寫了。

今天,我們就站在巨人的肩膀上,利用內核開發者已經寫好的驅動來實現我們想要的功能,本篇討論的是LED驅動。

LED驅動

我們以imx6ull pro開發板的板載led為例,其板載了一個可控制的Led2,原理圖如下:

不敲一行代碼,實現Linux下的LED驅動!

LED2進行上拉電阻,另外一個管腳接到了GPIO5_3,因此GPIO5_3輸出低電平即可點亮LED。下面說明如何控制該LED。

內核配置:

?Device?Drivers??---> ??[*]?LED?Support??---> ??????LED?class?Support ??????LED?Support?for?GPIO?connected?LEDs ???[*]???LED?Trigger?support??--->

我們的LED驅動是基于GPIO的,因此需要打開內核LED驅動的支持。

內核有兩個對應的驅動程序,分別是GPIO驅動LED驅動基于GPIO的LED驅動調用了GPIO驅動導出的函數

LED驅動實現代碼請參考:drivers/leds/leds-gpio.c,它實現了一個leds類,通過sysfs接口對LED進行控制。

設備樹:

leds{ ?compatible?=?"gpio-leds"; ? ????????led2{ ????????????label?=?"led2"; ????????????gpios?=?;//GPIO_ACTIVE_LOW,代表低電平點亮LED ????????????default-state?=?"on"; ????????}; }

在設備樹中創建一個名為leds的節點,compatible為”gpio-leds”,這樣可以匹配到leds-gpio.c的驅動。

然后創建一個子節點,名為led2。需要填三個屬性:label、gpios和default-state。

label:lable是出現在sys目錄下的名字,即生成/sys/class/leds/led2

gpios:前兩個值指定了該LED所連接的GPIO。第三個值可填GPIO_ACTIVE_HIGH或GPIO_ACTIVE_LOW。GPIO_ACTIVE_HIGH代表高電平點亮LED,GPIO_ACTIVE_LOW代表低電平點亮LED。

這里注意了,gpios屬性的第三個參數,代表該gpio點亮LED是需要高電平還是低電平,注意是點亮LED,細品

default-state:on代表默認情況LED是點亮的,off代表默認LED熄滅

這里又注意了,當defalut-state為on時,實際上gpio輸出的電平,就是gpios屬性中指定的點亮LED時的電平

設備樹配置好后,編譯并更換dtb,然后重啟開發板。可以看到/sys/class/leds/led2目錄:

不敲一行代碼,實現Linux下的LED驅動!

/sys/class/leds/led2/目錄下有一個brightnes文件,可以通過echo cat的方式查看和修改LED的亮度。因為LED連接在GPIO上,所以亮度只有0和1,在本文示例的led2中,0表示點亮,1表示熄滅。

點亮LED:

echo?0?>?/sys/class/leds/led2/brightness

熄滅LED:

echo?1?>?/sys/class/leds/led2/brightness

應用層控制

除了可以在shell中通過echo、cat的方式控制Led,我們也可以在寫一個應用層程序來操作/sys/class/leds/下的節點,應用層代碼:

#include?<stdio.h> #include?<stdlib.h> #include?<unistd.h> #include?<errno.h> #include?<fcntl.h> #include?<string.h>  #include?<sys> #include?<sys>  #define?LED_DEV_PATH?"/sys/class/leds/led%d/brightness" #define?ON #define?OFF  int?fs4412_set_led(unsigned?int?lednum,?unsigned?int?mode) { ?int?fd; ????int?ret; ????char?devpath[128]; ????char?*on?=?"1n"; ????char?*off?=?"0n"; ????char?*m?=?NULL; ???? ????snprintf(devpath,?sizeof(devpath),?LED_DEV_PATH,?lednum); ????fd?=?open(devpath,?O_WRONLY); ????if?(fd?==?-1)?{ ??perror("fsled-&gt;open"); ????????return?-1; ?} ???? ????if?(mode?==?ON) ?????????m?=?on; ????else ?????????m?=?off; ???? ????ret?=?write(fd,?m,?strlen(m)); ????if?(ret?==?-1)?{ ??perror("fsled-&gt;wrtie"); ????????close(fd); ????????return?-1; ????} ???? ????close(fd); ????return?0;  }  int?main(int?argc,?char?*argv[]) { ?unsigned?int?lednum?=?2; ???? ????while(1){ ??fs4412_set_led(lednum,?on); ????????usleep(500000); ????????fs4412_set_led(lednum,?OFF); ??usleep(500000); ???????? ????????lednum++; ????????if?(lednum?&gt;?5) ?????????????lednum?=?2; ?}  ?return?0; }</sys></sys></string.h></fcntl.h></errno.h></unistd.h></stdlib.h></stdio.h>

上述應用層代碼執行后,led2會閃爍。

? 版權聲明
THE END
喜歡就支持一下吧
點贊11 分享