轉自:http://blog.chinaunix.net/uid-22915173-id-329617.html
Framebuffer:是linux的framebuffer驅動在內存開辟的一塊顯存,存放一幀圖像數據。
IPU:是mx51的圖像處理單元,里面包含DMA控制器和DI顯示接口等。
LCDDriver:是一塊和LCD屏幕整合在一起的驅動芯 片,接收IPU傳過來的數據和時序信號,轉化為有規律的LCD驅動電壓。
一幅圖像的顯示過程是這樣的:用戶打開/dev/fbx設備,使用mmap()系統調用映射framebuffer內存空間到用戶空間,用戶直接用 memcpy()復制圖像數據到framebuffer,DMA探測到framebuffer數據發生變動,啟動DMA傳輸圖像數據到IPUI,PU再根 據framebuffer驅動設置的處理模式對像素數據進行一系列處理,比如framebuffer使用了overlay framebuffer那就啟動overlay處理單元混合兩個framebuffer的數據,另外IPU還會packing像素數據,比如 framebuffer里像素格式為RGB565,IPU會把他packing成RGB666的格式,以配合LCD模塊的接口。IPU處理完數據后,送到 DI,在DI時序模塊產生的時序信號同步下,一起輸出到LCD驅動芯片。
移植LCD驅動的第一步,是確保IPU輸出給LCD Driver的時序、數據、供電信號是對的。
時序信號一般是根據LCD的datasheet上的參數,填寫fb_videomode這個結構體:
struct fb_videomode {
const char *name; /* optional */
u32 refresh; /* optional */
u32 xres; // x分辨率
u32 yres; // y分辨率
u32 pixclock; // 像素時鍾頻率,即每個時鍾周期顯示一個像素點
u32 left_margin; // 行掃描開始脈沖到一行像素數據開始輸出的延遲 hsync<==>DEN
u32 right_margin; // 一行像素數據輸出完畢到下一行的行掃描開始脈沖間的延遲 DEN <==>hsync
u32 upper_margin; // 幀掃描開始脈沖到第一行像素數據開始輸出的延遲 vsync<==>DEN(1st line)
u32 lower_margin; // 最后一行像素數據輸出結束到下一幀的那幀掃描開始脈沖間的延遲DEN(last line)<==>vsync
u32 hsync_len; // 行掃描脈沖寬度,單位為pixclock
u32 vsync_len; // 幀掃描脈沖寬度,單位為line
u32 sync; // 各同步信號的極性定義,如hsync、vsync、DEN的極性等。
u32 vmode; // 顯示模式,逐行還是隔行掃描
u32 flag; // 一般為0
};
這個結構體定義完之后,對於一般的LCD,在連線正確的情況下,系統啟動后應該就出來圖像了,此時圖像可能是上下跳動或者左右有偏移,這就需要再調整一下 fb_videomode中left/right/upper/lower margin參數。如果上電后沒有圖像,則首先用示波器檢測hsync, vsync,DEN,pclk等波形是否正確,使用雙蹤示波器通過hsync、vsync與DEN的比對查看left/right/upper /lower margin是否合適。如果這些信號都沒有問題,那么說明LCD需要通過spi總線發送命令對其進行初始化。初始化代碼一般由LCD廠商提供,不過很多廠 商提供的初始化代碼都有問題,會導致LCD白屏或者其他不正常的現象。
TFT LCD的原理:
圖2. TFT LCD截面圖
TFT LCD主要由兩個透明電極,中間的液晶分子和一個有色玻璃組成。在沒有通電的情況下,液晶分子呈無規則排列,背光無法透過液晶層。當有外加電場時,液晶分 子順着電場的方向有序排列,背光可以通過,並且由於有色玻璃的濾光,呈現紅,綠,藍色調,不過,背光的透過率只有10%,這是LCD的一個缺點。
以上是一個像素中的一個RGB分量的產生過程。接下來看看如何整合這個基本單元,組成一個LCD屏幕。
圖3. LCD平面圖
這個圖比上面多出來的是2種長條和一種MOS晶體管。這3個東西的作用是在一定的時序下給各顯示電極充電。橫向的長條和LCD驅動芯片的Gate Driver連接的,用於打開各行的MOSFET。縱向的長條和LCD驅動芯片的Source Driver連接,代表RGB數據。整個過程大致是這樣的:首先第一行的Gate線產生一個充電脈沖,使第一行的MOS管導通,同時Source線那邊經 過數模轉換后的RGB電壓也已經就緒,於是通過MOS管對顯示電極充電,每個pixel clock充電一個像素,即3根Source線完成充電。對於320x480的屏,一共有480根Gate線,320x3=960根Source線,則經 過320個pclk后,第一行充電完成,顯示出相應的畫面。然后,第二行的Gate線產生一個充電脈沖,一次類推,直到最后一行,又從第一行開 始.....
圖4. LCD基本結構
圖4. LCD傳輸分解
圖5. LCD基本單元圖
圖6. LCD陣列圖
圖7. LCD信號圖
圖8. LCD整體框圖
LCD點屏步驟:
1.參考LCD datasheet修改fb_videomode結構體的參數。
2.配置GPIO,點亮LCD背光。
3.參考LCD datasheet看這個LCD是否需要spi總線發送命令進行初始化,一般廠商給datasheet時也會給一份初始化代碼,不過有些參數是錯誤的,需 要調整,發送不正確的命令會導致LCD白屏。
4.用示波器測試從LCD控制器出來的Hsync, Vsync, DE, PCLK是否正確,用萬用表測量Vio, Vci是否正常。
5.有的LCD Driver需要LCD控制器發出一個CS片選使能信號。
6.用萬用表測量LCD的柵壓是否正常,一般為9.2V。
7.如果上述步驟后還出不來,再檢查LCD初始化命令是否正確,spi時序是否符合。
圖像異常處理:
1.驅動問題
上下抖動,左右沒對齊:調整left/right/upper/lower margin值
2.LCD初始化命令問題
有紋波:調整VDD/AVDD/VGL/VGH電壓
色彩失真:看LCD的RGB模式設置和LCD控制器出來的RGB模式是否一致
本次點屏過程:
0. 非常感謝張同學和梁同學在本次點屏中所作的關鍵性工作。
1. 在mx51_kernel的mxcfb_epson_vga.c的fb_videomode結構體中修改了時序參數,上電,LCD無任何反應
2. 張同學在mx51_3stack_gpio.c中通過配置GPIO NANDF_CS6 打開了LCD背光燈,LCD產生白屏閃動現象,並在mxcfb_epson_vga.c的lcd_init()中加入了ilitek提供的初始化命令。
3. 梁同學在mx51_3stack_gpio.c中通過配置MX51_PIN_DI1_D1_CS ,使其一直拉低,提供了LCD Driver芯片的片選使能,並測量出upper margin和lower margin時序有偏移,經過調整此2值,消除了IPU error。
4. 去掉3條冗余的LCD初始化命令,LCD點亮。
5. 對於本次調屏,以上步驟都是必要的,也是充分的
kernel 文件修改:
1.driver/video/mxc/mxcfb_epson_vga.c
(1).static struct fb_videomode video_modes[] 改為:
- static struct fb_videomode video_modes[] = {
- {
- /* 320x480 @ 60 Hz */
- "Elite-HVGA", 60, 320, 480, 86566, 20, 40, 5, 1, 10, 2,
- FB_SYNC_CLK_LAT_FALL,
- FB_VMODE_NONINTERLACED,
- 0,},
- };
(2).static void lcd_init(void)改為:
- static void lcd_init(void)
- {
- u16 i;
- const u16 cmd[] = {
- 0x11,
- 0xD0, param(0x07), param(0x41), param(0x0F),
- 0xD1, param(0x00), param(0x3E), param(0x1F),
- 0xD2, param(0x01), param(0x10),
- 0xC0, param(0x00), param(0x3B), param(0x00), param(0x02),
- param(0x11),
- 0xC5, param(0x02),
- // 0xC6, param(0x1B),
- 0xC6, param(0x02),
- 0xC8, param(0x66), param(0x66), param(0x66), param(0x66),
- param(0x0E), param(0x1E), param(0x66), param(0x66),
- param(0x77), param(0x66), param(0x0F), param(0x0F),
- 0x36, param(0x0A), // set_address_mode, RGB order
- 0x3A, param(0x66), // 0x60: RGB=666; 0x50: RGB=565; 0x10: RGB=111
- 0xB4, param(0x11),
- 0x29,
- 0x2C
- };
- if (lcd_spi) {
- spi_write(lcd_spi, (const u8 *)cmd, ARRAY_SIZE(cmd));
- } else {
- for (i = 0; i < sizeof(cmd) / 2; i++)
- {
- ipu_disp_direct_write(DIRECT_ASYNC1, cmd[i], 0);
- }
- msleep(1);
- ipu_uninit_channel(DIRECT_ASYNC1);
- }
- }
2.arch/arm/mach-mx51/mx51_3stack.c
- static struct mxc_lcd_platform_data lcd_data = {
- .core_reg = "VIOHI",
- .io_reg = "SW4",
- .reset = lcd_reset,
- };
改 為
- static struct mxc_lcd_platform_data lcd_data = {
- .core_reg = "VSD",
- .io_reg = "SW4",
- .reset = lcd_reset,
- };
3.arch/arm/mach-mx51/mx51_3stack_gpio.c
void gpio_lcd_active(void)修改為:
- void gpio_lcd_active(void)
- {
- mxc_request_iomux(MX51_PIN_NANDF_CS6, IOMUX_CONFIG_ALT3);
- mxc_set_gpio_direction(MX51_PIN_NANDF_CS6, 0);
- mxc_set_gpio_dataout(MX51_PIN_NANDF_CS6, 1);
- mxc_request_iomux(MX51_PIN_DI1_D1_CS, IOMUX_CONFIG_ALT4);
- mxc_set_gpio_direction(MX51_PIN_DI1_D1_CS, 0);
- mxc_set_gpio_dataout(MX51_PIN_DI1_D1_CS, 0);
- mxc_request_iomux(MX51_PIN_DI_GP2, IOMUX_CONFIG_ALT0);
- mxc_request_iomux(MX51_PIN_DI_GP3, IOMUX_CONFIG_ALT0);
- }