LED实验

2440 LCD原理图如下:

这里写图片描述

从图中可以看出,需要的信号有:垂直方向上的信号(vsync)、水平方向的垂直信号(hsync)、时钟(vck)、使能信号(vden)、背光信号(LED+,LED-),数据信号(vd0 - vd23)

这里写图片描述

如果我们想点亮LED,首先要设置GPB0.

要知道这些信号怎么联系起来,需要看2440手册上的时序图:
这里写图片描述

假设LED的分辨率为240*320,LED从左到右、从上到下呈Z 字状的扫描方法,所谓的扫描就是电子枪(喷枪)移动,怎么控制它的电子枪的移动?

vsync: vsync为高电平的时候,马上回到最上一行;
喷枪回到最上一行,同步信号持续多长时间(VSPW+1)可以控制的;

LED时序图:
这里写图片描述

行开始与行结束是用Hsync来的表示。行里面的有效数据是用VDEN来表示(驱动)的。

从上面可以看出,写程序需要设置的参数有:VSPW、VBPD、VFPD、HSPW、HBPD、HFPD、时钟信号。在2440上面寄存器可以设置这些数据;

这里写图片描述
2440的数据是怎么发出来的?
2440里面会开一块内存,里面的数据就对于LED上的颜色,LED上的颜色在这块内存里面有一个对应的值;这块内存就叫Frame buffer,当我们想显示一张图片的时候,我们就把图片上的元素写到Frame buffer里面去;然后LCD控制器就会把Hsync,Vsync,VEDN这些信号驱动出去,在LED上显示出来。

写程序的步骤:
1,打开背光
2,上下左右的时序设置
3,在Frame buffer写数据,写数据的时候要注意格式;例如对于16BP(2个字节)的数据格式如下:
这里写图片描述
这里写图片描述
这里写图片描述

调色板:存256种颜色,以16BP的格式存;负责Flame Buffer与 LCD之间的数据转换。如果Flame Buffer是8BP,它里面的值并不是真正的像素值,而是索引,根据索引去调色板取颜色,然后发送到LCD;

接着看一下与LCD有关的控制寄存器,如图:
这里写图片描述

具体要看手册;

接下来看代码,首先看一下makefile文件:


CC      = arm-linux-gcc
LD      = arm-linux-ld
AR      = arm-linux-ar
OBJCOPY = arm-linux-objcopy
OBJDUMP = arm-linux-objdump

INCLUDEDIR  := $(shell pwd)/include
CFLAGS      := -Wall -O2
CPPFLAGS    := -nostdinc -I$(INCLUDEDIR)

export  CC LD AR OBJCOPY OBJDUMP INCLUDEDIR CFLAGS CPPFLAGS

objs := head.o init.o nand.o interrupt.o serial.o lcddrv.o framebuffer.o lcdlib.o main.o lib/libc.a

lcd.bin: $(objs)
    ${LD} -Tlcd.lds -o lcd_elf $^
    ${OBJCOPY} -O binary -S lcd_elf $@
    ${OBJDUMP} -D -m arm lcd_elf > lcd.dis

.PHONY : lib/libc.a
lib/libc.a:
    cd lib; make; cd ..

%.o:%.c
    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

%.o:%.S
    ${CC} $(CPPFLAGS) $(CFLAGS) -c -o $@ $<

clean:
    make  clean -C lib
    rm -f lcd.bin lcd_elf lcd.dis *.o

首先看一下head.o对应的文件head.S文件,代码如下:

@******************************************************************************
@ File: head.S
@ 功能: 设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@******************************************************************************       

.extern     main
.text 
.global _start 
_start:
@******************************************************************************       
@ 中断向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用
@******************************************************************************       
    b   Reset

@ 0x04: 未定义指令中止模式的向量地址
HandleUndef:
    b   HandleUndef 

@ 0x08: 管理模式的向量地址,通过SWI指令进入此模式
HandleSWI:
    b   HandleSWI

@ 0x0c: 指令预取终止导致的异常的向量地址
HandlePrefetchAbort:
    b   HandlePrefetchAbort

@ 0x10: 数据访问终止导致的异常的向量地址
HandleDataAbort:
    b   HandleDataAbort

@ 0x14: 保留
HandleNotUsed:
    b   HandleNotUsed

@ 0x18: 中断模式的向量地址
    b   HandleIRQ

@ 0x1c: 快中断模式的向量地址
HandleFIQ:
    b   HandleFIQ

Reset:                  
    ldr sp, =4096           @ 设置栈指针,以下都是C函数,调用前需要设好栈
    bl  disable_watch_dog   @ 关闭WATCHDOG,否则CPU会不断重启
    bl  clock_init          @ 设置MPLL,改变FCLK、HCLK、PCLK
    bl  memsetup            @ 设置存储控制器以使用SDRAM
    bl  nand_init           @ 初始化NAND Flash

                            @ 复制代码到SDRAM中
    ldr r0, =0x30000000     @ 1. 目标地址 = 0x30000000,这是SDRAM的起始地址
    mov r1, #4096           @ 2. 源地址   = 4096,运行地址在SDRAM中的代码保存在NAND Flash 4096地址开始处
    mov r2, #16*1024        @ 3. 复制长度 = 16K,对于本实验,这是足够了
    bl  CopyCode2SDRAM      @ 调用C函数CopyCode2SDRAM

    bl  clean_bss           @ 清除bss段,未初始化或初值为0的全局/静态变量保存在bss段

    msr cpsr_c, #0xd2       @ 进入中断模式
    ldr sp, =0x31000000     @ 设置中断模式栈指针

    msr cpsr_c, #0xdf       @ 进入系统模式
    ldr sp, =0x34000000     @ 设置系统模式栈指针,

    ldr lr, =ret_initirq    @ 设置返回地址    
    ldr pc, =init_irq       @ 调用中断初始化函数
ret_initirq:
    msr cpsr_c, #0x5f       @ 设置I-bit=0,开IRQ中断

    ldr lr, =halt_loop      @ 设置返回地址
    ldr pc, =main           @ 调用main函数
halt_loop:
    b   halt_loop

HandleIRQ:
    sub lr, lr, #4                  @ 计算返回地址
    stmdb   sp!,    { r0-r12,lr }   @ 保存使用到的寄存器
                                    @ 注意,此时的sp是中断模式的sp
                                    @ 初始值是上面设置的4096

    ldr lr, =int_return             @ 设置调用IRQ_Handle函数后的返回地址  
    ldr pc, =IRQ_Handle             @ 调用中断分发函数,在interrupt.c中
int_return:
    ldmia   sp!,    { r0-r12,pc }^  @ 中断返回, ^表示将spsr的值复制到cpsr

main.c文件:

#include <stdio.h>
#include "serial.h"
#include "lcdlib.h"
#include "s3c24xx.h"

int main()
{
    char c;

    uart0_init();   // 波特率115200,8N1(8个数据位,无校验位,1个停止位)

    while (1)
    {
        printf("\r\n##### Test TFT LCD #####\r\n");
        printf("[1] TFT240320 8Bit\n\r");
        printf("[2] TFT240320 16Bit\n\r");
        printf("Enter your selection: ");

        c = getc();
        printf("%c\n\r", c);
        switch (c)
        {
            case '1':
            {
                Test_Lcd_Tft_8Bit_240320();
                break;
            }

            case '2':
            {
                Test_Lcd_Tft_16Bit_240320();
                break;
            }


            default: 
                break;
        }
    }

    return 0;
}

其中Test_Lcd_Tft_16Bit_240320();
就是LCD的核心代码。它位于lcdlib.c文件,代码如下:

/*
 * FILE: lcdlib.c
 * 实现TFT LCD的测试函数
 */

#include <stdio.h>
#include "lcddrv.h"
#include "framebuffer.h"


/* 
 * 以240x320,8bpp的显示模式测试TFT LCD
 */
void Test_Lcd_Tft_8Bit_240320(void)
{
    Lcd_Port_Init();                     // 设置LCD引脚
    Tft_Lcd_Init(MODE_TFT_8BIT_240320);  // 初始化LCD控制器
    Lcd_PowerEnable(0, 1);               // 设置LCD_PWREN有效,它用于打开LCD的电源
    Lcd_EnvidOnOff(1);                   // 使能LCD控制器输出信号

    Lcd_Palette8Bit_Init();     // 初始化调色板
    ClearScr(0x0);              // 清屏
    printf("[TFT 64K COLOR(16bpp) LCD TEST]\n");

    printf("1. Press any key to draw line\n");
    getc();
    DrawLine(0  , 0  , 239, 0  , 0);    // 颜色为DEMO256pal[0]
    DrawLine(0  , 0  , 0  , 319, 1);    // 颜色为DEMO256pal[1]
    DrawLine(239, 0  , 239, 319, 2);    // ⋯⋯
    DrawLine(0  , 319, 239, 319, 4);
    DrawLine(0  , 0  , 239, 319, 8);
    DrawLine(239, 0  , 0  , 319, 16);
    DrawLine(120, 0  , 120, 319, 32);
    DrawLine(0  , 160, 239, 160, 64);

    printf("2. Press any key to draw circles\n");
    getc();
    Mire();

    printf("3. Press any key to fill the screem with one color\n");
    getc();
    ClearScr(128);  //  输出单色图像,颜色为DEMO256pal[128]

    printf("4. Press any key to fill the screem by temporary palette\n");
    getc(); 
    ClearScrWithTmpPlt(0x0000ff);       //  输出单色图像,颜色为蓝色

    printf("5. Press any key to fill the screem by palette\n");
    getc();
    DisableTmpPlt();            // 关闭临时调色板寄存器
    ChangePalette(0xffff00);    // 改变整个调色板为黄色,输出单色图像

    printf("6. Press any key stop the testing\n");
    getc();
    Lcd_EnvidOnOff(0);
}

/* 
 * 以240x320,16bpp的显示模式测试TFT LCD
 */
void Test_Lcd_Tft_16Bit_240320(void)
{
    Lcd_Port_Init();                     // 设置LCD引脚
    Tft_Lcd_Init(MODE_TFT_16BIT_240320); // 初始化LCD控制器
    Lcd_PowerEnable(0, 1);               // 设置LCD_PWREN有效,它用于打开LCD的电源
    Lcd_EnvidOnOff(1);                   // 使能LCD控制器输出信号

    ClearScr(0x0);  // 清屏,黑色
    printf("[TFT 64K COLOR(16bpp) LCD TEST]\n");

    printf("1. Press any key to draw line\n");
    getc();
    DrawLine(0  , 0  , 239, 0  , 0xff0000);     // 红色
    DrawLine(0  , 0  , 0  , 319, 0x00ff00);     // 绿色
    DrawLine(239, 0  , 239, 319, 0x0000ff);     // 蓝色
    DrawLine(0  , 319, 239, 319, 0xffffff);     // 白色
    DrawLine(0  , 0  , 239, 319, 0xffff00);     // 黄色
    DrawLine(239, 0  , 0  , 319, 0x8000ff);     // 紫色
    DrawLine(120, 0  , 120, 319, 0xe6e8fa);     // 银色
    DrawLine(0  , 160, 239, 160, 0xcd7f32);     // 金色

    printf("2. Press any key to draw circles\n");
    getc();
    Mire();

    printf("3. Press any key to fill the screem with one color\n");
    getc();
    ClearScr(0xff0000);             // 红色

    printf("4. Press any key to fill the screem by temporary palette\n");
    getc();
    ClearScrWithTmpPlt(0x0000ff);   // 蓝色

    printf("5. Press any key stop the testing\n");
    getc();
    Lcd_EnvidOnOff(0);
}


/* 
 * 以640x480,8bpp的显示模式测试TFT LCD
 */
void Test_Lcd_Tft_8Bit_640480(void)
{
    Lcd_Port_Init();                     // 设置LCD引脚
    Tft_Lcd_Init(MODE_TFT_8BIT_640480);  // 初始化LCD控制器
    Lcd_PowerEnable(0, 1);               // 设置LCD_PWREN有效,它用于打开LCD的电源
    Lcd_EnvidOnOff(1);                   // 使能LCD控制器输出信号

    Lcd_Palette8Bit_Init();     // 初始化调色板
    ClearScr(0x0);              // 清屏,黑色
    printf("[TFT 64K COLOR(16bpp) LCD TEST]\n");

    printf("1. Press any key to draw line\n");
    getc();
    DrawLine(0  , 0  , 639, 0  , 0);    // 颜色为DEMO256pal[0]
    DrawLine(0  , 0  , 0  , 479, 1);    // 颜色为DEMO256pal[1]
    DrawLine(639, 0  , 639, 479, 2);    // ⋯⋯
    DrawLine(0  , 479, 639, 479, 4);
    DrawLine(0  , 0  , 639, 479, 8);
    DrawLine(639, 0  , 0  , 479, 16);
    DrawLine(320, 0  , 320, 479, 32);
    DrawLine(0  , 240, 639, 240, 64);

    printf("2. Press any key to draw circles\n");
    getc();
    Mire();

    printf("3. Press any key to fill the screem with one color\n");
    getc();
    ClearScr(128);  //  输出单色图像,颜色为DEMO256pal[128]

    printf("4. Press any key to fill the screem by temporary palette\n");
    getc(); 
    ClearScrWithTmpPlt(0x0000ff);       //  输出单色图像,颜色为蓝色

    printf("5. Press any key to fill the screem by palette\n");
    getc();
    DisableTmpPlt();            // 关闭临时调色板寄存器
    ChangePalette(0xffff00);    // 改变整个调色板为黄色,输出单色图像

    printf("6. Press any key stop the testing\n");
    getc();
    Lcd_EnvidOnOff(0);
}

/* 
 * 以640x480,16bpp的显示模式测试TFT LCD
 */
void Test_Lcd_Tft_16Bit_640480(void)
{
    Lcd_Port_Init();                     // 设置LCD引脚
    Tft_Lcd_Init(MODE_TFT_16BIT_640480); // 初始化LCD控制器
    Lcd_PowerEnable(0, 1);               // 设置LCD_PWREN有效,它用于打开LCD的电源
    Lcd_EnvidOnOff(1);                   // 使能LCD控制器输出信号

    ClearScr(0x0);  // 清屏,黑色
    printf("[TFT 64K COLOR(16bpp) LCD TEST]\n");

    printf("1. Press any key to draw line\n");
    getc();
    DrawLine(0  , 0  , 639, 0  , 0xff0000);     // 红色
    DrawLine(0  , 0  , 0  , 479, 0x00ff00);     // 绿色
    DrawLine(639, 0  , 639, 479, 0x0000ff);     // 蓝色
    DrawLine(0  , 479, 639, 479, 0xffffff);     // 白色
    DrawLine(0  , 0  , 639, 479, 0xffff00);     // 黄色
    DrawLine(639, 0  , 0  , 479, 0x8000ff);     // 紫色
    DrawLine(320, 0  , 320, 479, 0xe6e8fa);     // 银色
    DrawLine(0  , 240, 639, 240, 0xcd7f32);     // 金色

    printf("2. Press any key to draw circles\n");
    getc();
    Mire();

    printf("3. Press any key to fill the screem with one color\n");
    getc();
    ClearScr(0xff0000);             // 红色

    printf("4. Press any key to fill the screem by temporary palette\n");
    getc();
    ClearScrWithTmpPlt(0x0000ff);   // 蓝色

    printf("5. Press any key stop the testing\n");
    getc();
    Lcd_EnvidOnOff(0);
}

LCD的初始化代码(位于lcddrv中):

/*
 * FILE: lcddrv.c
 * 提供操作LCD控制器、调色板等的底层函数
 */

#include <stdio.h>
#include "s3c24xx.h"
#include "lcddrv.h"

#define GPB0_tout0  (2<<(0*2))
#define GPB0_out    (1<<(0*2))
#define GPB1_out    (1<<(1*2))

#define GPB0_MSK    (3<<(0*2))
#define GPB1_MSK    (3<<(1*2))


unsigned int fb_base_addr;
unsigned int bpp;
unsigned int xsize;
unsigned int ysize;

static const unsigned short DEMO256pal[]={
    0x0b5e,0xce9a,0xffd9,0x9d99,0xb63a,0xae7c,0xdd71,0x6c57,0xfd4d,0x00ae,0x9c4d,0xb5f8,0xad96,0x0131,0x0176,0xefff,0xcedd,0x9556,0xe4bf,0x00b6,0x22b7,0x002b,0x89de,0x002c,0x57df,0xab5f,0x3031,0x14bf,0x797e,0x5391,0x93ab,0x7239,0x7453,0xafdf,0x71b9,0x8c92,0x014d,0x302e,0x5175,0x0029,0x0969,0x004e,0x2a6d,0x0021,0x3155,0x4b6e,0xd677,0xf6b6,0x9b5f,0x4bb5,0xffd5,0x0027,0xdfdf,0x74d8,0x1256,0x6bcd,0x9b08,0x2ab2,0xbd72,0x84b5,0xfe52,0xd4ad,0x00ad,0xfffc,0x422b,0x73b0,0x0024,0x5246,0x8e5e,0x28b3,0x0050,0x3b52,0x2a4a,0x3a74,0x8559,0x3356,0x1251,0x9abf,0x4034,0x40b1,
    0x8cb9,0x00b3,0x5c55,0xdf3d,0x61b7,0x1f5f,0x00d9,0x4c59,0x0926,0xac3f,0x925f,0x85bc,0x29d2,0xc73f,0xef5c,0xcb9f,0x827b,0x5279,0x4af5,0x01b9,0x4290,0xf718,0x126d,0x21a6,0x515e,0xefbd,0xd75e,0x42ab,0x00aa,0x10b3,0x7349,0x63b5,0x61a3,0xaadf,0xcb27,0x87df,0x6359,0xc7df,0x4876,0xb5bc,0x4114,0xfe2e,0xef5e,0x65be,0x43b9,0xe5df,0x21c9,0x7d16,0x6abb,0x5c11,0x49f7,0xbc0b,0x9e1a,0x3b0f,0x202b,0xff12,0x821b,0x842f,0xbccf,0xdefb,0x8a3e,0x68fa,0xa4f1,0x38ae,0x28b7,0x21ad,0x31d7,0x0073,0x182b,0x1831,0x3415,0xbdf6,0x2dbf,0x0a5d,0xc73d,0x182c,0x293e,0x7b3d,0x643d,0x3cbd,
    0x92dd,0x09d4,0x1029,0x7cdd,0x6239,0x182e,0x5aea,0x11eb,0x8abc,0x7bfa,0x00a7,0x2153,0x1853,0x1318,0x0109,0x54fa,0x72a7,0x89e3,0x01cf,0x3a07,0x7b17,0x1a14,0x2150,0x23dc,0x4142,0x1b33,0x00a4,0xf6df,0x08fc,0x18ae,0x3a7e,0x18d1,0xa51c,0xff5a,0x1a0f,0x28fa,0xdfbe,0x82de,0x60d7,0x1027,0x48fa,0x5150,0x6213,0x89d6,0x110d,0x9bbb,0xbedd,0x28e1,0x1925,0xf449,0xaa79,0xd5f4,0x693c,0x110a,0x2889,0x08a2,0x923d,0x10a6,0xd9bc,0x5b2e,0x32ec,0xcf7f,0x1025,0x2148,0x74b4,0x6d59,0x9d14,0x0132,0x00f0,0x56bf,0x00f1,0xffff,0x0173,0x0133,0x00b0,0x00b1,0xf7ff,0x08b1,0xfffe,0x08b0,
    0x0171,0xf7bf,0x10f3,0xf7fe,0x08ef,0x1192,0xefbe,0x1131,0x2177,0xff9f,0x1116,0xffbc,0x5914,0x22ef,0xb285,0xa6df,
};

/*
 * 初始化用于LCD的引脚
 */
void Lcd_Port_Init(void)
{
    GPCUP   = 0xffffffff;   // 禁止内部上拉
    GPCCON  = 0xaaaaaaaa;   // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND 
    GPDUP   = 0xffffffff;   // 禁止内部上拉
    GPDCON  = 0xaaaaaaaa;   // GPIO管脚用于VD[23:8]
    GPBCON &= ~(GPB0_MSK);  // Power enable pin
    GPBCON |= GPB0_out;
    GPBDAT &= ~(1<<0);         // Power off
    printf("Initializing GPIO ports..........\n");
}

/*
 * 初始化LCD控制器
 * 输入参数:
 * type: 显示模式
 *      MODE_TFT_8BIT_240320  : 240*320 8bpp的TFT LCD
 *      MODE_TFT_16BIT_240320 : 240*320 16bpp的TFT LCD
 *      MODE_TFT_8BIT_640480  : 640*480 8bpp的TFT LCD
 *      MODE_TFT_16BIT_640480 : 640*480 16bpp的TFT LCD
 */
void Tft_Lcd_Init(int type)
{
    switch(type)
    {
    case MODE_TFT_8BIT_240320:
        /* 
         * 设置LCD控制器的控制寄存器LCDCON1~5
         * 1. LCDCON1:
         *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
         *    选择LCD类型: TFT LCD   
         *    设置显示模式: 8BPP
         *    先禁止LCD信号输出
         * 2. LCDCON2/3/4:
         *    设置控制信号的时间参数
         *    设置分辨率,即行数及列数
         * 现在,可以根据公式计算出显示器的频率:
         * 当HCLK=100MHz时,
         * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
         *              {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
         *              {2x(CLKVAL+1)/(HCLK)}]
         *            = 60Hz
         * 3. LCDCON5:
         *    设置显示模式为8BPP时,调色板中的数据格式: 5:6:5
         *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
         *    字节交换使能
         */
        LCDCON1 = (CLKVAL_TFT_240320<<8) | (LCDTYPE_TFT<<5) | \
                  (BPPMODE_8BPP<<1) | (ENVID_DISABLE<<0);
        LCDCON2 = (VBPD_240320<<24) | (LINEVAL_TFT_240320<<14) | \
                  (VFPD_240320<<6) | (VSPW_240320);
        LCDCON3 = (HBPD_240320<<19) | (HOZVAL_TFT_240320<<8) | (HFPD_240320);
        LCDCON4 = HSPW_240320;
        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \
                  (BSWP<<1);

        /*
         * 设置LCD控制器的地址寄存器LCDSADDR1~3
         * 帧内存与视口(view point)完全吻合,
         * 图像数据格式如下(8BPP时,帧缓冲区中的数据为调色板中的索引值):
         *         |----PAGEWIDTH----|
         *    y/x  0   1   2       239
         *     0   idx idx idx ... idx
         *     1   idx idx idx ... idx
         * 1. LCDSADDR1:
         *    设置LCDBANK、LCDBASEU
         * 2. LCDSADDR2:
         *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]
         * 3. LCDSADDR3:
         *    OFFSIZE等于0,PAGEWIDTH等于(240/2)
         */
        LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
        LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ \
                    (LINEVAL_TFT_240320+1)*(HOZVAL_TFT_240320+1)*1)>>1);
        LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_240320/2);

        /* 禁止临时调色板寄存器 */
        TPAL = 0;

        fb_base_addr = LCDFRAMEBUFFER;
        bpp = 8;
        xsize = 240;
        ysize = 320;

        break;

    case MODE_TFT_16BIT_240320:
        /* 
         * 设置LCD控制器的控制寄存器LCDCON1~5
         * 1. LCDCON1:
         *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
         *    选择LCD类型: TFT LCD   
         *    设置显示模式: 16BPP
         *    先禁止LCD信号输出
         * 2. LCDCON2/3/4:
         *    设置控制信号的时间参数
         *    设置分辨率,即行数及列数
         * 现在,可以根据公式计算出显示器的频率:
         * 当HCLK=100MHz时,
         * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
         *              {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
         *              {2x(CLKVAL+1)/(HCLK)}]
         *            = 60Hz
         * 3. LCDCON5:
         *    设置显示模式为16BPP时的数据格式: 5:6:5
         *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
         *    半字(2字节)交换使能
         */
        LCDCON1 = (CLKVAL_TFT_240320<<8) | (LCDTYPE_TFT<<5) | \
                  (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0);
        LCDCON2 = (VBPD_240320<<24) | (LINEVAL_TFT_240320<<14) | \
                  (VFPD_240320<<6) | (VSPW_240320);
        LCDCON3 = (HBPD_240320<<19) | (HOZVAL_TFT_240320<<8) | (HFPD_240320);
        LCDCON4 = HSPW_240320;
        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \
                  (HWSWP<<1);

        /*
         * 设置LCD控制器的地址寄存器LCDSADDR1~3
         * 帧内存与视口(view point)完全吻合,
         * 图像数据格式如下:
         *         |----PAGEWIDTH----|
         *    y/x  0   1   2       239
         *     0   rgb rgb rgb ... rgb
         *     1   rgb rgb rgb ... rgb
         * 1. LCDSADDR1:
         *    设置LCDBANK、LCDBASEU
         * 2. LCDSADDR2:
         *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]
         * 3. LCDSADDR3:
         *    OFFSIZE等于0,PAGEWIDTH等于(240*2/2)
         */
        LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
        LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ \
                    (LINEVAL_TFT_240320+1)*(HOZVAL_TFT_240320+1)*2)>>1);
        LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_240320*2/2);

        /* 禁止临时调色板寄存器 */
        TPAL = 0;

        fb_base_addr = LCDFRAMEBUFFER;
        bpp = 16;
        xsize = 240;
        ysize = 320;

        break;

    case MODE_TFT_8BIT_640480:
        /* 
         * 设置LCD控制器的控制寄存器LCDCON1~5
         * 1. LCDCON1:
         *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
         *    选择LCD类型: TFT LCD   
         *    设置显示模式: 8BPP
         *    先禁止LCD信号输出
         * 2. LCDCON2/3/4:
         *    设置控制信号的时间参数
         *    设置分辨率,即行数及列数
         * 现在,可以根据公式计算出显示器的频率:
         * 当HCLK=100MHz时,
         * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
         *              {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
         *              {2x(CLKVAL+1)/(HCLK)}]
         *            = 60Hz
         * 3. LCDCON5:
         *    设置显示模式为8BPP时,调色板中的数据格式: 5:6:5
         *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
         *    字节交换使能
         */
        LCDCON1 = (CLKVAL_TFT_640480<<8) | (LCDTYPE_TFT<<5) | \
                  (BPPMODE_8BPP<<1) | (ENVID_DISABLE<<0);
        LCDCON2 = (VBPD_640480<<24) | (LINEVAL_TFT_640480<<14) | \
                  (VFPD_640480<<6) | (VSPW_640480);
        LCDCON3 = (HBPD_640480<<19) | (HOZVAL_TFT_640480<<8) | (HFPD_640480);
        LCDCON4 = HSPW_640480;
        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \
                  (BSWP<<1);

        /*
         * 设置LCD控制器的地址寄存器LCDSADDR1~3
         * 帧内存与视口(view point)完全吻合,
         * 图像数据格式如下(8BPP时,帧缓冲区中的数据为调色板中的索引值):
         *         |----PAGEWIDTH----|
         *    y/x  0   1   2       639
         *     0   idx idx idx ... idx
         *     1   idx idx idx ... idx
         * 1. LCDSADDR1:
         *    设置LCDBANK、LCDBASEU
         * 2. LCDSADDR2:
         *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]
         * 3. LCDSADDR3:
         *    OFFSIZE等于0,PAGEWIDTH等于(640/2)
         */
        LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
        LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ \
                    (LINEVAL_TFT_640480+1)*(HOZVAL_TFT_640480+1)*1)>>1);
        LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_640480/2);

        /* 禁止临时调色板寄存器 */
        TPAL = 0;

        fb_base_addr = LCDFRAMEBUFFER;
        bpp = 8;
        xsize = 640;
        ysize = 480;

        break;

    case MODE_TFT_16BIT_640480:
        /* 
         * 设置LCD控制器的控制寄存器LCDCON1~5
         * 1. LCDCON1:
         *    设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
         *    选择LCD类型: TFT LCD   
         *    设置显示模式: 16BPP
         *    先禁止LCD信号输出
         * 2. LCDCON2/3/4:
         *    设置控制信号的时间参数
         *    设置分辨率,即行数及列数
         * 现在,可以根据公式计算出显示器的频率:
         * 当HCLK=100MHz时,
         * Frame Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
         *              {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
         *              {2x(CLKVAL+1)/(HCLK)}]
         *            = 60Hz
         * 3. LCDCON5:
         *    设置显示模式为16BPP时的数据格式: 5:6:5
         *    设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
         *    半字(2字节)交换使能
         */
        LCDCON1 = (CLKVAL_TFT_640480<<8) | (LCDTYPE_TFT<<5) | \
                  (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0);
        LCDCON2 = (VBPD_640480<<24) | (LINEVAL_TFT_640480<<14) | \
                  (VFPD_640480<<6) | (VSPW_640480);
        LCDCON3 = (HBPD_640480<<19) | (HOZVAL_TFT_640480<<8) | (HFPD_640480);
        LCDCON4 = HSPW_640480;
        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \
                  (HWSWP<<1);

        /*
         * 设置LCD控制器的地址寄存器LCDSADDR1~3
         * 帧内存与视口(view point)完全吻合,
         * 图像数据格式如下:
         *         |----PAGEWIDTH----|
         *    y/x  0   1   2       639
         *     0   rgb rgb rgb ... rgb
         *     1   rgb rgb rgb ... rgb
         * 1. LCDSADDR1:
         *    设置LCDBANK、LCDBASEU
         * 2. LCDSADDR2:
         *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]
         * 3. LCDSADDR3:
         *    OFFSIZE等于0,PAGEWIDTH等于(640*2/2)
         */
        LCDSADDR1 = ((LCDFRAMEBUFFER>>22)<<21) | LOWER21BITS(LCDFRAMEBUFFER>>1);
        LCDSADDR2 = LOWER21BITS((LCDFRAMEBUFFER+ \
                    (LINEVAL_TFT_640480+1)*(HOZVAL_TFT_640480+1)*2)>>1);
        LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_640480*2/2);

        /* 禁止临时调色板寄存器 */
        TPAL = 0;

        fb_base_addr = LCDFRAMEBUFFER;
        bpp = 16;
        xsize = 640;
        ysize = 480;

        break;

    default:
        break;
    }   
}

/*
 * 设置调色板
 */
void Lcd_Palette8Bit_Init(void)
{
    int i;  
    volatile unsigned int *palette;

    LCDCON1 &= ~0x01;  // stop lcd controller

    LCDCON5 |= (FORMAT8BPP_565<<11); // 设置调色板中数据格式为5:6:5

    palette = (volatile unsigned int *)PALETTE;
    for (i = 0; i < 256; i++)
        *palette++ = DEMO256pal[i];

    LCDCON1 |= 0x01;    // re-enable lcd controller
}

/*
 * 改变调色板为一种颜色
 * 输入参数:
 *     color: 颜色值,格式为0xRRGGBB
 */
void ChangePalette(UINT32 color)
{
    int i;
    unsigned char red, green, blue;
    UINT32 *palette;

    red   = (color >> 19) & 0x1f;
    green = (color >> 10) & 0x3f;
    blue  = (color >>  3) & 0x1f;
    color = (red << 11) | (green << 5) | blue; // 格式5:6:5

    palette=(UINT32 *)PALETTE;
    LCDCON1 &= ~0x01;  // stop lcd controller
    for (i = 0; i < 256; i++)
    {
//        while (((LCDCON5>>15) & 0x3) == 2);     // 等待直到VSTATUS不为”有效”
        *palette++ = color;
    }
    LCDCON1 |= 0x01;    // re-enable lcd controller
}

/*
 * 设置是否输出LCD电源开关信号LCD_PWREN
 * 输入参数:
 *     invpwren: 0 - LCD_PWREN有效时为正常极性
 *               1 - LCD_PWREN有效时为反转极性
 *     pwren:    0 - LCD_PWREN输出有效
 *               1 - LCD_PWREN输出无效
 */
void Lcd_PowerEnable(int invpwren, int pwren)
{
    GPGCON = (GPGCON & (~(3<<8))) | (3<<8);   // GPG4用作LCD_PWREN
    GPGUP  = (GPGUP & (~(1<<4))) | (1<<4);    // 禁止内部上拉    

    LCDCON5 = (LCDCON5 & (~(1<<5))) | (invpwren<<5);  // 设置LCD_PWREN的极性: 正常/反转
    LCDCON5 = (LCDCON5 & (~(1<<3))) | (pwren<<3);     // 设置是否输出LCD_PWREN
}    

/*
 * 设置LCD控制器是否输出信号
 * 输入参数:
 * onoff: 
 *      0 : 关闭
 *      1 : 打开
 */
void Lcd_EnvidOnOff(int onoff)
{
    if (onoff == 1)
    {
        LCDCON1 |= 1;         // ENVID ON
        GPBDAT |= (1<<0);           // Power on
    }
    else
    {
        LCDCON1 &= 0x3fffe;  // ENVID Off
        GPBDAT &= ~(1<<0);  // Power off
    }
}    

/*
 * 使用临时调色板寄存器输出单色图像
 * 输入参数:
 *     color: 颜色值,格式为0xRRGGBB
 */
void ClearScrWithTmpPlt(UINT32 color)
{
    TPAL = (1<<24)|((color & 0xffffff)<<0);
}

/*
 * 停止使用临时调色板寄存器
 */
void DisableTmpPlt(void)
{
    TPAL = 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值