天天看點

調試OTM4001A液晶驅動的一點心得

      這幾天調試一塊以OTM4001A作驅動晶片的LCM模組,調試完畢後,終于有結果OK了。之前對這塊一直用的不太透徹,恰好趁這次摸清楚了。需要注意的幾點記錄如下:

(1)關于信号類型的片選。在很多LCD晶片規格書上都有關于信号片選的描述,如M2/M1/M0,典型如下:

調試OTM4001A液晶驅動的一點心得

如上圖,上面的三個M接口腳是有連接配接線直接連到主機闆接口上的,至于是高還是低,可以由主機闆硬體限定死,另一方面也可以由LCM模組自身做工來限制。具體到我的工作内容上,主機闆上IM0是不接的,IM2接地,基本上就由IM1來決定是16位是18位,用一個電阻來控制。目前我是用的18位接口,多屬于DBI B類型。

      關于DBI接口,18位資料線連接配接和16位連接配接線要作下說明,針對16位寄存器(8位寄存器不存在這個問題)。

A,18位

調試OTM4001A液晶驅動的一點心得

可以看出:18位的資料線傳輸16位的寄存器參數和指令時,DB0和DB9是跳過去的。這就決定了在寫寄存器控制指令時要注意移位(假設32位系統上,怎麼樣将16位寄存器資料分離,然後放到18位資料線上發送出去),這個在後面會有程式說明。18位的資料傳輸就是RGB666了,此處不作說明。

B,16位

調試OTM4001A液晶驅動的一點心得

可以看出:16位的資料線,硬體上是直接對應上的,是以寫控制指令和參數時,不存在上述移位的問題。16位的資料就是RGB565,這個也不做說明。

      從上可以看出,不管是16位還是18位,傳輸指令的總是那幾根線。在硬體接線上注意具體要求。

(2)關于寫寄存器的說明。

      主晶片自帶的讀寫語句分别是:寫寄存器位址SendCtrlComnd(),寫寄存器參數SendDataComnd()。兩者的形參後來我驗證了,應該是32位。硬體采用18位,傳輸18位資料。那麼需要對資料線對應的位進行适當的處理,以在寫寄存器指令時跳過DB0和DB9:

#define SendCtrlComndWrapped(value)         SendCtrlComnd(((value<<1)&0x1fe)|(((value<<2)&0x3fc00)))

#define SendDataComndWrapped(value)       SendDataComnd(((value<<1)&0x1fe)|(((value<<2)&0x3fc00)))

說明:((value<<1)&0x1fe)保證跳過DB0後傳輸采用的DB8到DB1,恰好在位置上對應。((value<<2)&0x3fc00)保證跳過DB0跟DB9兩個位,取得DB17到DB10的資料,從這裡可以看出,該寄存器參數類型是32位的,否則無法跟0x3fc00相與。

      另外,跳過DB0和DB9還有另一種寫法:

#define SendCtrlComndWrapped(value)    SendCtrlComnd(((value&0xFF00)<<2) | ((value&0x00FF)<<1) )

#define SendDataComndWrapped(value)  SendDataComnd(((value&0xFF00)<<2) | ((value&0x00FF)<<1) )

      另補充:以上寫控制指令和指令參數都是16位的,是以在18位資料線和16位資料線上要考慮時序。如果控制指令和參數都是8位的,則不需考慮這個過程,也即直接用:

#define SendCtrlComndWrapped(value)   SendCtrlComnd(value&0xff)

#define SendDataComndWrapped(value)  SendDataComnd(value&0xff)

(3)關于配新屏的過程。

      大部分的LCM模組隻需要處理好四個函數就可以了。初始化,進入睡眠,喚醒睡眠,寫GRAM。都是通過一系列寄存器語句來實作的,比如對于OTM4001A,典型的語句是:

SendCtrlComndWrapped(0x0200);SendDataComndWrapped(0x0000);

      其它典型的要補充的是:初始化時要在寫GRAM前設定RAM ADDR參數、起始終結的水準垂直位置、Display ON、Write Start;喚醒和睡眠都是有特定的sleep寄存器來控制的,喚醒後可以再把初始化執行一次就可以了。

(4)關于RGB565向RGB666轉化

       寫GRAM的本質就是向不同位址寫入對應的點陣顔色的資料,而每個顔色點的格式可能有16位或者18位。如果是單點16位的點陣格式,采用在位址自加的同時,執行WriteHwDataAddrWrapped( color );如果是18位的格式,除了在配置時要改成18位和RGB666格式外,在循環寫入顔色資料時需要一個轉換:

UINT16  color;                  //16位顔色值存儲單元

UINT32  rgb666;              //18位顔色值存儲單元

UINT32  panelX, panelY;

UINT16  x0, y0, x1, y1;

x0 = (UINT16)rc.left;

y0 = (UINT16)rc.top;

x1 = (UINT16)rc.right-1;

y1 = (UINT16)rc.bottom-1;     //起始終結坐标

for (panelY = y0; panelY <= y1; panelY++)

{

        for (panelX = x0; panelX <= x1; panelX++)

        {

            color = pFB[pixelIndex++];

            rColor  = ((color & 0xF800) >> 10);

            gColor  = ((color & 0x07E0) >>  5);

            bColor  = ((color & 0x001F) <<  1);

            rgb666  = ((rColor << 12) | (gColor << 6) | (bColor));    //RGB565轉成RGB666

            WriteHwDataAddrWrapped( rgb666 );

        }

 }

(5)關于圖像傾斜。如果一個圖像出現一個對角線,整體傾斜,那麼可以考慮是多寫了資料或是少些了資料。我的改動方法是一定要注意矩形視窗坐标是0到WIDTH-1,和0到HEIGHT-1。如果沒有減去1,則會出現此問題。

(6)關于讀晶片的ID号

      很多晶片的ID都是0X0000寄存器的值,不需要發讀出指令。是以隻要在讀資料前把寄存器的位址0X0000寫進去,就可以讀到正确的ID。6516提供的指令如下:

VOID LCDReadDataCommand(void )

{

        UINT32 data;

        LCD_OUTREG32(PARALLEL[s_pLCDParams->m_ifIndex].CONTROL, 0x0000);   //寫索引位址0X0000

        data = LCD_INREG32(PARALLEL[s_pLCDParams->m_ifIndex].DATA);

        SHIPMSG(2,(L"Read lcd id is : 0x%x  /r /n",data));

}

直接把該函數放到初始化開始就可以了。

      實際調試R61509V的代碼時,讀得的ID号是0x2d412。而晶片規格書上的0XB509,不一緻。後來想了一下,由于是18位的接口,對于指令來說,讀和寫都要跳過第零位和第九位。是以把0x2d412處理一下後就是0XB509。

(7)關于TE(tearing effect)現象

      TE現象的表現在于刷屏時有拖尾殘留,起因在于主要發送GRAM的速率與LCM刷屏的速率不一緻。主要是刷屏速率太快而主要送GRAM資料太慢,導緻刷屏重新整理的資料時,GRAM的資料還沒有送到,是以刷的還是老舊的資料。用FMARK可以解決此問題,否則就要手動調節兩邊一緻才行。一般也可以降低屏的重新整理速度來解決,但是降低太多容易出現FLICKER現象。

      關于TE,還做過如下實驗:

A,在屏初始化加TE和使能AP的TE情況下,片選信号CS跟FMARK信号都有波形,圖像重新整理;

B,在屏初始化屏蔽TE和使能AP的TE情況下,FMARK信号是沒有,因為屏沒有發出,CS是沒有的,因為AP沒有TE收到不工作,圖像靜止;

C,在屏初始化屏蔽TE和屏蔽AP的TE情況下,FMARK信号是沒有,因為屏沒有發出,CS是有的,AP不需要TE也能工作,圖像重新整理;

        綜上,屏和AP端的TE功能,要麼都開,要麼都關。在上述B情況中,碰到過手機開機UB階段無圖像但是進入核心後又有圖像,原因不明。

(8)關于開機雪花屏或者閃白屏的解決

        在開機的時候,有時會出現雪花樣的彩點或者閃白屏,造成這種原因的可能性有兩點。一是晶片初始化的時間慢于背光上電的時間,在LCD還沒有正常工作的時候,背光已經亮了就會造成這種現象,解決方法是調整兩者之間的延時關系(喚醒螢幕時有延遲也是類似原因,縮短延時讓晶片盡快工作就行);二是LCD初始化完畢後,AP送資料的速度太慢了,導緻空的FrameBuffer映射到LCD上也會出現這種彩點畫面,解決方法是在LCD初始化之後加上刷黑屏的函數,就可以掩蓋此現象。舉個刷黑屏的例子:

sw_clear_panel(0x00000);

原型是

static void sw_clear_panel(unsigned int color)

        unsigned int x0 = 0;

        unsigned int y0 = 0;

        unsigned int x1 = x0 + FRAME_WIDTH - 1;

        unsigned int y1 = y0 + FRAME_HEIGHT - 1;

        unsigned int x, y;

        send_ctrl_cmd(0x2A);                           //X座标域

        send_data_cmd(HIGH_BYTE(x0));

        send_data_cmd(LOW_BYTE(x0));

        send_data_cmd(HIGH_BYTE(x1));

        send_data_cmd(LOW_BYTE(x1));

        send_ctrl_cmd(0x2B);                          //Y座标域

        send_data_cmd(HIGH_BYTE(y0));

        send_data_cmd(LOW_BYTE(y0));

        send_data_cmd(HIGH_BYTE(y1));

        send_data_cmd(LOW_BYTE(y1));

        send_ctrl_cmd(0x2C);    // send DDRAM set

        for (y = y0; y <= y1; ++ y)

               for (x = x0; x <= x1; ++ x)

               {

                        lcm_util.send_data(color);   //刷色

              }

        }

}

        還碰到另一種開機有幹擾紋現象:開機時螢幕有橫的閃爍幹擾線,過了UBOOT階段之後就沒有了。後來經過示波器測試發現,是屏的VCC供電存在電壓不穩的幹擾所導緻的,到核心後就穩定了。同樣碰到過接上UART口後電流會回灌到CPU晶片上,導緻手機開機異常的現象。

        另一種出現開機雪花屏的原因是:18位的LCM,如果初始化序列用的16位就會出現花屏。如果丢的2位是低兩位,一般還是會有圖像的;如果丢掉的是高兩位的資料,那麼會出現花屏。

        開機白屏有個情況是:輕按下電源鍵不開機,LCD就會閃爍一個輕微的白屏,這是硬體電路中導緻的,因為這個時候程式是還沒有運作的,無法從開機初始化來解決這個問題。其實這個問題的根本原因如下:

輕觸POWER鍵時BL_PWM會有一個脈沖,直接給到背光IC,導緻屏閃。通過測試時序發現LPSTB這個複位腳和屏供電是一起上電的,在LPSTB為高又不處于複位(低複位)的情況下,BL_PWM是有可能會輸出某些波形的。是以解決這個問題的方法是:一可以通過軟體使LPSTB在輕觸這個時間内不變高,始終為低,使LCD驅動處于複位的可控狀态;二是可以硬體方式使LPSTB在輕觸時上電緩慢甚至不上電。

         背光由MTK系統的PWM控制,碰到開機會閃白屏,但是系統睡眠後喚醒和開機執行的是一模一樣的内容,喚醒卻不會白屏。說明問題不在屏參的初始化中,做個實驗在開機初始化中加延時,無論延時多久,等到出LOGO時都會閃白屏。最後發現問題出來LK中,在LK的platform中将開背光的位置往後放就解決問題了。為什麼有的屏有這個問題有的屏沒有?答案是跟屏的特殊性有關,有些屏在buffer 沒有内容時顯示的是白屏,有些屏在buffer 沒有内容時顯示的是黑屏;在platform init 的函數裡,開背光的時間點過早,在show logo 之前就會導緻開背光時無内容可顯示,如果恰好是預設白屏的這種屏,就會閃一下白屏。 

(9)圖像反轉

        平時調LCD驅動時,有時需要對圖像反轉處理。一個思路在重新整理函數中緩存顔色資料,将像素逆序後再輸出。更簡單的做法是直接用寄存器設定。參數如下圖:

調試OTM4001A液晶驅動的一點心得

圖像的具體旋轉可以根據行列的掃描方向及像素的起始設定位址來實作。

(10)關于刷屏,開屏,開背光三者的關系

        為了保證液晶顯示器件在開機和關機時有正常的無瑕疵的顯示,一般要遵循嚴格的信号順序。對于刷屏資料、開屏電壓、開屏背光三者的關系,開機時要做到刷屏資料-》開屏電壓-》開背光,這樣是保證資料準備好之後再顯示背光,避免畫面有瑕疵;關機時則要做到相反,即關背光-》關屏電壓-》關屏資料,做到資料撤出是在背光滅掉之後。

        對于手機充電畫面這種動态的刷屏顯示。目前我見到的有兩種做法:

A,始終處在一個循環中,每個循環隻刷一幅圖。這樣的話,需要一直有個刷圖-》開屏電壓-》開背光的流程。如以下:

#define BATTERY_BAR  25

while(1)

      g_prog_temp = (g_bat_volt_check_point/BATTERY_BAR) * BATTERY_BAR;   //從電壓百分比擷取電壓顯示檔位,注意隻有四檔,處于五個圖檔間隔中

      mt65xx_disp_show_battery_capacity(g_prog);   //刷屏資料

      g_prog += BATTERY_BAR;

      if (g_prog > 100)

              g_prog = g_prog_temp;    //如滿,則再從目前電壓檔開始

      mt65xx_disp_power(KAL_TRUE);   //開屏

      g_bl_switch_timer++;             //逾時計數器

      mt6573_sleep(100, KAL_TRUE);   

      mt65xx_backlight_on();                       //開背光

      if (g_bl_switch_timer > BL_SWITCH_TIMEOUT)      //如果逾時則熄滅顯示

      {

               g_bl_switch_timer = 0;           //計數器清零

               mt65xx_backlight_off();          //關背光

               mt65xx_disp_power(KAL_FALSE);         //關屏

       }

B,在一個函數段中就完成顯示多幅圖檔,不需要循環。如下:

mt65xx_disp_show_low_batteryThunderYes();    //顯示第一幅圖

mt6573_sleep(100, KAL_TRUE);

mt65xx_disp_power(KAL_TRUE);                          //開屏

mt65xx_leds_brightness_set(6, 10);                     //開背光,之後就不需要再開屏開背光了

mt65xx_disp_wait_idle();

mt6573_sleep(1000, KAL_TRUE);

mt65xx_disp_show_low_batteryThunderNo();     

mt6573_sleep(1000, KAL_TRUE); 

mt65xx_disp_show_low_batteryThunderYes();     

mt65xx_disp_wait_idle();      

mt6573_sleep(1000, KAL_TRUE);

mt65xx_disp_power(KAL_FALSE);          //關屏

mt65xx_backlight_off();                               //關背光

如上,僅在顯示第一幅圖後開屏開背光,之後就不需要控制。需要注意的是該操作不能放後面,不然會出現後來的畫面覆寫前面的畫面,待背光亮時已經看不到前面的圖檔。

(11)adb reboot會閃白屏的問題

          碰到一種現象:開機不會閃白屏,用CMD執行adb reboot時則會閃白屏。兩者的差別是前者有掉電,後者沒有掉電。解決這個問題的方法是:在幀緩沖驅動的關閉函數内關FB的語句前,加上關背光的語句,這樣即可保證FB在背光滅之後無論什麼圖像都對使用者不可見。

(12)關機充電時畫面滅時有白屏

繼續閱讀