hud項目lcd調試過程的一些見解


1.幀緩沖(FrameBuffer)設備驅動
幀緩沖設備為標准的字符型設備,在Linux中主設備號29,定義在/include/uapi/linux/major.h中的FB_MAJOR,次設備號定義幀緩沖的個數,最大允許有32個FrameBuffer,定義在/include/linux/fb.h中的FB_MAX,對應於文件系統下/dev/fb%d設備文件

 

我們從上面這幅圖看,幀緩沖設備在Linux中也可以看做是一個完整的子系統,大體由fbmem.c和xxxfb.c組成。向上給應用程序提供完善的設備文件操作接口(即對FrameBuffer設備進行read、write、ioctl等操作),接口在Linux提供的fbmem.c文件中實現;向下提供了硬件操作的接口,只是這些接口Linux並沒有提供實現,因為這要根據具體的LCD控制器硬件進行設置,所以這就是我們要做的事情了(即xxxfb.c部分的實現), imx6dl的在kernel/drivers/video/mxc/mxc_ipuv3_fb.c中實現

 

參考sdk中rgb接口配置
硬件資源:設備樹/imx6ul_sdk/linux-3.14.52/arch/arm/boot/dts/myimx6ek140-6g.dts和imx6ul_sdk/linux-3.14.52/arch/arm/boot/dts/imx6ul.dtsi
lcdif設備節點, ELCDIF(Enhanced LCD Interface)內存基地址為0x021c8000
lcdif數據接口為pinctrl_lcdif_dat, 信號控制接口為pinctrl_lcdif_ctrl
lcd屏硬件資源為display0設備節點

2.解析drivers/video/mxc/mxc_ipuv3_fb.c文件
2.1根據compatible = "fsl,mxc_sdc_fb", 匹配進入mxcfb_probe()
2.2of_alias_get_id()獲取mxcfb硬件節點編號
2.3devm_kzalloc()申請內存給plat_data
2.4pdev->dev.platform_data = plat_data, 把申請好的地址傳遞給pdev->dev的自定義的私有數據platform_data
2.5mxcfb_get_of_property(pdev, plat_data), 利用pdev來匹配設備節點, 然后解析設備樹上的私有數據(disp_dev, mode_str, interface_pix_fmt, default_bpp, init_clk, late_init, prefetch)賦值給plat_data
2.6mxcfb_init_fbinfo(), 初始化framebuffer(幀緩沖)數據結構, 即填充fb_info數據結構(主要填充fb_ops)
2.7mxcfb_option_setup(), 解析用戶特定選項
2.8把已經初始化好的fb_info數據賦值給自定義的數據結構mxcfbi
2.9mxcfb_dispdrv_init()顯示設備驅動初始化, 把剛剛從設備樹解析出來的plat_data私有數據賦值給mxcfbi, 然后mxc_dispdrv_gethandle()從已經注冊好的驅動中獲取驅動(比如drv name = "lcd", 即名字為lcd的驅動)句柄, 如果有該驅動(即名為"lcd"驅動), 那么注冊mxc顯示驅動
2.10platform_get_resource()獲取內存資源, 由於改成設備樹了, 已解析完, 不是按原來的板級文件解析, 所以獲取不到, res = NULL
2.11ipu_get_soc()獲取ipu編號

3.解析drivers/video/mxc/mxc_lcdif.c文件(RGB接口lcd驅動)
3.1lcdif = devm_kzalloc(), 為lcdif申請內存
3.2plat_data = devm_kzalloc(), 為plat_data申請內存
3.3pdev->dev.platform_data = plat_data; 把plat_data地址賦值給pdev->dev的私有數據結構
3.4ret = lcd_get_of_property(pdev, plat_data); 解析設備樹已經匹配好的設備節點(通過compatible = "fsl,lcd"進行匹配, 獲取到lcd節點)的屬性, 把解析好的數據(ipu_id, disp_id, default_ifmt)賦值給plat_data
3.5pinctrl = devm_pinctrl_get_select_default(&pdev->dev); 根據設備(pdev->dev)獲取pin操作句柄
3.6lcdif->pdev = pdev; 把pdev賦值給私有的lcdif->pdev
3.7lcdif->disp_lcdif = mxc_dispdrv_register(&lcdif_drv); 把lcd硬件操作句柄lcdif_drv賦值給lcdif->disp_lcdif, 其中lcdif_drv操作接口有:lcdif_init, lcdif_deinit
對於lcdif_init: ipu_di_to_ctrc, 使用平台預先定義好的ipu/di(在設備樹上lcd節點的disp_id, ipu_id屬性)來設置ipu的時鍾; fb_find_mode()用於解析有效的視頻或圖像模式(像素, 行切換延遲時間, 頻率等)
注意:lcdif_modedb[]這里添加我們lcd屏的參數(像素, 行切換延遲, 頻率等)
3.8mxc_dispdrv_setdata(lcdif->disp_lcdif, lcdif), 把lcdif數據添加到驅動鏈表中
3.9dev_set_drvdata(&pdev->dev, lcdif)

4.關於顯示設備驅動(比如lcd驅動)和framebuffer驅動加載順序

首先加載lcd驅動mxc_lcdif.c, lcd_get_of_property會解析lcd設備節點的default_ifmt, 比如"RGB24"

然后加載framebuffer驅動, 賦值好pdev->id, 這樣才可以即系對應的uboot傳過來的參數

然后在mxc_option_setup解析uboot傳過來的參數, 即uboot傳下來的參數是為了設置bpp, 像素格式ifmt和顯示設備

然后又在mxcfb_dispdrv_init初始化顯示驅動, 在mxc_dispdrv_gethandle()會對剛剛加載的lcd驅動進行lcdif_init, 即把mxc_option_setup解析的顯示設備參數通過lcdif_init對顯示設備進行設置(這回覆蓋掉之前加載的lcd驅動的default_ifmt)

所以framebuffer驅動與顯示驅動即分開又有聯系, 且uboot的傳參尤為重要, 它的優先級最高, 會覆蓋掉設備設備樹上的默認值比如(default_bpp, default_ifmt)

5.lcd驅動(RGB接口)內核配置
make menuconfig
然后搜索ipu, 可以看到加載lcd驅動需要依賴哪些驅動
framebuffer驅動, drivers/fbmem.c

6.初始化lcd屏mode
lcd屏參數:根據TFF9K2353-V1規格書p13
分辨率:480x240(屏幕一行有480個像素點, 一列有240個像素點), 實際項目中調試分辨率為:480x280
RGB666
VCLK(dotclk):7.97M(typ)
VBPD(vertical back porch):1-2(tH) ---> upper margin
VFBD(vertical front porch):1-8(tH) ---> lower margin
VSPW(vertical sync pulse width):5(tH) ---> vsync len
HBPD(horizontal back porch):2-40(dotclk) ---> left margin
HFPD(horizontal front porth):1-5(dotclk) ---> right margin
HSPW(horizontal sync pulse width):27(dotclk)---> hsync len

7.uboot配置:
The command line parameter takes the following form, use "off" for unused framebuffers:
"video=mxcfb<number>:dev=<Output>,<Mode Specifier>,if=<Output Format>,[bpp=<Framebuffer Depth>]"

e.g.:
video=mxcfb0:dev=lcd,EDT-WVGA,if=RGB24
video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24
video=mxcfb1:off

8.lcd參數解釋:
當前顯示模式結構體:
/* include/linux/fb.h */
struct fb_videomode {
const char *name; /* 液晶屏名字, 可選optional */
u32 refresh; /* 刷新頻率, 可選optional(內核中大多為60) */
u32 xres; /* 屏幕一行有多少個像素點 */
u32 yres; /* 屏幕一列有多少個像素點 */
u32 pixclock; /* 每個像素時鍾周期的長度, 單位時ps(10的負12次方分之一秒), 比如像素頻率為25M, 那么這個值就為(1/25*1000000)*(1000000000000)=40000*/
u32 left_margin; /*行切換,從同步到繪圖之間的延遲*/
u32 right_margin; /*行切換,從繪圖到同步之間的延遲*/
u32 upper_margin; /*幀切換,從同步到繪圖之間的延遲*/
u32 lower_margin; /*幀切換,從繪圖到同步之間的延遲*/
u32 hsync_len; /*水平同步的長度*/
u32 vsync_len; /*垂直同步的長度*/
u32 sync;
u32 vmode;
u32 flag;
};

9.當lcd顯示圖片是反向或鏡像時,請參考echo 1 > /sys/class/graphics/fb0/rotate,具體參考連接:https://community.nxp.com/message/416223

10.lcd常用接口原理篇
TFT-lCD常用的接口,TTL(RGB)、LVDS、EDP、MIPI, 這篇我們大致說一下這些接口的信號組成已經基本原理.
10.1TTL
a.TTL接口概述
TTL接口屬於並行方式傳輸數據的接口,采用這種接口時,不必在液晶顯示器的驅動板端和液晶面板端使用專用的接口電路,而是由驅動板主控芯片輸出的TTL數據信號經電纜線直接傳送到液晶面板的輸人接口。由於TTL接口信號電壓高、連線多、傳輸電纜長,因此,電路的抗干擾能力比較差,而且容易產生電磁干擾(EMI)。在實際應用中,TTL接口電路多用來驅動小尺寸(15in以下)或低分辨率的液晶面板。TTL最高像素時鍾只有28MHz。
TTL是信號時TFT-LCD唯一能識別的信號,早期的數字處理芯片都是TTL的,也就是RGB直接輸出到TFT-LCD。
b.TTL接口的信號類型
驅動板TTL輸出接口中一般包含RGB數據信號、時鍾信號和控制信號這三大類信號
10.2LVDS
a.LVDS接口概述
LVDS,即Low Voltage Differential Signaling,是一種低壓差分信號技術接口。克服以TTL電平方式傳輸寬帶高碼率數據時功耗大、EMI電磁干擾大等缺點而研制的一種數字視頻信號傳輸方式。LVDS輸出接口利用非常低的電壓擺幅(約350mV)在兩條PCB走線或一對平衡電纜上通過差分進行數據的傳輸,即低壓差分信號傳輸。采用LVDS輸出接口,可以使得信號在差分PCB線或平衡電纜上以幾百Mbit/s的速率傳輸,由於采用低壓和低電流驅動方式,因此,實現了低噪聲和低功耗。
b.LVDS接口電路的組成
在液晶顯示器中,LVDS接口電路包括兩部分,即主板側的LVDS輸出接口電路(LVDS發送端)和液晶面板側的LVDS輸入接口電路(LVDS接收器)。LVDS發送端將TTL信號轉換成LVDS信號,然后通過驅動板與液晶面板之間的柔性電纜(排線)將信號傳送到液晶面板側的LVDS接收端的LVDS解碼IC中,LVDS接收器再將串行信號轉換為TTL電平的並行信號,送往液晶屏時序控制與行列驅動電路。也就是其實TFT只識別TTL(RGB)信號。
c.LVDS接口的信號類型
LVDS信號有數據差分和時鍾差分信號組成
10.3EDP
這個接口比較陌生,我接觸到一個屏IPAD3的,用於高清屏,比如2048*1536,goole n10的分辨率2536* 也是用這個接口。
10.4MIPI接口
這個我們公司有產品用,不過是其他平台的,不是我們調試 ,我也沒接觸過。只是過一下。感覺這類接口非常類似:比如LVDS、EDP、HDMI、MIPI,都是差分信息+差分時鍾。

11.如何閱讀LCD規格書
首先我們調試LCD的時候要獲得的一些參數,沒必要把整個規格書通讀一遍,我剛開始調試屏的時候拿到一個規格書不知道從何入手,也不知那些參數有用,比較模糊,其實只提取一些有用的信息就可以,下面這些對初學者也許有點用處。
一個LCD規格書要了解的也就這么多,調試軟件就夠用:
a.General Specification中可得到,尺寸、分辨率、位數、色彩、像素時鍾頻率、接口類型;
b.Timing Characteristics中可以得到一些具體的參數;
c.LCD Timing diagram信號時序圖,可以看到一些信號的時序、極性等;

 

12.調試lcd驅動遇到的問題

a.lcd屏幕顯示顏色不對

b.lcd顯示的圖像下篇40mm

解決方法:

a.lcd屏幕顯示顏色不對,發現應該顯示紅色的顯示為藍色,應該顯示藍色的顯示為紅色,即RGB顯示為BGR

這個說明配置的RGB位域有問題(即一個像素的組織格式不對,RGB位域,表示該結構描述每一個像素顯示緩沖區的組織方式,假如為RGB565模式,R占5位=bit[11:15],G占6位=bit[10:5] B占5位=bit[4:0] ),之前像素格式ifmt=RGB565,lcd屏的硬件是RGB666,但是原理圖中它是按照RGB888格式來接的,低兩位接地,我的驅動也是用RGB565來解析,所以會有lcd顏色問題,后面改成ifmt=RGB24,顏色就正常了(低兩位接地,會導致lcd表示的顏色沒有那么豐富而已),所以在boot的參數中也要修改,設備樹中也要修改

之前的boot參數mmcargs=setenv bootargs console=ttymxc0,115200  root=/dev/mmcblk3p5 rootwait rw video=mxcfb0:dev=lcd,HUD-WVGA,if=RGB565,bpp=16

改為mmcargs=setenv bootargs console=ttymxc0,115200  root=/dev/mmcblk3p5 rootwait rw video=mxcfb0:dev=lcd,HUD-WVGA,if=RGB24,bpp=24

之前設備樹mxcfb3: fb@2 {
         compatible = "fsl,mxc_sdc_fb";
         disp_dev = "lcd";
         interface_pix_fmt = "RGB565";
         mode_str ="HUD-WVGA";
         default_bpp = <16>;
         int_clk = <0>;
         late_init = <0>;
         status = "disabled";

    }

   lcd@0{

    compatible = "fsl,lcd";
         ipu_id = <0>;
         disp_id = <0>;
         default_ifmt = "RGB565";
         pinctrl-names = "default";
         pinctrl-0 = <&pinctrl_ipu1>;
         status = "okay";
    }

改為mxcfb3: fb@2 {
         compatible = "fsl,mxc_sdc_fb";
         disp_dev = "lcd";
         interface_pix_fmt = "RGB24";
         mode_str ="HUD-WVGA";
         default_bpp = <24>;
         int_clk = <0>;
         late_init = <0>;
         status = "disabled";

    }

   lcd@0{

    compatible = "fsl,lcd";
         ipu_id = <0>;
         disp_id = <0>;
         default_ifmt = "RGB24";
         pinctrl-names = "default";
         pinctrl-0 = <&pinctrl_ipu1>;
         status = "okay";
    }

這樣就顯示正常了

b.lcd顯示的圖像下篇40mm,對於這個問題是由於調試的lcd行列同步的時間沒調好,所以會導致延遲(可參考http://blog.csdn.net/wocao1226/article/details/21702601中的LCD圖像錯位問題解決方案)

本來lcd的屏幕分辨率時480x240,由於調試時發現下偏了40mm,所以把分辨率配置成480x280,這只是權宜之計,這相當於lcd顯示的原點都下移了40mm,還是要從根本上解決問題,就調整了行列同步問題

之前調試的

/* 480x280 @ 60 Hz , pixel clk @ 9.2 MHz*/
+#if 0
     "HUD-WVGA", 60, 480, 280, 108696, 16, 4, 2, 5, 27, 5,
     FB_SYNC_CLK_LAT_FALL,
     FB_VMODE_NONINTERLACED,
     0,},
改為

 /* 480x240 @ 60 Hz , pixel clk @ 9.2 MHz*/
+    "HUD-WVGA", 60, 480, 240, 125470, 40, 5, 40, 8, 2, 2,
+    FB_SYNC_CLK_LAT_FALL,
+    FB_VMODE_NONINTERLACED,
+    0,},

就解決了

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM