Linux LCD 驱动实验
目錄
- Linux 下LCD 驅(qū)動(dòng)簡析
- 1 Framebuffer 設(shè)備
- LCD 驅(qū)動(dòng)簡析
- 硬件原理圖分析
- LCD 驅(qū)動(dòng)程序編寫
- 運(yùn)行測試
- LCD 屏幕基本測試
- 設(shè)置LCD 作為終端控制臺(tái)
- LCD 背光調(diào)節(jié)
- 從LCD自動(dòng)關(guān)閉解決方法
LCD 是很常用的一個(gè)外設(shè),在裸機(jī)篇中我們講解了如何編寫LCD 裸機(jī)驅(qū)動(dòng),在Linux 下LCD 的使用更加廣泛,在搭配QT 這樣的GUI 庫下可以制作出非常精美的UI 界面。本章我們就來學(xué)習(xí)一下如何在Linux 下驅(qū)動(dòng)LCD 屏幕。
Linux 下LCD 驅(qū)動(dòng)簡析
1 Framebuffer 設(shè)備
先來回顧一下裸機(jī)的時(shí)候LCD 驅(qū)動(dòng)是怎么編寫的,裸機(jī)LCD 驅(qū)動(dòng)編寫流程如下:
①、初始化I.MX6U 的eLCDIF 控制器,重點(diǎn)是LCD 屏幕寬(width)、高(height)、hspw、hbp、hfp、vspw、vbp 和vfp 等信息。
②、初始化LCD 像素時(shí)鐘。
③、設(shè)置RGBLCD 顯存。
④、應(yīng)用程序直接通過操作顯存來操作LCD,實(shí)現(xiàn)在LCD 上顯示字符、圖片等信息。
在Linux 中應(yīng)用程序最終也是通過操作RGB LCD 的顯存來實(shí)現(xiàn)在LCD 上顯示字符、圖片等信息。在裸機(jī)中我們可以隨意的分配顯存,但是在Linux 系統(tǒng)中內(nèi)存的管理很嚴(yán)格,顯存是需要申請(qǐng)的,不是你想用就能用的。而且因?yàn)樘摂M內(nèi)存的存在,驅(qū)動(dòng)程序設(shè)置的顯存和應(yīng)用程序訪問的顯存要是同一片物理內(nèi)存。
為了解決上述問題,Framebuffer 誕生了,Framebuffer 翻譯過來就是幀緩沖,簡稱fb,因此大家在以后的Linux 學(xué)習(xí)中見到“Framebuffer”或者“fb”的話第一反應(yīng)應(yīng)該想到RGBLCD或者顯示設(shè)備。fb 是一種機(jī)制,將系統(tǒng)中所有跟顯示有關(guān)的硬件以及軟件集合起來,虛擬出一個(gè)fb 設(shè)備,當(dāng)我們編寫好LCD 驅(qū)動(dòng)以后會(huì)生成一個(gè)名為/dev/fbX(X=0~n)的設(shè)備,應(yīng)用程序通過訪問/dev/fbX 這個(gè)設(shè)備就可以訪問LCD。NXP 官方的Linux 內(nèi)核默認(rèn)已經(jīng)開啟了LCD 驅(qū)動(dòng),因此我們是可以看到/dev/fb0 這樣一個(gè)設(shè)備,如圖59.1.1.1 所示:
圖59.1.1.1 中的/dev/fb0 就是LCD 對(duì)應(yīng)的設(shè)備文件,/dev/fb0 是個(gè)字符設(shè)備,因此肯定有file_operations 操作集,fb 的file_operations 操作集定義在drivers/video/fbdev/core/fbmem.c 文件中,如下所示:
關(guān)于fb 的詳細(xì)處理過程就不去深究了,本章我們的重點(diǎn)是驅(qū)動(dòng)起來ALPHA 開發(fā)板上的LCD。
LCD 驅(qū)動(dòng)簡析
LCD 裸機(jī)例程主要分兩部分:
①、獲取LCD 的屏幕參數(shù)。
②、根據(jù)屏幕參數(shù)信息來初始化eLCDIF 接口控制器。
不同分辨率的LCD 屏幕其eLCDIF 控制器驅(qū)動(dòng)代碼都是一樣的,只需要修改好對(duì)應(yīng)的屏幕參數(shù)即可。屏幕參數(shù)信息屬于屏幕設(shè)備信息內(nèi)容,這些肯定是要放到設(shè)備樹中的,因此我們本章實(shí)驗(yàn)的主要工作就是修改設(shè)備樹,NXP 官方的設(shè)備樹已經(jīng)添加了LCD 設(shè)備節(jié)點(diǎn),只是此節(jié)點(diǎn)的LCD 屏幕信息是針對(duì)NXP 官方EVK 開發(fā)板所使用的4.3 寸480*272 編寫的,我們需要將其改為我們所使用的屏幕參數(shù)。
我們簡單看一下NXP 官方編寫的Linux 下的LCD 驅(qū)動(dòng),打開imx6ull.dtsi,然后找到lcdif節(jié)點(diǎn)內(nèi)容,如下所示:
1 lcdif: lcdif@021c8000 { 2 compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif"; 3 reg = <0x021c8000 0x4000>; 4 interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; 5 clocks = <&clks IMX6UL_CLK_LCDIF_PIX>, 6 <&clks IMX6UL_CLK_LCDIF_APB>, 7 <&clks IMX6UL_CLK_DUMMY>; 8 clock-names = "pix", "axi", "disp_axi"; 9 status = "disabled"; 10 };示例代碼59.1.2.1 中的lcdif 節(jié)點(diǎn)信息是所有使用I.MX6ULL 芯片的板子所共有的,并不是完整的lcdif 節(jié)點(diǎn)信息。像屏幕參數(shù)這些需要根據(jù)不同的硬件平臺(tái)去添加,比如向imx6ull-alientek-emmc.dts 中的lcdif 節(jié)點(diǎn)添加其他的屬性信息。從示例代碼59.1.2.1 可以看出lcdif 節(jié)點(diǎn)的compatible 屬性值為“fsl,imx6ul-lcdif”和“fsl,imx28-lcdif”,因此在Linux 源碼中搜索這兩個(gè)
字符串即可找到I.MX6ULL 的LCD 驅(qū)動(dòng)文件,這個(gè)文件為drivers/video/fbdev/mxsfb.c,mxsfb.c就是I.MX6ULL 的LCD 驅(qū)動(dòng)文件,在此文件中找到如下內(nèi)容:
從示例代碼59.1.2.2 可以看出,這是一個(gè)標(biāo)準(zhǔn)的platform 驅(qū)動(dòng),當(dāng)驅(qū)動(dòng)和設(shè)備匹配以后mxsfb_probe 函數(shù)就會(huì)執(zhí)行。在看mxsfb_probe 函數(shù)之前我們先簡單了解一下Linux 下Framebuffer 驅(qū)動(dòng)的編寫流程,Linux 內(nèi)核將所有的Framebuffer 抽象為一個(gè)叫做fb_info 的結(jié)構(gòu)體,fb_info 結(jié)構(gòu)體包含了Framebuffer 設(shè)備的完整屬性和操作集合,因此每一個(gè)Framebuffer 設(shè)
備都必須有一個(gè)fb_info。換言之就是,LCD 的驅(qū)動(dòng)就是構(gòu)建fb_info,并且向系統(tǒng)注冊(cè)fb_info的過程。fb_info 結(jié)構(gòu)體定義在include/linux/fb.h 文件里面,內(nèi)容如下(省略掉條件編譯):
fb_info 結(jié)構(gòu)體的成員變量很多,我們重點(diǎn)關(guān)注var、fix、fbops、screen_base、screen_size和pseudo_palette。mxsfb_probe 函數(shù)的主要工作內(nèi)容為:
①、申請(qǐng)fb_info。
②、初始化fb_info 結(jié)構(gòu)體中的各個(gè)成員變量。
③、初始化eLCDIF 控制器。
④、使用register_framebuffer 函數(shù)向Linux 內(nèi)核注冊(cè)初始化好的fb_info。register_framebuffer函數(shù)原型如下:
函數(shù)參數(shù)和返回值含義如下:
fb_info:需要上報(bào)的fb_info。
返回值:0,成功;負(fù)值,失敗。
接下來我們簡單看一下mxsfb_probe 函數(shù),函數(shù)內(nèi)容如下(有縮減):
第1374 行,host 結(jié)構(gòu)體指針變量,表示I.MX6ULL 的LCD 的主控接口,mxsfb_info 結(jié)構(gòu)體是NXP 定義的針對(duì)I.MX 系列SOC 的Framebuffer 設(shè)備結(jié)構(gòu)體。也就是我們前面一直說的設(shè)備結(jié)構(gòu)體,此結(jié)構(gòu)體包含了I.MX 系列SOC 的Framebuffer 設(shè)備詳細(xì)信息,比如時(shí)鐘、eLCDIF控制器寄存器基地址、fb_info 等。
第1395 行,從設(shè)備樹中獲取eLCDIF 接口控制器的寄存器首地址,設(shè)備樹中l(wèi)cdif 節(jié)點(diǎn)已經(jīng)設(shè)置了eLCDIF 寄存器首地址為0X021C8000,因此res=0X021C8000。
第1401 行,給host 申請(qǐng)內(nèi)存,host 為mxsfb_info 類型結(jié)構(gòu)體指針。
第1407 行,給fb_info 申請(qǐng)內(nèi)存,也就是申請(qǐng)fb_info。
第1413~1414 行,設(shè)置host 的fb_info 成員變量為fb_info,設(shè)置fb_info 的par 成員變量為host。通過這一步就將前面申請(qǐng)的host 和fb_info 聯(lián)系在了一起。
第1416 行,申請(qǐng)中斷,中斷服務(wù)函數(shù)為mxsfb_irq_handler。
第1425 行,對(duì)從設(shè)備樹中獲取到的寄存器首地址(res)進(jìn)行內(nèi)存映射,得到虛擬地址,并保存到host 的base 成員變量。因此通過訪問host 的base 成員即可訪問I.MX6ULL 的整個(gè)eLCDIF寄存器。其實(shí)在mxsfb.c 中已經(jīng)定義了eLCDIF 各個(gè)寄存器相比于基地址的偏移值,如下所示:
大家可以對(duì)比著《I.MX6ULL 參考手冊(cè)》中的eLCDIF 章節(jié)檢查一下示例代碼59.1.2.4 中的這些寄存器有沒有錯(cuò)誤。
繼續(xù)回到示例代碼59.1.2.5 中的mxsfb_probe 函數(shù),第1462 行,給fb_info 中的pseudo_palette申請(qǐng)內(nèi)存。
第1473 行,調(diào)用mxsfb_init_fbinfo 函數(shù)初始化fb_info,重點(diǎn)是fb_info 的var、fix、fbops,screen_base 和screen_size。其中fbops 是Framebuffer 設(shè)備的操作集,NXP 提供的fbops 為mxsfb_ops,內(nèi)容如下:
987 static struct fb_ops mxsfb_ops = { 988 .owner = THIS_MODULE, 989 .fb_check_var = mxsfb_check_var, 990 .fb_set_par = mxsfb_set_par, 991 .fb_setcolreg = mxsfb_setcolreg, 992 .fb_ioctl = mxsfb_ioctl, 993 .fb_blank = mxsfb_blank, 994 .fb_pan_display = mxsfb_pan_display, 995 .fb_mmap = mxsfb_mmap, 996 .fb_fillrect = cfb_fillrect, 997 .fb_copyarea = cfb_copyarea, 998 .fb_imageblit = cfb_imageblit, 999 };關(guān)于mxsfb_ops 里面的各個(gè)操作函數(shù)這里就不去詳解的介紹了。mxsfb_init_fbinfo 函數(shù)通過調(diào)用mxsfb_init_fbinfo_dt 函數(shù)從設(shè)備樹中獲取到LCD 的各個(gè)參數(shù)信息。最后,mxsfb_init_fbinfo函數(shù)會(huì)調(diào)用mxsfb_map_videomem 函數(shù)申請(qǐng)LCD 的幀緩沖內(nèi)存(也就是顯存)。
第1489~1490 行,設(shè)置eLCDIF 控制器的相應(yīng)寄存器。
第1494 行,最后調(diào)用register_framebuffer 函數(shù)向Linux 內(nèi)核注冊(cè)fb_info。
mxsfb.c 文件很大,還有一些其他的重要函數(shù),比如mxsfb_remove、mxsfb_shutdown 等,這里我們就簡單的介紹了一下mxsfb_probe 函數(shù),至于其他的函數(shù)大家自行查閱。
硬件原理圖分析
本章實(shí)驗(yàn)硬件原理圖參考24.2 小節(jié)即可。
LCD 驅(qū)動(dòng)程序編寫
前面已經(jīng)說了,6ULL 的eLCDIF 接口驅(qū)動(dòng)程序NXP 已經(jīng)編寫好了,因此LCD 驅(qū)動(dòng)部分我們不需要去修改。我們需要做的就是按照所使用的LCD 來修改設(shè)備樹。重點(diǎn)要注意三個(gè)地方:
①、LCD 所使用的IO 配置。
②、LCD 屏幕節(jié)點(diǎn)修改,修改相應(yīng)的屬性值,換成我們所使用的LCD 屏幕參數(shù)。
③、LCD 背光節(jié)點(diǎn)信息修改,要根據(jù)實(shí)際所使用的背光IO 來修改相應(yīng)的設(shè)備節(jié)點(diǎn)信息。
接下來我們依次來看一下上面這兩個(gè)節(jié)點(diǎn)改如何去修改:
1、LCD 屏幕IO 配置
首先要檢查一下設(shè)備樹中LCD 所使用的IO 配置,這個(gè)其實(shí)NXP 都已經(jīng)給我們寫好了,不需要修改,不過我們還是要看一下。打開imx6ull-alientek-emmc.dts 文件,在iomuxc 節(jié)點(diǎn)中找到如下內(nèi)容:
第2~27 行,子節(jié)點(diǎn)pinctrl_lcdif_dat,為RGB LCD 的24 根數(shù)據(jù)線配置項(xiàng)。
第30~36 行,子節(jié)點(diǎn)pinctrl_lcdif_ctrl,RGB LCD 的4 根控制線配置項(xiàng),包括CLK、ENABLE、VSYNC 和HSYNC。
第37~40 行,子節(jié)點(diǎn)pinctrl_pwm1,LCD 背光PWM 引腳配置項(xiàng)。這個(gè)引腳要根據(jù)實(shí)際情況設(shè)置,這里我們建議大家在以后的學(xué)習(xí)或工作中,LCD 的背光IO 盡量和半導(dǎo)體廠商的官方開發(fā)板一致。
注意示例代碼59.3.1 中默認(rèn)將LCD 的電氣屬性都設(shè)置為0X79,這里將其都改為0X49,也就是將LCD 相關(guān)IO 的驅(qū)動(dòng)能力改為R0/1,也就是降低LCD 相關(guān)IO 的驅(qū)動(dòng)能力。因?yàn)榍懊嬉呀?jīng)說了,正點(diǎn)原子的ALPHA 開發(fā)板上的LCD 接口用了三個(gè)SGM3157 模擬開關(guān),為了防止模擬開關(guān)影響到網(wǎng)絡(luò),因此這里需要降低LCD 數(shù)據(jù)線的驅(qū)動(dòng)能力,如果你所使用的板子沒有用到模擬開關(guān)那么就不需要將0X79 改為0X49。
2、LCD 屏幕參數(shù)節(jié)點(diǎn)信息修改
繼續(xù)在imx6ull-alientek-emmc.dts 文件中找到lcdif 節(jié)點(diǎn),節(jié)點(diǎn)內(nèi)容如下所示:
示例代碼59.3.2 就是向imx6ull.dtsi 文件中的lcdif 節(jié)點(diǎn)追加的內(nèi)容,我們依次來看一下示例代碼59.3.2 中的這些屬性都是寫什么含義。
第3 行,pinctrl-0 屬性,LCD 所使用的IO 信息,這里用到了pinctrl_lcdif_dat、pinctrl_lcdif_ctrl和pinctrl_lcdif_reset 這三個(gè)IO 相關(guān)的節(jié)點(diǎn),前兩個(gè)在示例代碼59.3.1 中已經(jīng)講解了。
pinctrl_lcdif_reset 是LCD 復(fù)位IO 信息節(jié)點(diǎn),正點(diǎn)原子的I.MX6U-ALPHA 開發(fā)板的LCD 沒有用到復(fù)位IO,因此pinctrl_lcdif_reset 可以刪除掉。
第6 行,display 屬性,指定LCD 屬性信息所在的子節(jié)點(diǎn),這里為display0,下面就是display0子節(jié)點(diǎn)內(nèi)容。
第9~32 行,display0 子節(jié)點(diǎn),描述LCD 的參數(shù)信息,第10 行的bits-per-pixel 屬性用于指明一個(gè)像素占用的bit 數(shù),默認(rèn)為16bit。本教程我們將LCD 配置為RGB888 模式,因此一個(gè)像素點(diǎn)占用24bit,bits-per-pixel 屬性要改為24。第11 行的bus-width 屬性用于設(shè)置數(shù)據(jù)線寬度,因?yàn)橐渲脼镽GB888 模式,因此bus-width 也要設(shè)置為24。
第13~30 行,這幾行非常重要!因?yàn)檫@幾行設(shè)置了LCD 的時(shí)序參數(shù)信息,NXP 官方的EVK開發(fā)板使用了一個(gè)4.3 寸的480*272 屏幕,因此這里默認(rèn)是按照NXP 官方的那個(gè)屏幕參數(shù)設(shè)置的。每一個(gè)屬性的含義后面的注釋已經(jīng)寫的很詳細(xì)了,大家自己去看就行了,這些時(shí)序參數(shù)就是我們重點(diǎn)要修改的,需要根據(jù)自己所使用的屏幕去修改。
這里以正點(diǎn)原子的ATK7016(7 寸1024*600)屏幕為例,將imx6ull-alientek-emmc.dts 文件中的lcdif 節(jié)點(diǎn)改為如下內(nèi)容:
1 &lcdif { 2 pinctrl-names = "default"; 3 pinctrl-0 = <&pinctrl_lcdif_dat /* 使用到的IO */ 4 &pinctrl_lcdif_ctrl>; 5 display = <&display0>; 6 status = "okay"; 7 8 display0: display { /* LCD屬性信息*/ 9 bits-per-pixel = <24>; /* 一個(gè)像素占用24bit */ 10 bus-width = <24>; /* 總線寬度*/ 11 12 display-timings { 13 native-mode = <&timing0>; /* 時(shí)序信息*/ 14 timing0: timing0 { 15 clock-frequency = <51200000>; /* LCD像素時(shí)鐘,單位Hz */ 16 hactive = <1024>; /* LCD X軸像素個(gè)數(shù)*/ 17 vactive = <600>; /* LCD Y軸像素個(gè)數(shù)*/ 18 hfront-porch = <160>; /* LCD hfp參數(shù)*/ 19 hback-porch = <140>; /* LCD hbp參數(shù)*/ 20 hsync-len = <20>; /* LCD hspw參數(shù)*/ 21 vback-porch = <20>; /* LCD vbp參數(shù)*/ 22 vfront-porch = <12>; /* LCD vfp參數(shù)*/ 23 vsync-len = <3>; /* LCD vspw參數(shù)*/ 24 25 hsync-active = <0>; /* hsync數(shù)據(jù)線極性*/ 26 vsync-active = <0>; /* vsync數(shù)據(jù)線極性*/ 27 de-active = <1>; /* de數(shù)據(jù)線極性*/ 28 pixelclk-active = <0>; /* clk數(shù)據(jù)線先極性*/ 29 }; 30 }; 31 }; 32 };第3 行,設(shè)置LCD 屏幕所使用的IO,刪除掉原來的pinctrl_lcdif_reset,因?yàn)闆]有用到屏幕復(fù)位IO,其他的IO 不變。
第9 行,使用RGB888 模式,所以一個(gè)像素點(diǎn)是24bit。
第15~23 行,ATK7016 屏幕時(shí)序參數(shù),根據(jù)自己所使用的屏幕修改即可。
3、LCD 屏幕背光節(jié)點(diǎn)信息
正點(diǎn)原子的LCD 接口背光控制IO 連接到了I.MX6U 的GPIO1_IO08 引腳上,GPIO1_IO08復(fù)用為PWM1_OUT,通過PWM 信號(hào)來控制LCD 屏幕背光的亮度,這個(gè)我們已經(jīng)在第二十九章詳細(xì)的講解過了。正點(diǎn)原子I.MX6U-ALPHA 開發(fā)板的LCD 背光引腳和NXP 官方EVK 開發(fā)板的背光引腳一樣,因此背光的設(shè)備樹節(jié)點(diǎn)是不需要修改的,但是考慮到其他同學(xué)可能使用別的開發(fā)板或者屏幕,LCD 背光引腳和NXP 官方EVK 開發(fā)板可能不同,因此我們還是來看一下如何在設(shè)備樹中添加背光節(jié)點(diǎn)信息。
首先是GPIO1_IO08 這個(gè)IO 的配置,在imx6ull-alientek-emmc.dts 中找到如下內(nèi)容:
1 pinctrl_pwm1: pwm1grp { 2 fsl,pins = < 3 MX6UL_PAD_GPIO1_IO08__PWM1_OUT 0x110b0 4 >; 5 };pinctrl_pwm1 節(jié)點(diǎn)就是GPIO1_IO08 的配置節(jié)點(diǎn),從第3 行可以看出,設(shè)置GPIO1_IO08這個(gè)IO 復(fù)用為PWM1_OUT,并且設(shè)置電氣屬性值為0x110b0。
LCD 背光要用到PWM1,因此也要設(shè)置PWM1 節(jié)點(diǎn),在imx6ull.dtsi 文件中找到如下內(nèi)容:
1 pwm1: pwm@02080000 { 2 compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm"; 3 reg = <0x02080000 0x4000>; 4 interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; 5 clocks = <&clks IMX6UL_CLK_PWM1>, 6 <&clks IMX6UL_CLK_PWM1>; 7 clock-names = "ipg", "per"; 8 #pwm-cells = <2>; 9 };imx6ull.dtsi 文件中的pwm1 節(jié)點(diǎn)信息大家不要修改,如果要修改pwm1 節(jié)點(diǎn)內(nèi)容的話請(qǐng)?jiān)趇mx6ull-alientek-emmc.dts 文件中修改。在整個(gè)Linux 源碼文件中搜索compatible 屬性的這兩個(gè)值即可找到imx6ull 的pwm 驅(qū)動(dòng)文件,imx6ull 的PWM 驅(qū)動(dòng)文件為drivers/pwm/pwm-imx.c,這里我們就不詳細(xì)的去分析這個(gè)文件了。繼續(xù)在imx6ull-alientek-emmc.dts 文件中找到向pwm1
追加的內(nèi)容,如下所示:
第3 行,設(shè)置pwm1 所使用的IO 為pinctrl_pwm1,也就是示例代碼59.3.4 所定義的GPIO1_IO08 這個(gè)IO。
第4 行,將status 設(shè)置為okay。
如果背光用的其他pwm 通道,比如pwm2,那么就需要仿照示例代碼59.3.6 的內(nèi)容,向pwm2 節(jié)點(diǎn)追加相應(yīng)的內(nèi)容。pwm 和相關(guān)的IO 已經(jīng)準(zhǔn)備好了,但是Linux 系統(tǒng)怎么知道PWM1_OUT 就是控制LCD 背光的呢?因此我們還需要一個(gè)節(jié)點(diǎn)來將LCD 背光和PWM1_OUT連接起來。這個(gè)節(jié)點(diǎn)就是backlight ,backlight 節(jié)點(diǎn)描述可以參考
Documentation/devicetree/indings/video/backlight/pwm-backlight.txt 這個(gè)文檔,此文檔詳細(xì)講解了backlight 節(jié)點(diǎn)該如何去創(chuàng)建,這里大概總結(jié)一下:
①、節(jié)點(diǎn)名稱要為“backlight”。
②、節(jié)點(diǎn)的compatible 屬性值要為“pwm-backlight”,因此可以通過在Linux 內(nèi)核中搜索“pwm-backlight ”來查找PWM 背光控制驅(qū)動(dòng)程序,這個(gè)驅(qū)動(dòng)程序文件為drivers/video/backlight/pwm_bl.c,感興趣的可以去看一下這個(gè)驅(qū)動(dòng)程序。
③、pwms 屬性用于描述背光所使用的PWM 以及PWM 頻率,比如本章我們要使用的pwm1,pwm 頻率設(shè)置為5KHz(NXP 官方推薦設(shè)置)。
④、brightness-levels 屬性描述亮度級(jí)別,范圍為0~255,0 表示PWM 占空比為0%,也就是亮度最低,255 表示100%占空比,也就是亮度最高。至于設(shè)置幾級(jí)亮度,大家可以自行填寫此屬性。
⑤、default-brightness-level 屬性為默認(rèn)亮度級(jí)別。
根據(jù)上述5 點(diǎn)設(shè)置backlight 節(jié)點(diǎn),這個(gè)NXP 已經(jīng)給我們?cè)O(shè)置好了,大家在imx6ull-alientek-emmc.dts 文件中找到如下內(nèi)容:
第3 行,設(shè)置背光使用pwm1,PWM 頻率為5KHz。
第4 行,設(shè)置背8 級(jí)背光(0~7),分別為0、4、8、16、32、64、128、255,對(duì)應(yīng)占空比為0%、1.57%、3.13%、6.27%、12.55%、25.1%、50.19%、100%,如果嫌少的話可以自行添加一些其他的背光等級(jí)值。
第5 行,設(shè)置默認(rèn)背光等級(jí)為6,也就是50.19%的亮度。
關(guān)于背光的設(shè)備樹節(jié)點(diǎn)信息就講到這里,整個(gè)的LCD 設(shè)備樹節(jié)點(diǎn)內(nèi)容我們就講完了,按照這些節(jié)點(diǎn)內(nèi)容配置自己的開發(fā)板即可。
運(yùn)行測試
LCD 屏幕基本測試
1、編譯新的設(shè)備樹
上一小節(jié)我們已經(jīng)配置好了設(shè)備樹,所以需要輸入如下命令重新編譯一下設(shè)備樹:
等待編譯生成新的imx6ull-alientek-emmc.dtb 設(shè)備樹文件,一會(huì)要使用新的設(shè)備樹啟動(dòng)Linux 內(nèi)核。
2、使能Linux logo 顯示
Linux 內(nèi)核啟動(dòng)的時(shí)候可以選擇顯示小企鵝logo,只要這個(gè)小企鵝logo 顯示沒問題那么我們的LCD 驅(qū)動(dòng)基本就工作正常了。這個(gè)logo 顯示是要配置的,不過Linux 內(nèi)核一般都會(huì)默認(rèn)開啟logo 顯示,但是奔著學(xué)習(xí)的目的,我們還是來看一下如何使能Linux logo 顯示。打開Linux內(nèi)核圖形化配置界面,按下路徑找到對(duì)應(yīng)的配置項(xiàng):
如圖59.4.1.1 所示:
圖59.4.1.1 中這三個(gè)選項(xiàng)分別對(duì)應(yīng)黑白、16 位、24 位色彩格式的logo,我們把這三個(gè)都選中,都編譯進(jìn)Linux 內(nèi)核里面。設(shè)置好以后保存退出,重新編譯Linux 內(nèi)核,編譯完成以后使用新編譯出來的imx6ull-alientek-emmc.dtb 和zImage 鏡像啟動(dòng)系統(tǒng),如果LCD 驅(qū)動(dòng)工作正常的話就會(huì)在LCD 屏幕左上角出現(xiàn)一個(gè)彩色的小企鵝logo,屏幕背景色為黑色,如圖59.4.1.2 所示:
設(shè)置LCD 作為終端控制臺(tái)
我們一直使用SecureCRT 作為Linux 開發(fā)板終端,開發(fā)板通過串口和SecureCRT 進(jìn)行通信。現(xiàn)在我們已經(jīng)驅(qū)動(dòng)起來LCD 了,所以可以設(shè)置LCD 作為終端,也就是開發(fā)板使用自己的顯示設(shè)備作為自己的終端,然后接上鍵盤就可以直接在開發(fā)板上敲命令了,將LCD 設(shè)置為終端控制臺(tái)的方法如下:
1、設(shè)置uboot 中的bootargs
重啟開發(fā)板,進(jìn)入Linux 命令行,重新設(shè)置bootargs 參數(shù)的console 內(nèi)容,命令如下所示:
注意紅色字體部分設(shè)置console,這里我們?cè)O(shè)置了兩遍console,第一次設(shè)置console=tty1,也就是設(shè)置LCD 屏幕為控制臺(tái),第二遍又設(shè)置console=ttymxc0,115200,也就是設(shè)置串口也作為控制臺(tái)。相當(dāng)于我們打開了兩個(gè)console,一個(gè)是LCD,一個(gè)是串口,大家重啟開發(fā)板就會(huì)發(fā)
現(xiàn)LCD 和串口都會(huì)顯示Linux 啟動(dòng)log 信息。但是此時(shí)我們還不能使用LCD 作為終端進(jìn)行交互,因?yàn)槲覀兊脑O(shè)置還未完成。
2、修改/etc/inittab 文件
打開開發(fā)板根文件系統(tǒng)中的/etc/inittab 文件,在里面加入下面這一行:
添加完成以后的/etc/inittab 文件內(nèi)容如圖59.4.2.1 所示:
修改完成以后保存/etc/inittab 并退出,然后重啟開發(fā)板,重啟以后開發(fā)板LCD 屏幕最后一
行會(huì)顯示下面一行語句:
上述提示語句說的是:按下回車鍵使能當(dāng)前終端,我們?cè)诘谖迨苏乱呀?jīng)將I.MX6U-ALPHA 開發(fā)板上的KEY 按鍵注冊(cè)為了回車鍵,因此按下開發(fā)板上的KEY 按鍵即可使能LCD這個(gè)終端。當(dāng)然了,大家也可以接上一個(gè)USB 鍵盤,Linux 內(nèi)核默認(rèn)已經(jīng)使能了USB 鍵盤驅(qū)動(dòng)了,因此可以直接使用USB 鍵盤。
至此,我們就擁有了兩套終端,一個(gè)是基于串口的SecureCRT,一個(gè)就是我們開發(fā)板的LCD屏幕,但是為了方便調(diào)試,我們以后還是以SecureCRT 為主。我們可以通過下面這一行命令向LCD 屏幕輸出“hello linux!”
LCD 背光調(diào)節(jié)
59.3 小節(jié)已經(jīng)講過了,背光設(shè)備樹節(jié)點(diǎn)設(shè)置了8 個(gè)等級(jí)的背光調(diào)節(jié),可以設(shè)置為0~7,我們可以通過設(shè)置背光等級(jí)來實(shí)現(xiàn)LCD 背光亮度的調(diào)節(jié),進(jìn)入如下目錄:
/sys/devices/platform/backlight/backlight/backlight此目錄下的文件如圖59.4.3.1 所示:
圖59.4.3.1 中的brightness 表示當(dāng)前亮度等級(jí),max_bgigntness 表示最大亮度等級(jí)。當(dāng)前這兩個(gè)文件內(nèi)容如圖59.4.3.2 所示:
從圖59.4.3.2 可以看出,當(dāng)前屏幕亮度等級(jí)為6,根據(jù)前面的分析可以,這個(gè)是50%亮度。屏幕最大亮度等級(jí)為7。如果我們要修改屏幕亮度,只需要向brightness 寫入需要設(shè)置的屏幕亮度等級(jí)即可。比如設(shè)置屏幕亮度等級(jí)為7,那么可以使用如下命令:
echo 7 > brightness輸入上述命令以后就會(huì)發(fā)現(xiàn)屏幕亮度增大了,如果設(shè)置brightness 為0 的話就會(huì)關(guān)閉LCD背光,屏幕就會(huì)熄滅。
從LCD自動(dòng)關(guān)閉解決方法
默認(rèn)情況下10 分鐘以后LCD 就會(huì)熄屏,這個(gè)并不是代碼有問題,而是Linux 內(nèi)核設(shè)置的,就和我們用手機(jī)或者電腦一樣,一段時(shí)間不操作的話屏幕就會(huì)熄滅,以節(jié)省電能。解決這個(gè)問題有多種方法,我們依次來看一下:
1、按鍵盤喚醒
最簡單的就是按下回車鍵喚醒屏幕,我們?cè)诘?8 章將I.MX6U-ALPHA 開發(fā)板上的KEY按鍵注冊(cè)為了回車鍵,因此按下開發(fā)板上的KEY 按鍵即可喚醒屏幕。如果開發(fā)板上沒有按鍵的話可以外接USB 鍵盤,然后按下USB 鍵盤上的回車鍵喚醒屏幕。
2、關(guān)閉10 分鐘熄屏功能
在Linux 源碼中找到drivers/tty/vt/vt.c 這個(gè)文件,在此文件中找到blankinterval 變量,如下所示:
blankinterval 變量控制著LCD 關(guān)閉時(shí)間,默認(rèn)是10*60,也就是10 分鐘。將blankinterval的值改為0 即可關(guān)閉10 分鐘熄屏的功能,修改完成以后需要重新編譯Linux 內(nèi)核,得到新的zImage,然后用新的zImage 啟動(dòng)開發(fā)板。
3、編寫一個(gè)APP 來關(guān)閉熄屏功能
在ubuntu 中新建一個(gè)名為lcd_always_on.c 的文件,然后在里面輸入如下所示內(nèi)容:
使用如下命令編譯lcd_always_on.c 這個(gè)文件:
arm-linux-gnueabihf-gcc lcd_always_on.c -o lcd_always_on編譯生成lcd_always_on 以后將此可執(zhí)行文件拷貝到開發(fā)板根文件系統(tǒng)的/usr/bin 目錄中,然后給予可執(zhí)行權(quán)限。設(shè)置lcd_always_on 這個(gè)軟件為開機(jī)自啟動(dòng),打開/etc/init.d/rcS,在此文件最后面加入如下內(nèi)容:
1 cd /usr/bin 2 ./lcd_always_on 3 cd ..修改完成以后保存/etc/init.d/rcS 文件,然后重啟開發(fā)板即可。關(guān)于Linux 下的LCD 驅(qū)動(dòng)我們就講到這里。
總結(jié)
以上是生活随笔為你收集整理的Linux LCD 驱动实验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上传图片预览,支持IE6
- 下一篇: Linux RTC 驱动实验