首页 > 代码库 > 实验九--裸机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