首页 > 代码库 > 实验九--裸机LCD
实验九--裸机LCD
一。环境
系统:ubuntu12.04
开发板:jz2440
编译器:gcc
二。说明
有空补上
三。代码
Makefile:
1 CC = arm-linux-gcc 2 LD = arm-linux-ld 3 AR = arm-linux-ar 4 OBJCOPY = arm-linux-objcopy 5 OBJDUMP = arm-linux-objdump 6 7 CFLAGS := -Wall -O2 8 9 10 export CC LD AR OBJCOPY OBJDUMP CFLAGS11 12 objs := head.o init.o nand.o lcddrv.o framebuffer.o main.o13 14 lcd.bin: $(objs)15 ${LD} -Tlcd.lds -o lcd_elf $^16 ${OBJCOPY} -O binary -S lcd_elf $@17 ${OBJDUMP} -D -m arm lcd_elf > lcd.dis18 19 20 %.o:%.c21 ${CC} $(CFLAGS) -c -o $@ $<22 23 %.o:%.S24 ${CC} $(CFLAGS) -c -o $@ $<25 26 clean:27 rm -f lcd.bin lcd_elf lcd.dis *.o28
head.S:
1 @****************************************************************************** 2 @ File: head.S 3 @ 功能: 设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行 4 @****************************************************************************** 5 6 .extern main 7 .text 8 .global _start 9 _start:10 @****************************************************************************** 11 @ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用12 @****************************************************************************** 13 b Reset14 15 @ 0x04: 未定义指令中止模式的向量地址16 HandleUndef:17 b HandleUndef 18 19 @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式20 HandleSWI:21 b HandleSWI22 23 @ 0x0c: 指令预取终止导致的异常的向量地址24 HandlePrefetchAbort:25 b HandlePrefetchAbort26 27 @ 0x10: 数据访问终止导致的异常的向量地址28 HandleDataAbort:29 b HandleDataAbort30 31 @ 0x14: 保留32 HandleNotUsed:33 b HandleNotUsed34 35 @ 0x18: 中断模式的向量地址36 HandleIRQ:37 b HandleIRQ38 39 @ 0x1c: 快中断模式的向量地址40 HandleFIQ:41 b HandleFIQ42 43 Reset: 44 ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈45 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启46 bl clock_init @ 设置MPLL,改变FCLK、HCLK、PCLK47 bl memsetup @ 设置存储控制器以使用SDRAM48 bl nand_init @ 初始化NAND Flash49 50 @ 复制代码到SDRAM中51 ldr r0, =0x30000000 @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址52 mov r1, #4096 @ 2. 源地址 = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处53 mov r2, #16*1024 @ 3. 复制长度 = 16K,对于本实验,这是足够了54 bl CopyCode2SDRAM @ 调用C函数CopyCode2SDRAM55 56 bl clean_bss @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段57 58 59 60 msr cpsr_c, #0xdf @ 进入系统模式61 ldr sp, =0x34000000 @ 设置系统模式栈指针,62 63 64 65 ldr lr, =halt_loop @ 设置返回地址66 ldr pc, =main @ 调用main函数67 halt_loop:68 b halt_loop
上面的sdram,时钟,nand flash等同前面的,不贴出来了
现在与lcd有关的函数:
main.c:
1 #include "lcddrv.h" 2 #include "framebuffer.h" 3 #include "s3c24xx.h" 4 5 void delay() 6 7 { 8 9 unsigned long cnt;10 11 for(cnt=0;cnt<100000;cnt++);12 13 }14 15 int main()16 {17 Lcd_Port_Init(); // 设置LCD引脚18 Tft_Lcd_Init(); // 初始化LCD控制器19 Lcd_PowerEnable(0, 1); // 设置LCD_PWREN有效,它用于打开LCD的电源20 Lcd_EnvidOnOff(1); // 使能LCD控制器输出信号21 22 ClearScr(0x0); // 清屏,黑色23 while (1)24 { 25 26 Mire(); 27 delay(); 28 //Lcd_EnvidOnOff(0);29 30 }31 32 return 0;33 }
由main函数可以看出,本程序只是驱动lcd来画同心圆,参考代码是韦东山先生的,此处作了较大的删改:
framebuffer.c:
1 /* 2 * FILE: framebuffer.c 3 * 实现在framebuffer上画点、画线、画同心圆、清屏的函数 4 */ 5 6 #include "framebuffer.h" 7 8 extern unsigned int fb_base_addr; 9 extern unsigned int bpp;10 extern unsigned int xsize;11 extern unsigned int ysize;12 13 /* 14 * 画点15 * 输入参数:16 * x、y : 象素坐标17 * color: 颜色值18 * 对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),19 * 需要转换为5:6:5格式20 * 对于8BPP: color为调色板中的索引值,21 * 其颜色取决于调色板中的数值22 */23 void PutPixel(unsigned int x, unsigned int y, unsigned int color)24 {25 unsigned char red,green,blue;26 27 switch (bpp){28 case 16:29 {30 unsigned short *addr = (unsigned short *)fb_base_addr + (y * xsize + x);31 red = (color >> 19) & 0x1f;32 green = (color >> 10) & 0x3f;33 blue = (color >> 3) & 0x1f;34 color = (red << 11) | (green << 5) | blue; // 格式5:6:535 *addr = (unsigned short) color;36 break;37 }38 39 40 default:41 break;42 }43 }44 45 /* 46 * 绘制同心圆47 */48 void Mire(void)49 {50 unsigned int x,y;51 unsigned int color;52 unsigned char red,green,blue,alpha;53 54 for (y = 0; y < ysize; y++)55 for (x = 0; x < xsize; x++){56 color = ((x-xsize/2)*(x-xsize/2) + (y-ysize/2)*(y-ysize/2))/64;57 red = (color/8) % 256;58 green = (color/4) % 256;59 blue = (color/2) % 256;60 alpha = (color*2) % 256;61 62 color |= ((unsigned int)alpha << 24);63 color |= ((unsigned int)red << 16);64 color |= ((unsigned int)green << 8 );65 color |= ((unsigned int)blue );66 67 PutPixel(x,y,color);68 }69 }70 71 /* 72 * 将屏幕清成单色73 * 输入参数:74 * color: 颜色值75 * 对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),76 * 需要转换为5:6:5格式77 * 对于8BPP: color为调色板中的索引值,78 * 其颜色取决于调色板中的数值79 */80 void ClearScr(unsigned int color)81 { 82 unsigned int x,y;83 84 for (y = 0; y < ysize; y++)85 for (x = 0; x < xsize; x++)86 PutPixel(x, y, color);87 }
lcddrv.c:
1 /* 2 * FILE: lcddrv.c 3 * 提供操作LCD控制器、调色板等的底层函数 4 */ 5 6 #include "s3c24xx.h" 7 #include "lcddrv.h" 8 9 #define GPB0_tout0 (2<<(0*2)) 10 #define GPB0_out (1<<(0*2)) 11 #define GPB1_out (1<<(1*2)) 12 13 #define GPB0_MSK (3<<(0*2)) 14 #define GPB1_MSK (3<<(1*2)) 15 16 17 unsigned int fb_base_addr; 18 unsigned int bpp; 19 unsigned int xsize; 20 unsigned int ysize; 21 22 23 /* 24 * 初始化用于LCD的引脚 25 */ 26 void Lcd_Port_Init(void) 27 { 28 GPCUP = 0xffffffff; // 禁止内部上拉 29 GPCCON = 0xaaaaaaaa; // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND 30 GPDUP = 0xffffffff; // 禁止内部上拉 31 GPDCON = 0xaaaaaaaa; // GPIO管脚用于VD[23:8] 32 GPBCON &= ~(GPB0_MSK); // Power enable pin 33 GPBCON |= GPB0_out; 34 GPBDAT &= ~(1<<0); // Power off 35 36 } 37 38 /* 39 * 初始化LCD控制器 40 * 输入参数: 41 * type: 显示模式 42 * MODE_TFT_8BIT_240320 : 240*320 8bpp的TFT LCD 43 * MODE_TFT_16BIT_240320 : 240*320 16bpp的TFT LCD 44 * MODE_TFT_8BIT_640480 : 640*480 8bpp的TFT LCD 45 * MODE_TFT_16BIT_640480 : 640*480 16bpp的TFT LCD 46 */ 47 void Tft_Lcd_Init() 48 { 49 50 /* 51 * 设置LCD控制器的控制寄存器LCDCON1~5 52 * 1. LCDCON1: 53 * 设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2] 54 * 选择LCD类型: TFT LCD 55 * 设置显示模式: 16BPP 56 * 先禁止LCD信号输出 57 * 2. LCDCON2/3/4: 58 * 设置控制信号的时间参数 59 * 设置分辨率,即行数及列数 60 * 现在,可以根据公式计算出显示器的频率: 61 * 当HCLK=100MHz时, 62 * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x 63 * {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x 64 * {2x(CLKVAL+1)/(HCLK)}] 65 * = 60Hz 66 * 3. LCDCON5: 67 * 设置显示模式为16BPP时的数据格式: 5:6:5 68 * 设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转 69 * 半字(2字节)交换使能 70 */ 71 LCDCON1 = (4<<8) | (LCDTYPE_TFT<<5) | 72 (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0); 73 LCDCON2 = (1<<24) | (271<<14) | 74 (1<<6) | (9); 75 LCDCON3 = (1<<19) | (479<<8) | (1); 76 LCDCON4 = 40; 77 LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | 78 (HWSWP<<1); 79 80 /* 81 * 设置LCD控制器的地址寄存器LCDSADDR1~3 82 * 帧内存与视口(view point)完全吻合, 83 * 图像数据格式如下: 84 * |----PAGEWIDTH----| 85 * y/x 0 1 2 239 86 * 0 rgb rgb rgb ... rgb 87 * 1 rgb rgb rgb ... rgb 88 * 1. LCDSADDR1: 89 * 设置LCDBANK、LCDBASEU 90 * 2. LCDSADDR2: 91 * 设置LCDBASEL: 帧缓冲区的结束地址A[21:1] 92 * 3. LCDSADDR3: 93 * OFFSIZE等于0,PAGEWIDTH等于(240*2/2) 94 */ 95 LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1); 96 LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ 97 (480)*(272)*2)>>1); 98 LCDSADDR3 = (0<<11) | (480*2/2); 99 100 /* 禁止临时调色板寄存器 */101 TPAL = 0;102 103 fb_base_addr = LCDFRAMEBUFFER;104 bpp = 16;105 xsize = 480;106 ysize = 272;107 108 109 }110 111 112 /*113 * 设置是否输出LCD电源开关信号LCD_PWREN114 * 输入参数:115 * invpwren: 0 - LCD_PWREN有效时为正常极性116 * 1 - LCD_PWREN有效时为反转极性117 * pwren: 0 - LCD_PWREN输出有效118 * 1 - LCD_PWREN输出无效119 */120 void Lcd_PowerEnable(int invpwren, int pwren)121 {122 GPGCON = (GPGCON & (~(3<<8))) | (3<<8); // GPG4用作LCD_PWREN123 GPGUP = (GPGUP & (~(1<<4))) | (1<<4); // 禁止内部上拉 124 125 LCDCON5 = (LCDCON5 & (~(1<<5))) | (invpwren<<5); // 设置LCD_PWREN的极性: 正常/反转126 LCDCON5 = (LCDCON5 & (~(1<<3))) | (pwren<<3); // 设置是否输出LCD_PWREN127 } 128 129 /*130 * 设置LCD控制器是否输出信号131 * 输入参数:132 * onoff: 133 * 0 : 关闭134 * 1 : 打开135 */136 void Lcd_EnvidOnOff(int onoff)137 {138 if (onoff == 1)139 {140 LCDCON1 |= 1; // ENVID ON141 GPBDAT |= (1<<0); // Power on142 }143 else144 {145 LCDCON1 &= 0x3fffe; // ENVID Off146 GPBDAT &= ~(1<<0); // Power off147 }148 }
现在贴出重要的头文件做为理解用:
lcddrv.h:
1 /* 2 * FILE: lcddrv.h 3 * 操作LCD控制器、调色板等的底层函数接口 4 */ 5 6 #ifndef __LCDDRV_H__ 7 #define __LCDDRV_H__ 8 9 10 #define LOWER21BITS(n) ((n) & 0x1fffff)11 12 #define BPPMODE_16BPP 0xC13 14 15 #define LCDTYPE_TFT 0x316 17 #define ENVID_DISABLE 018 #define ENVID_ENABLE 119 20 #define FORMAT8BPP_5551 021 #define FORMAT8BPP_565 122 23 #define HSYNC_NORM 024 #define HSYNC_INV 125 26 #define VSYNC_NORM 027 #define VSYNC_INV 128 29 #define VDEN_NORM 030 #define VDEN_INV 131 32 #define BSWP 133 #define HWSWP 134 35 #define LCDFRAMEBUFFER 0x3040000036 37 /*38 * 初始化用于LCD的引脚39 */40 void Lcd_Port_Init(void);41 42 /*43 * 初始化LCD控制器44 * 输入参数:45 * type: 显示模式46 * MODE_TFT_8BIT_640480 : 640*640 8bpp的TFT LCD47 * MODE_TFT_16BIT_640480 : 640*640 16bpp的TFT LCD48 */49 void Tft_Lcd_Init();50 51 void Lcd_EnvidOnOff(int onoff);52 53 /*54 * 设置是否输出LCD电源开关信号LCD_PWREN55 * 输入参数:56 * invpwren: 0 - LCD_PWREN有效时为正常极性57 * 1 - LCD_PWREN有效时为反转极性58 * pwren: 0 - LCD_PWREN输出有效59 * 1 - LCD_PWREN输出无效60 */61 void Lcd_PowerEnable(int invpwren, int pwren);62 63 64 #endif /*__LCDDRV_H__*/
自然不难看出,仍然有不少冗余项,这里先不做深究。
上面代码经过烧写验证,没有问题。
代码删减了串口,中断,以及print函数的硬件重定向等内容,以便更直观理解lcd驱动。
关于代码中重要函数,有时间补上。
实验九--裸机LCD
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。