三十八.进入自己的控制台LCD

1.ARM系统中LCD体系架构


其中LCD驱动芯片和LCD显示器是连接在LCD模块上的,而LCD控制器则是在ARM处理器上的。

2.液晶工作原理:
液晶分子为长棒子状,通过分子的电流不一样, 他们会发生不同程度的偏转,从而对背光灯的光线产生不同程度的反射和折射,进而使得显示的像素呈现出不同的色彩。每个分子对应一个像素,很多像素构成一幅图像。

3.液晶屏分类:常见的有STN的,就是玩单片机用到的12864还有1602等,以及GF,而我们现在说的大都是TFT的。


4.LCD驱动芯片:为液晶分子的偏转提供电压,从而达到控制LCD的效果。相当于神经网络。

5.LCD控制器:为LCD驱动芯片提供必要的数据和控制信号。这是相当于大脑,LCD显示器就相当于器官。REGBANK里有寄存器组,调色板内存。LCDCDMA则是用来控制帧缓存(内存)里的数据到LCD显示器,不需要CPU干预。VIDPRCS则是像素数据,TIMEGEN则是控制时序的,与REGBANK密切相关。

6.显示过程


7.时序信号


8.各信号含义:

9.简要概括

10.引脚初始化,找到原理图VD对应的引脚,然后在datasheet里面找到相应的GPIO寄存器区写入初值,让这些引脚工作在LCD数据传输模式。

11时序初始化:
(1)找出需要初始化什么时序信号
(2)找到初始化这些信号的寄存器(LCDCON1,LCDCON2,LCDCON3,LCDCON4)
(3)根据datashhet确定初始化的值


12.帧缓冲初始化:
(1)分配空间,分辨率的两倍,每个像素用两个字节来描述。一般静态分配,用二维数组来分配,数组元素类型是描述颜色的位数对应的类型。但不一定是两倍,即不是只能用16位描述一个像素,位数越多颜色越丰富。

(2)告知地址:由DMA来搬运数据,不需要CPU干预。所以DMA首先要知道数据在内存中的地址,即帧缓存。(LCDSADDR1,2,3)起始地址,结束地址,是否间隔,多少半字单位。


13.杂项初始化:
(1)选择什么屏
(2)选择控制像素的位数
(3)是否打开LCD
(4)选择颜色控制格式(LCDCON5)
(5)选择所用LCD的HSYNC以及VSYNC的极性,即是否选择反转。默认三星的是高电平的极性。(LCDCON5)
(6)打开半字转换(LCDCON5),后来我发现打不打开都可以,这里表示有疑问???
(7)关闭临时调色板(TPAL)
(8)打开电源引脚功能(LCD_PWR,引脚复用,LCDCON5打卡电源允许)
(9)使能LCD控制器(LCDCON1)

14.画点函数:
(1)定义坐标,与帧缓存里面的数组的行列注意对应关系。
(2)颜色转换。根据datasheet将24位转换为16为数据,再赋值。
(3)建议大家初始化的时候不要使能LCD的数据输出,不然会花屏,建议大家用这个画点的思想,在最初上电的时候,进行一个清屏操作,根据自己想要的颜色来做。虽然老师说过这种方法比较傻,不如调色板好用,但是我试验了,用调色板清屏以后就不能在画图,具体原因还没弄清楚。所以为了避免一开机就花屏,建议大家用循环的方式不断往帧缓存里面写入相同的颜色值。这里不是纯粹的调用画点函数,那样的话效率很低,每次都要做移位运算。建议这样写,会加速清屏时间。
void lcd_clear_init(U32 color)
{
	U32 x,y;
	U32 red,green,blue;
	U16 temp;
	red = ((color >> 19) & 0x1f);
	green = ((color >> 10) & 0x3f);
	blue = ((color >> 3) & 0x1f);
	
	temp = (U16)((red << 11) | (green < 5) | blue);
	
	for(y = 0;y < 272;y++){
		for(x = 0;x < 480;x++)
			buf[y][x] = temp;	
	}
}


15.画线画图:利用画点函数,学会使用取模软件,单色显示要用到调色板(TPAL)。
我想实现一个函数,在任意两点之间画一条直线,但是由于像素是一个个小方格,不是直接连起来的圆点,目前还未实现,希望大家提出想法一起探讨。争取找一个好算法。

16.我用mini2440板子,用的tq4.3的液晶,不是迷你自带的LCD 
代码如下:
(1)宏定义和全局变量定义部分
#define VSPW 		9
#define VBPD 		1
#define LINEVAL 	271
#define VFPD 		1
#define HSPW 		40
#define HBPD 		1
#define HOZVAL 		479
#define HFPD 		1
#define CLKVAL		4 

#define U32		unsigned int 
#define U16		unsigned short 
#define U8		unsigned char 

unsigned short buf[272][480];

这些参数是根据这张表和时序信号图以及LCDCON1的描述得到的




(2)引脚初始化
void lcd_port_init()
{
	GPCCON = 0xAAAAAAAA;
	GPDCON = 0xAAAAAAAA;
}

(3)时序初始化
void lcd_time_init()
{
	LCDCON1 = (CLKVAL<<8);
	LCDCON2 = (VBPD << 24)| (LINEVAL << 14) | (VFPD << 6) | (VSPW);
	LCDCON3 = (HBPD << 19) | (HOZVAL << 8) | (HFPD << 0);
	LCDCON4 = (HSPW << 0);	
}

(4)帧缓存初始化
void lcd_frame_init()
{
	LCDSADDR1 = ((U32)(((U32)buf >> 22)<<21)) | ((U32)(((U32)buf >> 1) & 0x1fffff) << 0);
	LCDSADDR2 = (U32)(((((U32)buf + 272*480*2) >> 1) & 0x1fffff) << 0);
	LCDSADDR3 = ((U32)(0 <<11)) | ((U32)(480<<0));
}
(5)杂项初始化
void lcd__others_init()
{
	LCDCON1 |= (3 << 5) | (0xc << 1) | (0 << 0);
	LCDCON5 = (1 << 11) | (1 << 9) | (1 << 8) | (1 << 0);
	TPAL = 0;
	
	GPGCON |=  (3 << 8);
	LCDCON5 |= (1 << 3);
	LCDCON1 |= (1 << 0);
	
}

(6)总的初始化
void lcd_init()
{
	lcd_port_init();
	lcd_time_init();
	lcd_frame_init();
	lcd__others_init();
	lcd_clear_init(0x0000CD);
	Delay(500000);	
}

(7)画点函数
void lcd_point(U16 x, U16 y,U32 color)
{
	U32 red,green,blue;
	red = ((color >> 19) & 0x1f);
	green = ((color >> 10) & 0x3f);
	blue = ((color >> 3) & 0x1f);
	
	buf[y][x] = (U16)((red << 11) | (green < 5) | blue);
	
}

(8)用调色板清屏函数
void lcd_clear(U32 color)
{
	TPAL = 	(1<<24)|(color&0xffffff);
}

(9)画”十字架“函数
void lcd_line()
{
	U32 x,y;
	
	for(x = 0; x < 480;x++){
		lcd_point(x,136,0xFF0000);		
	}
	for(y = 0; y < 272;y++){
		lcd_point(240,y,0x54FF9F);		
	}
}


(10)画一张预存好的图片函数
extern const U8 pic[85928];
void lcd_picture(U16 x_start,U16 y_start,U16 x_size,U16 y_size,const U8* pic)
{
	U32 y = 0,x = 0;
	U16 temp = 0;
	U32 p = 0;
	
	for(y = y_start; y < y_start + y_size;y++){
		for(x = x_start; x < x_start + x_size;x++){
			
			temp = ((U16)pic[p]) | (((U16)pic[p + 1]) << 8);
			
			if(x < 480 && y < 272){
				buf[y][x] = temp;
			}	
			p += 2;
				
		}	
	}
		
}

(11)开机使用的清屏函数
void lcd_clear_init(U32 color)
{
	U32 x,y;
	U32 red,green,blue;
	U16 temp;
	red = ((color >> 19) & 0x1f);
	green = ((color >> 10) & 0x3f);
	blue = ((color >> 3) & 0x1f);
	
	temp = (U16)((red << 11) | (green < 5) | blue);
	
	for(y = 0;y < 272;y++){
		for(x = 0;x < 480;x++)
			buf[y][x] = temp;	
	}
}

(12)延时函数
void Delay(U32 time)
{
	
	while(time--);	
}

(13)测试函数
void lcd_tes()
{
	
	lcd_line();
	Delay(500000);
	
	lcd_picture(0,0,240,179,pic);	
	Delay(500000);
	
}

6410代码

/****************************
@File:lcd.c
@
@Tiny6410裸机下学期代码
@LCD配置文件
@Author:小君君
@****************************/

#include "common.h"

void lcd_init()
{
	/*1.配置GPIO*/
	(vi GPECON) = 0x00011111;
	(vi GPEDAT) = 0x00000001;
	(vi GPFCON) = 0x96AAAAAA;
	(vi GPFDAT) = 0x00002000;
	(vi GPICON) = 0xAAAAAAAA;
	(vi GPJCON) = 0x00AAAAAA;
	
	/*2.设置MOFPCON为normal mode*/
	(vi MIFPCON) &= ~(1<<3);
	
	/*3.设置SPCON,选择RGB/IF style*/
	(vi SPCON) &= ~(0x3);
	(vi SPCON) |= 1;
	
	/*4.设置VIDCONx,选择接口类型,输出格式,时钟,极性,使能LCD控制器*/
	/*ENVID_F = 1,当前帧结束后使能 LCD 控制器;
	ENVID = 1,使能 LCD 控制器;
	CLKSEL_F = 0, 选择时钟源为 HCLK;
	CLKDIR = 1, 选择需要分频;
	VCLKFREE = 0,选择 normal mode;
	CLKVAL_F = 10, 分频系数为 9,即 VCLK = 133 / (9+1) = 13MHz;
	CLKVALUP = 0,总是选择 CLKVAL_F 来更新时序控制;
	RGSPSEL = 0,RGB 并行;
	VIDOUT=0,使用 RGB 接口;*/
	(vi VIDCON0) = (0<<26)|(0<<17)|(0<<16)|(10<<6)|(0<<5)|(1<<4)|(0<<2)|(3<<0);
	(vi VIDCON1) |= 1<<5 | 1<<6;
	
	/*5.设置VIDTCONx,选择时序和分辨率*/
	(vi VIDTCON0) = VBPD<<16 | VFPD<<8 | VSPW<<0;
	(vi VIDTCON1) = HBPD<<16 | HFPD<<8 | HSPW<<0;
	(vi VIDTCON2) = (LINEVAL << 11) | (HOZVAL << 0);
	
	/*6.设置WINCON0,设置window0的数据格式*/
	/*Enable the video output and the VIDEO control signal.*/
	/*1011 = unpacked 24 BPP (non-palletized R:8-G:8-B:8 ) */
	
	(vi WINCON0) |= 1<<0;
	(vi WINCON0) &= ~(0xf << 2);
	(vi WINCON0) |= 0xB<<2;
	
	/*7.配置VIDOSDOA/B/C,设置window0坐标*/
	/*结合LCD的Data Input Format可知宽480,高272像素*/
	/*所以左上角坐标(0,0),右下角(479,271)*/
	(vi VIDOSD0A) = (LeftTopX<<11) | (LeftTopY << 0);
	(vi VIDOSD0B) = (RightBotX<<11) | (RightBotY << 0);
	(vi VIDOSD0C) = (LINEVAL + 1) * (HOZVAL + 1);
	
	/*8.设置VIDWOOADD0B0以及VIDWOOADD1B0,设置framebuffer的地址*/
	(vi VIDW00ADD0B0) = FRAME_BUFFER;
	(vi VIDW00ADD1B0) = (((HOZVAL + 1)*4 + 0) * (LINEVAL + 1)) & (0xffffff);	
}

// 描点
void lcd_draw_pixel(int row, int col, int color)
{
	unsigned long * pixel = (unsigned long  *)FRAME_BUFFER;

	*(pixel + row * COL + col) = color;

}

// 清屏
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);
}

// 绘制同心圆
void lcd_draw_circle(void)
{
	int x,y;
	int color;
	unsigned char red,green,blue,alpha;
	int xsize = ROW;
	int ysize = COL;

	for (y = 0; y < ysize; y++)
		for (x = 0; x < xsize; x++)
		{
			color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/64;
			red   = (color/8) % 256;
			green = (color/4) % 256;
			blue  = (color/2) % 256;
			alpha = (color*2) % 256;

			color |= ((int)alpha << 24);
			color |= ((int)red   << 16);
			color |= ((int)green << 8 );
			color |= ((int)blue       );

			lcd_draw_pixel(x,y,color);
		}
}

/****************************
@File:common.h
@
@Tiny6410裸机下学期代码
@常用头文件定义
@Author:小君君
@****************************/



#ifndef __COMMON_H__
#define __COMMON_H__

#define  vi   *( volatile unsigned long * ) 

#define ulong unsigned long




/*取消使用mmu*/

//#define MMU_ENABLE 1
/*LED初始化*/

#ifndef MMU_ENABLE
	#define LED_CON 0x7F008800
	#define LED_DAT  0x7F008808
#else
	#define LED_CON 0xA0008800
	#define LED_DAT  0xA0008808
#endif

void mmu_init();

void led_init();
void led_on();
void led_off();
void led1_on();
void led2_on();
void led3_on();
void led4_on();
void led5_on();
void led6_on();
void led7_on();
void led8_on();


/*按键相关初始化*/
#define KEYCON  0x7f008830
#define KEYCON1 0x7f008814

#define K1_MSK (3 << 0)
#define K2_MSK (3 << 2)
#define K3_MSK (3 << 4)
#define K4_MSK (3 << 6)
#define K5_MSK (3 << 8)
#define K6_MSK (3 << 10)
#define K7_MSK (0xF << 12)
#define K8_MSK (0xF << 16)


#define K1_OK (2 << 0)
#define K2_OK (2 << 2)
#define K3_OK (2 << 4)
#define K4_OK (2 << 6)
#define K5_OK (2 << 8)
#define K6_OK (2 << 10)
#define K7_OK (0x3 << 12)
#define K8_OK (0x3 << 16)

void button_init();


/*中断控制器相关的寄存器地址*/
#define EXT_INT_0_CON       0x7f008900   
#define EXT_INT_1_CON       0x7f008904  
#define EXT_INT_0_MASK      0x7f008920 
#define EXT_INT_0_PEND      0x7f008924     

#define VIC0INTENABLE       0x71200010   
#define VIC1INTENABLE       0x71300010

#define EINT0_VECTADDR      0x71200100 /*每个中断源有一个寄存器存放相应的中断处理函数的地址,共32+32 = 64个*/
#define EINT1_VECTADDR      0x71200104
#define EINT2_VECTADDR      0x71200108
#define EINT3_VECTADDR      0x7120010C
#define EINT4_VECTADDR      0x71200110
#define EINT5_VECTADDR      0x71200114/*以上是VIC0,见6410datasheet的P414*/

#define EINT19_VECTADDR     0x71300100     
#define EINT20_VECTADDR     0x71300104 /*以上是VIC1*/


#define VIC0ADDRESS         0x71200f00   
#define VIC1ADDRESS         0x71300f00

void irq_init();


/*nandflash相关寄存器定义*/
#define NFCONF  0x70200000 
#define NFCONT  0x70200004 
#define NFCMMD  0x70200008 
#define NFADDR  0x7020000C 
#define NFDATA  0x70200010 
#define NFDATA8 (*(volatile unsigned char *)0x70200010) 
#define NFSTAT  0x70200028

int nand_erase(unsigned int block_addr);
int Nand_PageWrite(unsigned long start_addr,char *buf);


/*UART相关寄存器定义*/
#define UARTCON     0x7F008000
#define ULCON0      0x7F005000
#define UCON0       0x7F005004
#define UFCON0      0x7F005008
#define UMCON0      0x7F00500C
#define UTRSTAT0    0x7F005010
#define UFSTAT0     0x7F005018

#define UTXH0      (*((volatile unsigned char *)0x7F005020))//注意是char类型的
#define URXH0      (*((volatile unsigned char *)0x7F005024))
#define UBRDIV0    (*((volatile unsigned short *)0x7F005028))//注意是short类型的
#define UDIVSLOT0  (*((volatile unsigned short *)0x7F00502C))

#define UART_FIFO_ENABLE 1  //最好使用FIFO模式,就是必须有这个宏定义

void uart_init();

#ifdef	UART_FIFO_ENABLE
	char getchar(void);
	void putchar(char c);
	void send_string(char* str);
#else
	unsigned char getchar(void);
	void putchar(unsigned char c);
	void send_string(unsigned char* str);
#endif


/*DMA相关定义*/

#define UTXH0_DMA 0x7F005020
#define DMA_BASE 0x75000000

#define DMACC0SrcAddr  (DMA_BASE + 0x100)
#define DMACC0DestAddr (DMA_BASE + 0x104)
#define DMACC0Control0 (DMA_BASE + 0x10C)

#define DMACC0Control1 (DMA_BASE + 0x110)
#define DMACC0Configuration (DMA_BASE + 0x114)
#define DMACC0ConfigurationExp (DMA_BASE + 0x118)

#define DMACC0LLI (DMA_BASE + 0x108)
#define DMACEnbldChns (DMA_BASE + 0x01C)
#define DMACConfiguration (DMA_BASE + 0x030)
#define DMACSync (DMA_BASE + 0x034)
#define DMA_SEL 0x7E00F110

void dma_init();
void dma_start();

/*LCD相关寄存器定义*/
#define GPECON  0x7F008080
#define GPEDAT  0x7F008084
#define GPEPUD  0x7F008088
#define GPFCON  0x7F0080A0
#define GPFDAT  0x7F0080A4
#define GPFPUD  0x7F0080A8
#define GPICON  0x7F008100
#define GPIPUD  0x7F008108
#define GPJCON  0x7F008120
#define GPJPUD  0x7F008128


/* display controller */
#define MIFPCON  	0x7410800C
#define SPCON        	0x7F0081A0
#define VIDCON0      	0x77100000
#define VIDCON1      	0x77100004
#define VIDTCON0     	0x77100010
#define VIDTCON1     	0x77100014
#define VIDTCON2     	0x77100018
#define WINCON0      	0x77100020
#define VIDOSD0A      	0x77100040
#define VIDOSD0B      	0x77100044
#define VIDOSD0C      	0x77100048
#define VIDW00ADD0B0    0x771000A0
#define VIDW00ADD1B0    0x771000D0
#define VIDW00ADD2      0x77100100
#define DITHMODE        0x77100170

#define FRAME_BUFFER   0x54000000
#define ROW				272
#define COL				480
#define HSPW 				(2)
#define HBPD			 	(40- 1)
#define HFPD 				(5 - 1)
#define VSPW				(2)
#define VBPD 				(8 - 1)
#define VFPD 				(9 - 1)
#define LINEVAL 			(271)
#define HOZVAL				(479)

#define LeftTopX     0
#define LeftTopY     0
#define RightBotX   479
#define RightBotY   271

void lcd_init();
void lcd_draw_pixel(int row, int col, int color);
void lcd_clear_screen(int color);
void lcd_draw_hline(int row, int col1, int col2, int color);
void lcd_draw_vline(int col, int row1, int row2, int color);
void lcd_draw_cross(int row, int col, int halflen, int color);
void lcd_draw_circle(void);

#define WIDTHEIGHT	480
#define HEIGHT	272

#endif

/****************************
@File:main.c
@
@Tiny6410裸机下学期代码
@LCD测试文件
@Author:小君君
@****************************/

#include "common.h"

int main(void)
{
	int num = 1000;
	
	//mmu_init();//MMU初始化,这里不使用MMU
	
	led_init();//LED的GPIO初始化
	
	button_init();//按键初始化
	
	irq_init();//中断初始化
	
	led_on();//点亮4颗LED
	
	uart_init();//串口初始化
	
	putchar('a');
	putchar('\r');
	putchar('\n');
	putchar('b');
	putchar('\r');
	putchar('\n');
	
	
	dma_init();//DMA初始化
	dma_start();//启动DMA发送数据到串口
	
	uart_init();//串口再次初始化,使得串口恢复中断或者轮询模式
	
	lcd_init();
	lcd_clear_screen(0xFFFFFF);
	
	
	while(1){
		printf("=================================================\n\r");
		printf("===================JUN-BOOT======================\n\r");
		printf("0.Send the ARP to get yhe host's MAC address\n\r");
		printf("1.Download the linux kernel from tftp\n\r");
		printf("2.Boot linux OS from SDRAM\n\r");
		printf("3.Junjun is a houmorous\n\r");
		printf("=================================================\n\r");
		printf("===================LCD_TEST======================\n\r");
		printf("4.清屏\n\r");
		printf("5.画横线\n\r");
		printf("6.画竖线\n\r");
		printf("7.画十字架\n\r");
		printf("8.画同心圆\n\r");
		printf("                                                   \n\r");
		printf("请输入0-8任意一个数字:\n\r");
		
		scanf("%d",&num);	
		
		switch(num){
			case 0:
				printf("请支持成都国嵌\n\r");
				break;
			case 1:
				printf("国嵌学院=====打造你的嵌入式人生\n\r");
				break;
			case 2:
				printf("学ARM,学Linux,学C++,学安卓,学嵌入式,就到成都国嵌学院\n\r");
				break;
			case 3:
				printf("只要你肯努力,你的明天就会等你!!\n\r");
				break;
			case 4:
				lcd_clear_screen(0x000000);
				break;
			case 5:
				lcd_clear_screen(0x000000);
				lcd_draw_hline(HEIGHT/2, 100, WIDTHEIGHT-100, 0xff0000);
				break;
			case 6:
				lcd_clear_screen(0x000000);
				lcd_draw_vline(WIDTHEIGHT/2, 50, HEIGHT-50, 0xff0000);
				break;
			case 7:
				lcd_clear_screen(0x000000);
				lcd_draw_cross(HEIGHT/2, WIDTHEIGHT/2, 20, 0x777777);
				break;
			case 8:
				lcd_clear_screen(0x000000);
				lcd_draw_circle();
				break;
			default:
				printf("只要你肯努力,你的明天就会等你!!\n\r");
				break;
			
		}
	}
	return 0;	
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值