s5pv210——LCD的原理和实战
生活随笔
收集整理的這篇文章主要介紹了
s5pv210——LCD的原理和实战
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
以下內(nèi)容源于朱友鵬《物聯(lián)網(wǎng)大講堂》課程的學(xué)習(xí),以及博客http://www.cnblogs.com/biaohc/p/6286946.html的學(xué)習(xí),如有侵權(quán),請告知刪除。
一、S5PV210的LCD控制器
1、FIMD結(jié)構(gòu)框圖(P1162)
- 210的LCD控制器叫FIMD;
- FIMD是210內(nèi)部和圖像處理相關(guān)的一些部件,在攝像頭等和圖像處理有關(guān)的部分都可以有關(guān)聯(lián)。
- FIMD在內(nèi)部與AHB總線等相連接,在外部提供RGB接口、I80接口、YUV接口與外部相連接,我們實(shí)際使用的是RGB接口。
2、虛擬屏幕疊加(數(shù)據(jù)手冊P1194)
(1)虛擬屏幕
- 屏幕顯示的場景,實(shí)際是很多個屏幕顯示疊加在一起的效果(譬如新聞圖像、電視臺臺標(biāo)、下方飄動的字幕新聞);
- S5PV210的LCD控制器中有5個虛擬屏幕Window0到Window4,虛擬屏幕不存在于真實(shí)而存在于內(nèi)存中。
- LCD顯示時,顯示對應(yīng)的內(nèi)存中的顯存區(qū)域的數(shù)值。
- 虛擬屏幕其實(shí)就是一個內(nèi)存中的顯存區(qū)域,有幾個顯存區(qū)域就有幾個虛擬屏幕。
- 這些虛擬屏幕都被映射到一個真實(shí)的顯示屏上面,實(shí)際效果是這幾個虛擬屏幕的顯示內(nèi)容的疊加。
- 疊加時,上面一層會覆蓋下面一層,因此要注意誰在前誰在后,通過相關(guān)寄存器進(jìn)行設(shè)置。
- 第一,可以保證不污染源圖像,方便程序處理;
- 第二,可以減少屏幕刷新,提高顯示效率,減少CPU工作量。
3、虛擬顯示(數(shù)據(jù)手冊P1206)
(1)解決如何實(shí)現(xiàn)在小分辨率的屏幕上(真實(shí)地,即不允許修改分辨路)顯示大分辨率的圖像?
(2)按照以前的思想,當(dāng)需要在屏幕上顯示不同圖像時,需要對整個顯存區(qū)域進(jìn)行刷新。
- 即使是顯示同一幅圖像的不同區(qū)域(比如只需要屏幕顯示移動一點(diǎn)點(diǎn)),整個屏幕對應(yīng)的顯存空間也需要整個重新刷新,工作量和完全重新顯示一幅圖像是一樣的。
- 這使得CPU刷新屏幕的工作量很大,效率很低。
(3)如何能夠在顯示一個大圖片的不同區(qū)域時,讓CPU刷新屏幕工作量減少?
- 方法是,虛擬顯示。
- 在內(nèi)存中建立顯示緩存時,建立一個很大的區(qū)域,直接將大圖像全部一次性加載入顯示緩存區(qū)(這樣就可以只加載一次);
- LCD選擇其中的一部分區(qū)域作為有效的顯示區(qū)域;
- 通過移動有效顯示區(qū)域就可以顯示大圖像的不同區(qū)域了。
4、主要寄存器簡介
(1)DISPAY_CONTROL寄存器:設(shè)置為10或11,即RGB模式可行。
(2)VIDCON0寄存器(Video Main Control 0 Register)
- bit0,bit1:為使能控制信號都使能;
- bit2:選擇時鐘源,選HCLK,連的是HCLC_DSYS 為166MHz;
- bit4:開啟分頻;
- bit13-6:設(shè)置時鐘大小,時鐘頻率要小于控制器的最大時鐘,也要小于LCD驅(qū)動器的最大時鐘。
- bit18:設(shè)置RGB數(shù)據(jù)傳輸為并行還是串行,因?yàn)橛?4根數(shù)據(jù)線所以為并行;
- bit28-26:選擇為RGB模式。
- bit5,bit6:設(shè)置HSYNC和VSYNC的極性,如果LCD的高低電平脈沖是相同的話,則Normal,如果極性相反則Invert。
(4)WINCONn(n=0~4)寄存器
- bit0:使能window0 ;
- bit5-2:選擇RGB888模式;
- bit15:設(shè)置輸出順序?yàn)?red green blue還是 blue green red,設(shè)置為1時BGR,設(shè)置為0時RGB。
- 用來設(shè)置內(nèi)存中window0的大小;
- 比如設(shè)置為LCD屏幕的尺寸,即左上坐標(biāo)為(0,0),右下坐標(biāo)為(1023,767)。
(6)VIDOSD0A寄存器
- 也是設(shè)置內(nèi)存中window0的大小,比如設(shè)置為LCD屏幕的尺寸=1024*768。
- VIDW0xADD0Bx寄存器,設(shè)置內(nèi)存中window0的起始地址;
- VIDW0xADD1Bx寄存器,設(shè)置內(nèi)存中window0的結(jié)束地址。
5、底板、核心板解讀
二、代碼實(shí)戰(zhàn)
#define GPF0CON (*(volatile unsigned long *)0xE0200120) #define GPF1CON (*(volatile unsigned long *)0xE0200140) #define GPF2CON (*(volatile unsigned long *)0xE0200160) #define GPF3CON (*(volatile unsigned long *)0xE0200180)#define GPD0CON (*(volatile unsigned long *)0xE02000A0) #define GPD0DAT (*(volatile unsigned long *)0xE02000A4)#define CLK_SRC1 (*(volatile unsigned long *)0xe0100204) #define CLK_DIV1 (*(volatile unsigned long *)0xe0100304) #define DISPLAY_CONTROL (*(volatile unsigned long *)0xe0107008)#define VIDCON0 (*(volatile unsigned long *)0xF8000000) #define VIDCON1 (*(volatile unsigned long *)0xF8000004) #define VIDTCON2 (*(volatile unsigned long *)0xF8000018) #define WINCON0 (*(volatile unsigned long *)0xF8000020) #define WINCON2 (*(volatile unsigned long *)0xF8000028) #define SHADOWCON (*(volatile unsigned long *)0xF8000034) #define VIDOSD0A (*(volatile unsigned long *)0xF8000040) #define VIDOSD0B (*(volatile unsigned long *)0xF8000044) #define VIDOSD0C (*(volatile unsigned long *)0xF8000048)#define VIDW00ADD0B0 (*(volatile unsigned long *)0xF80000A0) #define VIDW00ADD1B0 (*(volatile unsigned long *)0xF80000D0)#define VIDTCON0 (*(volatile unsigned long *)0xF8000010) #define VIDTCON1 (*(volatile unsigned long *)0xF8000014)#define HSPW (0) #define HBPD (40 - 1) #define HFPD (5 - 1) #define VSPW (0) #define VBPD (8 - 1) #define VFPD (8 - 1)// FB地址 #define FB_ADDR (0x23000000) //這個是任意的,只要對齊就好 #define ROW (480) #define COL (800) #define HOZVAL (COL-1) #define LINEVAL (ROW-1)// 初始化LCD void lcd_init(void) {// 配置引腳用于LCD功能/**LED、LCD、蜂鳴等,都是與gpio口有關(guān)的*因此,涉及這些器件的,都需要初始化gpio口*而初始化gpio,需要用到相關(guān)的配置寄存器,比如GPIOCON寄存器控制引腳的模式*而至于配置哪個GPIO,需要看原理圖。*這里從原理圖知LCD接到gpf0123,所以要到相應(yīng)的配置寄存器中進(jìn)行配置*/GPF0CON = 0x22222222;GPF1CON = 0x22222222;GPF2CON = 0x22222222;GPF3CON = 0x22222222;// 打開背光 GPD0_0(PWMTOUT0)/**由原理圖可知,當(dāng)PWMTOUT0接低電平時,正5V電壓加到背光上,也就打開了背光燈*而查閱PWMTOUT0可知,它就是GPD0_0這個引腳*把GPD0_0這個引腳配置為輸出模式,通過GPD0CON寄存器配置*然后配置GPD0_0這個引腳輸出值為0,通過GPD0DAT寄存器配置*/GPD0CON &= ~(0xf<<0);GPD0CON |= (1<<0); // output modeGPD0DAT &= ~(1<<0); // output 0 to enable backlight// 10: RGB=FIMD I80=FIMD ITU=FIMD//由上面寄存器的分析可知,這里可以設(shè)置為10DISPLAY_CONTROL = 2<<0;// bit[26~28]:使用RGB接口// bit[18]:RGB 并行// bit[2]:選擇時鐘源為HCLK_DSYS=166MHzVIDCON0 &= ~( (3<<26)|(1<<18)|(1<<2) );// bit[1]:使能lcd控制器// bit[0]:當(dāng)前幀結(jié)束后使能lcd控制器VIDCON0 |= ( (1<<0)|(1<<1) );// bit[4]:選擇需要分頻// bit[6~13]:分頻系數(shù)為15,即VCLK = 166M/(14+1) = 11M,那么bit[6~13]=14;VIDCON0 |= 14<<6 | 1<<4;//屏幕有的是高電平脈沖提示開始,有的是低脈沖提示開始// H43-HSD043I9W1.pdf(p13) 時序圖:VSYNC和HSYNC都是低脈沖提示開始// s5pv210芯片手冊(p1207) 時序圖:VSYNC和HSYNC都是高脈沖提示開始,所以需要反轉(zhuǎn)VIDCON1 |= 1<<5 | 1<<6;// 設(shè)置時序VIDTCON0 = VBPD<<16 | VFPD<<8 | VSPW<<0;VIDTCON1 = HBPD<<16 | HFPD<<8 | HSPW<<0;// 設(shè)置長寬(這里設(shè)置的是物理尺寸)VIDTCON2 = (LINEVAL << 11) | (HOZVAL << 0);// 設(shè)置windows0// bit[0]:使能// bit[2~5]:24bppWINCON0 |= 1<<0;WINCON0 &= ~(0xf << 2);//先清零WINCON0 |= (0xB<<2) | (1<<15);//再設(shè)置#define LeftTopX 0 #define LeftTopY 0 #define RightBotX 479 #define RightBotY 271// 設(shè)置windows1的上下左右//這里設(shè)置的是顯存空間的大小,可以比屏幕大。//這里設(shè)置和物理屏幕一樣大VIDOSD0A = (LeftTopX<<11) | (LeftTopY << 0);VIDOSD0B = (RightBotX<<11) | (RightBotY << 0);VIDOSD0C = (LINEVAL + 1) * (HOZVAL + 1);// 設(shè)置fb的地址VIDW00ADD0B0 = FB_ADDR;//這個可以任選的,但必須對齊(比如按照1M對齊)//每個像素點(diǎn)3個字節(jié)(24bit的bpp)就可以了的,但是為了對齊,用了4字節(jié)。VIDW00ADD1B0 = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);//上述兩句表明了一個屏幕占用的空間大小// 使能channel 0傳輸數(shù)據(jù)SHADOWCON = 0x1; }// 描點(diǎn) void lcd_draw_pixel(int row, int col, int color) {unsigned long * pixel = (unsigned long *)FB_ADDR;*(pixel + row * COL + col) = color;//假設(shè)像素點(diǎn)坐標(biāo)為(row,col),則該像素點(diǎn)在內(nèi)存中的位置計算方法如下//有一個基地址,pixel(這里是一個指針,注意它是指針,加1會加上4個字節(jié))//偏移量=每行多少個像素*有多少行*每個像素占用多少個字節(jié)+col個像素*每個像素多少字節(jié)// COL * row * 4 + col * 4//那么所處的位置應(yīng)該是(int)pixel+COL*row*4 + col * 4//或者簡單地寫成 pixel + row * COL + col }// 清屏 void lcd_clear_screen(int color) {int i, j;for (i = 0; i < ROW; i++)for (j = 0; j < COL; j++)lcd_draw_pixel(i, j, color);}// 劃橫線 void lcd_draw_hline(int row, int col1, int col2, int color) {int j;// 描第row行,第j列for (j = col1; j <= col2; j++)lcd_draw_pixel(row, j, color);}// 劃豎線 void lcd_draw_vline(int col, int row1, int row2, int color) {int i;// 描第i行,第col列for (i = row1; i <= row2; i++)lcd_draw_pixel(i, col, color);}// 劃十字 void lcd_draw_cross(int row, int col, int halflen, int color) {lcd_draw_hline(row, col-halflen, col+halflen, color);lcd_draw_vline(col, row-halflen, row+halflen, color); }三、顯示內(nèi)容
1、首先必須清屏;
2、顯示點(diǎn)、線;
3、顯示英文字符;
(1)每個英文字符,占用16*8個像素,如果單色顯示,則每個像素占1bit,則每個英文字符是16Byte。 (2)字模。要想得到顯示,必須先取“模”(知道該字符的字模),然后填充即可。 (3)代碼示例 // 寫字 // 寫字的左上角坐標(biāo)(x, y),字的顏色是color,字的字模信息存儲在data中 static void show_8_16(unsigned int x, unsigned int y, unsigned int color, unsigned char *data) { // count記錄當(dāng)前正在繪制的像素的次序int i, j, count = 0; for (j=y; j<(y+16); j++) { for (i=x; i<(x+8); i++) { if (i<XSIZE && j<YSIZE) { // 在坐標(biāo)(i, j)這個像素處判斷是0還是1,如果是1寫color;如果是0直接跳過if (data[count/8]/*表示一個字模中(16行,每行8個像素)的第幾行(每行8bit)*/ & (1<<(count%8))/*表示該行的第幾bit*/) lcd_draw_pixel(i, j, color);} count++; } } } // 寫字符串 // 字符串起始坐標(biāo)左上角為(x, y),字符串文字顏色是color,字符串內(nèi)容為str void draw_ascii_ok(unsigned int x, unsigned int y, unsigned int color, unsigned char *str) {int i; unsigned char *ch;for (i=0; str[i]!='\0'; i++) { ch = (unsigned char *)ascii_8_16[(unsigned char)str[i]-0x20];show_8_16(x, y, color, ch); x += 8;if (x >= XSIZE){x -= XSIZE; // 回車y += 16; // 換行}} }4、顯示中文字符;
5、顯示圖像
(1)之前都是單色的,每個像素點(diǎn)用一個bit(單色顯示時),像素點(diǎn)不是0就是1;而圖像是彩色的,每個像素點(diǎn)占用4字節(jié)(RGB888時),像素點(diǎn)情況很多。 (2)需要取模。使用軟件image2LCD。知道RGB順序的含義,知道生成的步驟即可(一般設(shè)置輸出的和屏幕實(shí)際大小一樣)。 (3)代碼// 畫800×480的圖,圖像數(shù)據(jù)存儲在pData所指向的數(shù)組中 void lcd_draw_picture(const unsigned char *pData) {u32 x, y, color, p = 0;for (y=0; y<480; y++){for (x=0; x<800; x++){// 在這里將坐標(biāo)點(diǎn)(x, y)的那個像素填充上相應(yīng)的顏色值即可color = (pData[p+0] << 0) | (pData[p+1] << 8) | (pData[p+2] << 16);lcd_draw_pixel(x, y, color);p += 3;//注意這里的p不是指針,而是int數(shù)。由于RGB888,三個一組,所以下一個像素是p+3}} } (4)這樣處理得到的bin大于16KB,所以需要分成BL1,BL2部分。
- 引用chapter10的分割方法,詳見chapter14\6.LCD目錄下的內(nèi)容。
- 最后使用燒錄腳本(./write2sd),不能使用windows里的燒錄工具。
#!/bin/sh sudo dd iflag=dsync oflag=dsync if=./BL1/BL1.bin of=/dev/sdb seek=1 sudo dd iflag=dsync oflag=dsync if=./BL2/BL2.bin of=/dev/sdb seek=45
(5)補(bǔ)充
- bmp格式是原始圖像,沒有經(jīng)過壓縮?因此可以直接使用image2LCD軟件解釋成數(shù)據(jù)。
- jpg、png、gif等壓縮的不可以直接用image2LCD解釋。需要先用對應(yīng)的解壓縮庫對其解壓縮,才能使用image2LCD軟件?
總結(jié)
以上是生活随笔為你收集整理的s5pv210——LCD的原理和实战的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三菱plc基本指令
- 下一篇: 汇编指令的学习1——ARM汇编的特点