JZ2440 TFT LCD

一、简介

LCD ( Liquid Crystal Display 的简称)液晶显示器。LCD 的构造是在两片平行的玻璃基板当中放置液晶盒,下基板玻璃上设置TFT(薄膜晶体管),上基板玻璃上设置彩色滤光片,通过TFT上的信号与电压改变来控制液晶分子的转动方向,从而达到控制每个像素点偏振光出射与否而达到显示目的。s3c2440通过lcd控制器来显示图像,在2440内部,存在lcd控制相关的寄存器,其结构图如下:



二、代码解释


1、Makefile,lcd.lds链接脚本,head.s 

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
	
lcd.lds

SECTIONS {
    . = 0x00000000;
    .init : AT(0){ head.o init.o nand.o}
    . = 0x30000000;
    .text : AT(4096) { *(.text) }
    .rodata ALIGN(4) : AT((LOADADDR(.text)+SIZEOF(.text)+3)&~(0x03)) {*(.rodata*)} 
    .data ALIGN(4)   : AT((LOADADDR(.rodata)+SIZEOF(.rodata)+3)&~(0x03)) { *(.data) }
    __bss_start = .;
    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
    __bss_end = .;
}



@******************************************************************************
@ File: head.S
@ 功能: 设置SDRAM,将程序复制到SDRAM,然后跳到SDRAM继续执行
@******************************************************************************       
  
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



    

2、main函数

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("[3] TFT480272 8Bit\n\r");
        printf("[4] TFT480272 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;
            }


3、lcdlib.c

/* 
 * 以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);
}


4、 lcddrv.c

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

/*
 * 初始化用于LCD的引脚
 */
void Lcd_Port_Init(void);
/*

 * 初始化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) 
.......
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);

/*
 * 设置调色板
 */
void Lcd_Palette8Bit_Init(void);

/*
 * 设置LCD控制器是否输出信号
 * 输入参数:
 * onoff: 
 *      0 : 关闭
 *      1 : 打开
 */
void Lcd_EnvidOnOff(int onoff);
/*
 * 设置是否输出LCD电源开关信号LCD_PWREN
 * 输入参数:
 *     invpwren: 0 - LCD_PWREN有效时为正常极性
 *               1 - LCD_PWREN有效时为反转极性
 *     pwren:    0 - LCD_PWREN输出有效
 *               1 - LCD_PWREN输出无效
 */
void Lcd_PowerEnable(int invpwren, int pwren);


/*
 * 使用临时调色板寄存器输出单色图像
 * 输入参数:
 *     color: 颜色值,格式为0xRRGGBB
 */
void ClearScrWithTmpPlt(UINT32 color);


/*
 * 停止使用临时调色板寄存器
 */
void DisableTmpPlt(void);


/*
 * 改变调色板为一种颜色
 * 输入参数:
 *     color: 颜色值,格式为0xRRGGBB
 */
void ChangePalette(UINT32 color);



5、framebuffer.c


/*
 * FILE: framebuffer.c
 * 在framebuffer上画点、画线、画同心圆、清屏的函数接口
 */
#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__


#include <types.h>


/* 
 * 画点
 * 输入参数:
 *     x、y : 象素坐标
 *     color: 颜色值
 *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
 *     需要转换为5:6:5格式
 *         对于8BPP: color为调色板中的索引值,
 *     其颜色取决于调色板中的数值
 */
void PutPixel(UINT32 x, UINT32 y, UINT32 color);


/* 
 * 画线
 * 输入参数:
 *     x1、y1 : 起点坐标
 *     x2、y2 : 终点坐标
 *     color  : 颜色值
 *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
 *     需要转换为5:6:5格式
 *         对于8BPP: color为调色板中的索引值,
 *     其颜色取决于调色板中的数值
 */
void DrawLine(int x1,int y1,int x2,int y2,int color);


/* 
 * 绘制同心圆
 */
void Mire(void);


/* 
 * 将屏幕清成单色
 * 输入参数:
 *     color: 颜色值
 *         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
 *     需要转换为5:6:5格式
 *         对于8BPP: color为调色板中的索引值,
 *     其颜色取决于调色板中的数值
 */
void ClearScr(UINT32 color);


#endif /*__FRAMEBUFFER_H__*/














发布了11 篇原创文章 · 获赞 6 · 访问量 1万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览