【學習筆記】圖解LCD硬件原理 && 調色板與Framebuffer原理 && 根據S3C2440數據手冊設置對應寄存器

001LCD硬件原理

LCD操作原理

在這裏插入圖片描述

  • LCD屏幕上的點稱爲像素
  • 屏幕後面有電子槍【紅綠藍】:一邊移動,一邊發出顏色
  • 每來一個clk移動一個像素
  • R、G、B三線確定顏色
  • 接收到HSYNC(水平同步信號)脈衝,電子槍從最右邊跳到最左邊。(跳到下一行)
  • 接收到VSYNC[垂直同步信號]最下邊跳到最上邊。(跳到原點)

LCD時序圖

在這裏插入圖片描述

LCD硬件原理圖

在這裏插入圖片描述

006 LCD設置

打開LCD4.3芯片手冊,根據芯片手冊設置

在這裏插入圖片描述
在這裏插入圖片描述

2440_LCD時序圖

在這裏插入圖片描述

LCD display config

在這裏插入圖片描述

可以通過調整四邊黑框調整屏幕邊框

BPP(bit per pixel)

BPP:在FrameBuffer中每個像素佔據多少位

  • 硬件上LCD的BPP是確定的
    但是可以對LCD進行封裝
  • 16條線,每個像素佔16位數據,16BPP
    在這裏插入圖片描述

002 S3C2440_LCD控制器

功能:

  • 1.從內存中(FrameBuffer取出某個像素的數據

FrameBuffer的地址告訴LCD控制器,BPP,分辨率

  • 2.配合其他信號把數據發送給LCD:

時序告訴LCD控制器,設置引腳的極性

BLOCK DIAGRAM

16BPP

在這裏插入圖片描述

調色板[ palette]

  • 本質:內存
  • 16BPP中,本來用16bit表示1像素,也可用利用調色板,用8位表示;8BPP:僞彩色16/24BPP:真彩色

那麼當使用像素深度爲8pp時候,像素深度和我們的帶寬不一致,我們的顏色要用16位表示,如果直接用上肯定不可能,那我們就可以選擇用調色板,調色板中存放了256種16bpp的顏色,這時候我們color存放的就不是真實的顏色值了,而是存放的是調色板中256種顏色的索引,成線性關係一一對應,這樣我們大大減輕了系統的負擔。用16bpp還是8bpp這得取決實際情況,16bpp肯定比8pp清晰,但同時帶來的負荷也更加重。

  • 過程:FrameBuffer中8bit —> LCD控制器 —> 調色板中取16bit【用8bit作爲索引,取出真正的顏色】 —> LCD

003LCD編程_框架與準備

  • 目標:
  • 講解後續程序的框架
  • 準備一個支持NAND、NOR啓動的程序
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-pMYeoa9H-1580909221579)(en-resource://database/1932:1)]

在這裏插入圖片描述


在這裏插入圖片描述

定義結構體

  • 定義引腳極性結構體
typedef struct pins_polarity{
	int vclk;	/* normal:在下降沿獲取 */
	int rgb;	/* normal:高電平表示1 */
	int hsync;  /* normal:高脈衝 */
	int vsync;  /* normal:高脈衝 */

}pins_polarity,*p_pins_polarity;
  • 定義時序結構體
typedef struct time_sequence{
	/* 垂直方向 */
	int tvp;/* vysnc脈衝寬度 */
	int tvb;/* 上邊黑框,Vertical Back porch */
	int tvf;/* 下邊黑框,Vertical Front porch */

	/* 水平方向 */
	int thp;/* hysnc脈衝寬度 */
	int thb;/* 左邊黑框,Horizontal Back porch */
	int thf;/* 右邊黑框,Horizontal Front porch */
}time_sequence,*p_time_sequence;
  • 定義lcd參數結構體
typedef struct lcd_params{
	/* 引腳極性 */
	pins_polarity pins_pol;
	
	/* 時序 */
	pins_sequence time_seq;
	
	/* 分辨率,bpp */
	int xres;
	int yres;
	int bpp;
	
	/* framebuffer的地址 */
	unsigned int fb_base;

}lcd_params,*p_lcd_params;

004LCD_編程_抽象出重要結構體

結構體傳參

在這裏插入圖片描述

005LCD_LCD控制器

  • S3C2440_controller.c:根據S3C2440數據手冊,設置LCD控制器相關寄存器

引腳初始化

void jz2440_lcd_pin_init(void)
{
	/* 初始化引腳 : 背光引腳*/
	GPBCON &= ~0x3;
	GPBCON |= 0x01;
	
	/* 初始化引腳 : LCD專用引腳*/
	GPCCON = 0xaaaaaaaa;
	GPDCON = 0xaaaaaaaa;

	/* PWREN */
	GPGCON |= (3<<8);
}

LCDCON1

在這裏插入圖片描述

    /* [17 : 8] :clkval,VCLK = HCLK / [(CLKVAL+1) x 2]
	 *					9    = 100M/ [(CLKVAL+1) x 2] ,clkval = 4.5 = 5
	 * 					clkval = 100/vclk/2-1
	 * [6 : 5]0b11,TFT lcd
	 * [4:1]: bpp mode
	 * [0]  : LCD video output and the logic enable/disable.
	 */
	int clkval = (double)HCLK/plcdparams ->time_seq.vclk/2-1+0.5;
	int bppmode = plcdparams->bpp == 8 ? 0xb :\
				   plcdparams->bpp == 16 ? 0xc:\
				   0xd;  /* 0xd:24bpp */
	LCDCON1 = (clkval << 8) | (3<<5) | (bppmode<<1);

LCDCON2

    /* [ 31:24 ] :VBPD    = tvb - 1
	 * [ 23:14 ] :lineval = line - 1
	 * [ 13:6  ] :vfpd    = tvf - 1
	 * [  5:0  ] :vspw    = tvp - 1 
	 */
	LCDCON2 = ((plcdparams->time_seq.tvb - 1)<<24) | \
			  ((plcdparams->yres - 1 )<<14)           | \
			  ((plcdparams->time_seq.tvf - 1)<<6)    |\
			  ((plcdparams->time_seq.tvp - 1)<<0);

LCDCON3

在這裏插入圖片描述

      /* [ 25:19 ] :HBPD	= thb - 1
	   * [ 13:6  ] :HOZVAL	=- 1
	   * [	5:0  ] :HFPD	= thf - 1 
	   */
	  LCDCON3 = ((plcdparams->time_seq.thb - 1)<<19) | \
				((plcdparams->xres - 1 )<<8)		   | \
				((plcdparams->time_seq.thf - 1)<<0)    |\;

LCDCON4

在這裏插入圖片描述

  /* [ 7:0 ] :HSPD	= thp - 1
	   */
	  LCDCON4 = ((plcdparams->time_seq.thp - 1)<<0);

LCDCON5

在這裏插入圖片描述

        /* 用來設置引腳極性,設置16BPP,設置內存中像素存放的格式
	   * [12] : BPP24BL
	   * [11] : PRM565 , 1- 565
	   * [10] : INVVCLK,0 = The video data is fetched at VCLK falling edge
	   * [9]  : HSYNC 是否反轉
	   * [8]  : VSYNC 是否反轉
	   * [7]  : INVVD,rgb是否反轉
	   * [6]  : INVVDEN
	   * [5]  : INVPWREN
	   * [4]  : INVLEND
	   * [3]  : PWREN, LCD_PWREN output signal enable/disable
	   * [2]  : ENLEND
	   * [1]  : BSWP
	   * [0]  : HWSWP
	   */

	  pixelplace = plcdparams -> == 24 ? (0) |\
	  				plcdparams-> == 16 ? (1) |\
	  				(1<<1);  /* 8BPP */
	  LCDCON5 = (plcdparams->pins_pol.vclk <<10)   |\
	  			(plcdparams->pins_pol.rgb<<7)      |\
	  			(plcdparams->pins_pol.hsync<<9)    |\
	  			(plcdparams->pins_pol.vsync<<8)    |\
	  			(plcdparams->pins_pol.de<<6)       |\
	  			(plcdparams->pins_pol.pwren<<5)    |\
	  			(1<<11) | pixelplace ;

FrameBuffer地址設置

LCDADDR1

在這裏插入圖片描述

	/* 
	 * [29:21] : LCDBANK,A[30:22] of fb
	 * [20:0 ] : LCDBASEU,A[21:1] of fb
	*/
	addr = plcdparams->fb_base & (1<<31)
	LCDSADDR1 = (addr>>1) ;
LCDSADDR2

在這裏插入圖片描述

    /* 
	 * [20:0 ] : LCDBASEL,A[21:1] of end addr
	*/
	addr = plcdparams->fb_base + plcdparams->xres*plcdparams->yres*plcdparams->bpp/8;
	addr >>= 1;
	addr &= 0x1fffff;
	LCDSADDR2 = addr;

LCD硬件原理圖

在這裏插入圖片描述

006 LCD設置

打開LCD4.3芯片手冊,根據芯片手冊設置

在這裏插入圖片描述
在這裏插入圖片描述

#define LCD_FB_BASE 0x33c00000

lcd_params lcd_4_3_params = {
	.name = "lcd_4.3",
	.pins_polarity = {
		 .de    = NORMAL,       /* normal: 高電平時可以傳輸數據*/
		 .pwren = NORMAL, 		/* normal: 高電平有效 */
		 .vclk  = NORMAL,		/* normal: 在下降沿獲取 */
		 .rgb   = NORMAL,		/* normal:高電平表示1 */
		 .hsync = INVERT, 		/* normal:高脈衝 */
		 .vsync = INVERT,		/* normal:高脈衝 */
	},
	.time_sequence = {
		/* 垂直方向 */
		.tvp = 10,/* vysnc脈衝寬度 */
		.tvb = 2 ,/* 上邊黑框,Vertical Back porch */
		.tvf = 2 ,/* 下邊黑框,Vertical Front porc
		h */

		/* 水平方向 */
		.thp = 41, /* hysnc脈衝寬度 */
		.thb = 2,  /* 左邊黑框,Horizontal Back porch */
		.thf = 2,  /* 右邊黑框,Horizontal Front porch */

		.vclk = 9, /* MHZ */
	},
	.xres = 480,
	.yres = 272,
	.bpp = 16,
	.fb_base = LCD_FB_BASE,
}

硬件16BPP軟件上爲何可以使用24bpp

在這裏插入圖片描述

008 畫點線圓

FB基地址計算

在這裏插入圖片描述

unsigned int pixel_base = (unsigned int)(fb_base + (xres * bpp /8) * y + x * bpp / 8);

畫點畫線的基礎都是描點

#include "lcd.h"
/* 實現畫點 */

/* 獲得LCD參數 */

static unsigned int fb_base;
static int xres, yres, bpp;

void fb_get_lcd_params(void)
{
	get_lcd_params(&fb_base,&xres,&yres,&bpp);
}

/* rgb : 32 bit, 0x00RRGGBB */
unsigned short convert32bppto16bpp(unsigned int rgb)
{
	int r = (rgb>>16) & 0xff;
	int g = (rgb>>8)  & 0xff;
	int b =  rgb      & 0xff;

	/* rgb 565 */
	r = r >> 3;
	g = g >> 2;
	b = b >> 3;

	return((r<<11) | (g<<5) | (b));
}

/* color : 32bit , 0x00RRGGBB
 *
 */
void fb_put_pixel(int x,int y,unsigned int color)
{
	unsigned char *pc;   /* 8bpp */
	unsigned short *pw;  /* 16bpp */
	unsigned int *pdw;   /* 32bpp */

	unsigned int pixel_base = (unsigned int)(fb_base + (xres * bpp /8) * y + x * bpp / 8);
	
	switch(bpp)
	{
		case 8:
			pc = (unsigned char *)pixel_base;
			*pc = color;
			break;
		case 16:
			pw = (unsigned short *)pixel_base;
			*pw = convert32bppto16bpp(color);
			break;
		case 32:
			pdw = (unsigned int *)pixel_base;
			*pdw = color;
			break;
	}
}


畫點畫線座標

在這裏插入圖片描述

  • 先找一個畫點畫線的LCD函數複製下來
//-------------畫圓函數。參數:圓心,半徑,顏色----------
//1/8圓 然後其他7/8對稱畫
//          ---------------->X
//          |(0,0)   0
//          |     7     1
//          |    6       2
//          |     5     3
//       (Y)V        4
//
//      L = x^2 + y^2 - r^2
void draw_circle(int x, int y, int r, int color)
{
    int a, b, num;
    a = 0;
    b = r;
    while(2 * b * b >= r * r)          // 1/8圓即可
    {
        fb_put_pixel(x + a, y - b,color); // 0~1
        fb_put_pixel(x - a, y - b,color); // 0~7
        fb_put_pixel(x - a, y + b,color); // 4~5
        fb_put_pixel(x + a, y + b,color); // 4~3
 
        fb_put_pixel(x + b, y + a,color); // 2~3
        fb_put_pixel(x + b, y - a,color); // 2~1
        fb_put_pixel(x - b, y - a,color); // 6~7
        fb_put_pixel(x - b, y + a,color); // 6~5
        
        a++;
        num = (a * a + b * b) - r*r;
        if(num > 0)
        {
            b--;
            a--;
        }
    }
}
 
//-----------畫線。參數:起始座標,終點座標,顏色--------
void draw_line(int x1,int y1,int x2,int y2,int color)
{
    int dx,dy,e;
    dx=x2-x1; 
    dy=y2-y1;
    if(dx>=0)
    {
        if(dy >= 0) // dy>=0
        {
            if(dx>=dy) // 1/8 octant
            {
                e=dy-dx/2;
                while(x1<=x2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){y1+=1;e-=dx;}   
                    x1+=1;
                    e+=dy;
                }
            }
            else        // 2/8 octant
            {
                e=dx-dy/2;
                while(y1<=y2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){x1+=1;e-=dy;}   
                    y1+=1;
                    e+=dx;
                }
            }
        }
        else           // dy<0
        {
            dy=-dy;   // dy=abs(dy)
            if(dx>=dy) // 8/8 octant
            {
                e=dy-dx/2;
                while(x1<=x2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){y1-=1;e-=dx;}   
                    x1+=1;
                    e+=dy;
                }
            }
            else        // 7/8 octant
            {
                e=dx-dy/2;
                while(y1>=y2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){x1+=1;e-=dy;}   
                    y1-=1;
                    e+=dx;
                }
            }
        }   
    }
    else //dx<0
    {
        dx=-dx;     //dx=abs(dx)
        if(dy >= 0) // dy>=0
        {
            if(dx>=dy) // 4/8 octant
            {
                e=dy-dx/2;
                while(x1>=x2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){y1+=1;e-=dx;}   
                    x1-=1;
                    e+=dy;
                }
            }
            else        // 3/8 octant
            {
                e=dx-dy/2;
                while(y1<=y2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){x1-=1;e-=dy;}   
                    y1+=1;
                    e+=dx;
                }
            }
        }
        else           // dy<0
        {
            dy=-dy;   // dy=abs(dy)
            if(dx>=dy) // 5/8 octant
            {
                e=dy-dx/2;
                while(x1>=x2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){y1-=1;e-=dx;}   
                    x1-=1;
                    e+=dy;
                }
            }
            else        // 6/8 octant
            {
                e=dx-dy/2;
                while(y1>=y2)
                {
                    fb_put_pixel(x1,y1,color);
                    if(e>0){x1-=1;e-=dy;}   
                    y1-=1;
                    e+=dx;
                }
            }
        }   
    }
}
 

009顯示文字

字符顯示原理

在這裏插入圖片描述

顯示字符時,座標表示

在這裏插入圖片描述

void fb_print_char(int x, int y, char c,unsigned int color)
{
	int i,j;

	/* 根據c的asscii碼在fontdata_8x16中得到點陣數據 */
	unsigned char *dots = &fontdata_8x16[c *16];
	unsigned char data;
	int bit;


	/* 根據點陣來設置對應像素的顏色 */
	for(j = y; j < y+16; j++)
	{
		data = *data++;
		bit = 7;
		for(i = x; i < x+8; i++)
		{
			/* 根據點陣的某位決定是否描顏色 */
			if(data & (1<<bit))
				fb_put_pixel(i,j,color);
		}
	}
}

顯示字符串時,座標表示

在這裏插入圖片描述

010添加除法

對於未實現的函數:

  • a.去uboot中查找
  • b.去內核源碼中查找
  • c.去庫函數中查找 (一般來說編譯器自帶有很多庫)
    進入工具鏈的目錄:grep “__floatsisf” * -nr 找到.a文件

. a文件是靜態庫文件
. so文件時動態庫文件
注意:如果更換編譯器,需要自己去編譯器目錄裏找出對應的libgcc.a。可能有多個,逐個嘗試。

011使用調色板

在FB中每個象素佔8bit怎麼轉換成LCD所需要的16位數據

在調色板(0—255)中填入真正的16位的顏色

把LCD控制器設置成8bpp時,它回去FrameBuffer中取出一個象素的數據(8位),然後使用8位作爲索引,然後去調色板中取出真正的顏色,得到16位的數據;把這16位的數據發給LCD。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章