历史上的今天
返回首页

历史上的今天

今天是:2024年10月13日(星期日)

正在发生

2018年10月13日 | JZ2440裸板之LCD实验

2018-10-13 来源:eefocus

启动文件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        @ 调用中断初始化函数,此时跳入SDRAM中运行,init_irq函数位于interrupt.c文件中,

                                     @ 链接文件中也规定interrupt.c文件存放在SDRAM的地址

                            

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

    

=====================================================================

init.c源码:

// init.c: 进行一些初始化

  

#include "s3c24xx.h"

 

void disable_watch_dog(void);

void clock_init(void);

void memsetup(void);

void copy_steppingstone_to_sdram(void);

void clean_bss(void);

// 关闭WATCHDOG,否则CPU会不断重启

 

void disable_watch_dog(void)

{

    WTCON = 0;  // 关闭WATCHDOG很简单,往这个寄存器写0即可

}

#define FCLK        200000000

#define HCLK        100000000

#define PCLK        50000000

#define S3C2410_MPLL_200MHZ     ((0x5c<<12)|(0x04<<4)|(0x00))

#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))

// 对于MPLLCON寄存器,[19:12]为MDIV,[9:4]为PDIV,[1:0]为SDIV

// 有如下计算公式:

//  S3C2410: MPLL(FCLK) = (m * Fin)/(p * 2^s)

//  S3C2410: MPLL(FCLK) = (2 * m * Fin)/(p * 2^s)

//  其中: m = MDIV + 8, p = PDIV + 2, s = SDIV

// 对于本开发板,Fin = 12MHz

// 设置CLKDIVN,令分频比为:FCLK:HCLK:PCLK=1:2:4,

// FCLK=200MHz,HCLK=100MHz,PCLK=50MHz

void clock_init(void)

{

    // LOCKTIME = 0x00ffffff;   // 使用默认值即可

    CLKDIVN  = 0x03;                // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1

    // 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” 

__asm__(

    "mrc    p15, 0, r1, c1, c0, 0\n"        // 读出控制寄存器  

    "orr    r1, r1, #0xc0000000\n"       // 设置为“asynchronous bus mode” 

    "mcr    p15, 0, r1, c1, c0, 0\n"        // 写入控制寄存器 

    );

    // 判断是S3C2410还是S3C2440 

    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

    {

        MPLLCON = S3C2410_MPLL_200MHZ;  // 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz 

    }

    else

    {

        MPLLCON = S3C2440_MPLL_200MHZ;  // 现在,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz 

    }       

}

// 设置存储控制器以使用SDRAM

void memsetup(void)

{

    volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

    // 这个函数之所以这样赋值,而不是像前面的实验(比如mmu实验)那样将配置值

    // 写在数组中,是因为要生成”位置无关的代码”,使得这个函数可以在被复制到

    // SDRAM之前就可以在steppingstone中运行

     

    // 存储控制器13个寄存器的值 

    p[0] = 0x22011110;     //BWSCON

    p[1] = 0x00000700;     //BANKCON0

    p[2] = 0x00000700;     //BANKCON1

    p[3] = 0x00000700;     //BANKCON2

    p[4] = 0x00000700;     //BANKCON3  

    p[5] = 0x00000700;     //BANKCON4

    p[6] = 0x00000700;     //BANKCON5

    p[7] = 0x00018005;     //BANKCON6

    p[8] = 0x00018005;     //BANKCON7

    

    

    // HCLK=12MHz:  0x008C07A3,

    // HCLK=100MHz: 0x008C04F4                                     

    p[9]  = 0x008C04F4;     // REFRESH

    

    p[10] = 0x000000B1;     //BANKSIZE

    p[11] = 0x00000030;     //MRSRB6

    p[12] = 0x00000030;     //MRSRB7

}

void copy_steppingstone_to_sdram(void)

{

    unsigned int *pdwSrc  = (unsigned int *)0;

    unsigned int *pdwDest = (unsigned int *)0x30000000;

    

    while (pdwSrc < (unsigned int *)4096)

    {

        *pdwDest = *pdwSrc;

        pdwDest++;

        pdwSrc++;

    }

}

void clean_bss(void)

{

    extern int __bss_start, __bss_end;

    int *p = &__bss_start;

    

    for (; p < &__bss_end; p++)

        *p = 0;

}

int CopyCode2SDRAM(unsigned char *buf, unsigned long start_addr, int size)

{

    extern void nand_read(unsigned char *buf, unsigned long start_addr, int size);

    nand_read(buf, start_addr, size);

    return 0;

}

=====================================================================

nand.c源码:

#define LARGER_NAND_PAGE

#define GSTATUS1        (*(volatile unsigned int *)0x560000B0)

#define BUSY                 1

#define NAND_SECTOR_SIZE      512

#define NAND_BLOCK_MASK     (NAND_SECTOR_SIZE - 1)

#define NAND_SECTOR_SIZE_LP      2048

#define NAND_BLOCK_MASK_LP     (NAND_SECTOR_SIZE_LP - 1)

typedef unsigned int S3C24X0_REG32;

// NAND FLASH (see S3C2410 manual chapter 6) 

typedef struct {

    S3C24X0_REG32   NFCONF;

    S3C24X0_REG32   NFCMD;

    S3C24X0_REG32   NFADDR;

    S3C24X0_REG32   NFDATA;

    S3C24X0_REG32   NFSTAT;

    S3C24X0_REG32   NFECC;

} S3C2410_NAND;

// NAND FLASH (see S3C2440 manual chapter 6, www.100ask.net) 

typedef struct {

    S3C24X0_REG32   NFCONF;

    S3C24X0_REG32   NFCONT;

    S3C24X0_REG32   NFCMD;

    S3C24X0_REG32   NFADDR;

    S3C24X0_REG32   NFDATA;

    S3C24X0_REG32   NFMECCD0;

    S3C24X0_REG32   NFMECCD1;

    S3C24X0_REG32   NFSECCD;

    S3C24X0_REG32   NFSTAT;

    S3C24X0_REG32   NFESTAT0;

    S3C24X0_REG32   NFESTAT1;

    S3C24X0_REG32   NFMECC0;

    S3C24X0_REG32   NFMECC1;

    S3C24X0_REG32   NFSECC;

    S3C24X0_REG32   NFSBLK;

    S3C24X0_REG32   NFEBLK;

} S3C2440_NAND;

typedef struct {

    void (*nand_reset)(void);

    void (*wait_idle)(void);

    void (*nand_select_chip)(void);

    void (*nand_deselect_chip)(void);

    void (*write_cmd)(int cmd);

    void (*write_addr)(unsigned int addr);

    unsigned char (*read_data)(void);

}t_nand_chip;

static S3C2410_NAND * s3c2410nand = (S3C2410_NAND *)0x4e000000;

static S3C2440_NAND * s3c2440nand = (S3C2440_NAND *)0x4e000000;

static t_nand_chip nand_chip;

// 供外部调用的函数 

void nand_init(void);

void nand_read(unsigned char *buf, unsigned long start_addr, int size);

// NAND Flash操作的总入口, 它们将调用S3C2410或S3C2440的相应函数 

static void nand_reset(void);

static void wait_idle(void);

static void nand_select_chip(void);

static void nand_deselect_chip(void);

static void write_cmd(int cmd);

static void write_addr(unsigned int addr);

static unsigned char read_data(void);

// S3C2410的NAND Flash处理函数 

static void s3c2410_nand_reset(void);

static void s3c2410_wait_idle(void);

static void s3c2410_nand_select_chip(void);

static void s3c2410_nand_deselect_chip(void);

static void s3c2410_write_cmd(int cmd);

static void s3c2410_write_addr(unsigned int addr);

static unsigned char s3c2410_read_data();

// S3C2440的NAND Flash处理函数 

static void s3c2440_nand_reset(void);

static void s3c2440_wait_idle(void);

static void s3c2440_nand_select_chip(void);

static void s3c2440_nand_deselect_chip(void);

static void s3c2440_write_cmd(int cmd);

static void s3c2440_write_addr(unsigned int addr);

static unsigned char s3c2440_read_data(void);

// S3C2410的NAND Flash操作函数 

// 复位 

static void s3c2410_nand_reset(void)

{

    s3c2410_nand_select_chip();

    s3c2410_write_cmd(0xff);  // 复位命令

    s3c2410_wait_idle();

    s3c2410_nand_deselect_chip();

}

// 等待NAND Flash就绪 

static void s3c2410_wait_idle(void)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFSTAT;

    while(!(*p & BUSY))

        for(i=0; i<10; i++);

}

// 发出片选信号 

static void s3c2410_nand_select_chip(void)

{

    int i;

    s3c2410nand->NFCONF &= ~(1<<11);

    for(i=0; i<10; i++);    

}

// 取消片选信号 

static void s3c2410_nand_deselect_chip(void)

{

    s3c2410nand->NFCONF |= (1<<11);

}

// 发出命令 

static void s3c2410_write_cmd(int cmd)

{

    volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFCMD;

    *p = cmd;

}

// 发出地址 

static void s3c2410_write_addr(unsigned int addr)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFADDR;

    

    *p = addr & 0xff;

    for(i=0; i<10; i++);

    *p = (addr >> 9) & 0xff;

    for(i=0; i<10; i++);

    *p = (addr >> 17) & 0xff;

    for(i=0; i<10; i++);

    *p = (addr >> 25) & 0xff;

    for(i=0; i<10; i++);

}

// 读取数据 

static unsigned char s3c2410_read_data(void)

{

    volatile unsigned char *p = (volatile unsigned char *)&s3c2410nand->NFDATA;

    return *p;

}

// S3C2440的NAND Flash操作函数 

// 复位 

static void s3c2440_nand_reset(void)

{

    s3c2440_nand_select_chip();

    s3c2440_write_cmd(0xff);  // 复位命令

    s3c2440_wait_idle();

    s3c2440_nand_deselect_chip();

}

// 等待NAND Flash就绪 

static void s3c2440_wait_idle(void)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFSTAT;

    while(!(*p & BUSY))

        for(i=0; i<10; i++);

}

// 发出片选信号 

static void s3c2440_nand_select_chip(void)

{

    int i;

    s3c2440nand->NFCONT &= ~(1<<1);

    for(i=0; i<10; i++);    

}

// 取消片选信号 

static void s3c2440_nand_deselect_chip(void)

{

    s3c2440nand->NFCONT |= (1<<1);

}

// 发出命令 

static void s3c2440_write_cmd(int cmd)

{

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFCMD;

    *p = cmd;

}

// 发出地址 

static void s3c2440_write_addr(unsigned int addr)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    

    *p = addr & 0xff;

    for(i=0; i<10; i++);

    *p = (addr >> 9) & 0xff;

    for(i=0; i<10; i++);

    *p = (addr >> 17) & 0xff;

    for(i=0; i<10; i++);

    *p = (addr >> 25) & 0xff;

    for(i=0; i<10; i++);

}

static void s3c2440_write_addr_lp(unsigned int addr)

{

    int i;

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFADDR;

    int col, page;

    col = addr & NAND_BLOCK_MASK_LP;

    page = addr / NAND_SECTOR_SIZE_LP;

    

    *p = col & 0xff;            // Column Address A0~A7 

    for(i=0; i<10; i++);        

    *p = (col >> 8) & 0x0f;     // Column Address A8~A11 

    for(i=0; i<10; i++);

    *p = page & 0xff;            // Row Address A12~A19 

    for(i=0; i<10; i++);

    *p = (page >> 8) & 0xff;    // Row Address A20~A27 

    for(i=0; i<10; i++);

    *p = (page >> 16) & 0x03;    // Row Address A28~A29 

    for(i=0; i<10; i++);

}

// 读取数据 

static unsigned char s3c2440_read_data(void)

{

    volatile unsigned char *p = (volatile unsigned char *)&s3c2440nand->NFDATA;

    return *p;

}

// 在第一次使用NAND Flash前,复位一下NAND Flash 

static void nand_reset(void)

{

    nand_chip.nand_reset();

}

static void wait_idle(void)

{

    nand_chip.wait_idle();

}

static void nand_select_chip(void)

{

    int i;

    nand_chip.nand_select_chip();

    for(i=0; i<10; i++);

}

static void nand_deselect_chip(void)

{

    nand_chip.nand_deselect_chip();

}

static void write_cmd(int cmd)

{

    nand_chip.write_cmd(cmd);

}

static void write_addr(unsigned int addr)

{

    nand_chip.write_addr(addr);

}

static unsigned char read_data(void)

{

    return nand_chip.read_data();

}

// 初始化NAND Flash 

void nand_init(void)

{

#define TACLS   0

#define TWRPH0  3

#define TWRPH1  0

    // 判断是S3C2410还是S3C2440 

    if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))

    {

        nand_chip.nand_reset         = s3c2410_nand_reset;

        nand_chip.wait_idle          = s3c2410_wait_idle;

        nand_chip.nand_select_chip   = s3c2410_nand_select_chip;

        nand_chip.nand_deselect_chip = s3c2410_nand_deselect_chip;

        nand_chip.write_cmd          = s3c2410_write_cmd;

        nand_chip.write_addr         = s3c2410_write_addr;

        nand_chip.read_data          = s3c2410_read_data;

        // 使能NAND Flash控制器, 初始化ECC, 禁止片选, 设置时序 

        s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

    }

    else

    {

        nand_chip.nand_reset         = s3c2440_nand_reset;

        nand_chip.wait_idle          = s3c2440_wait_idle;

        nand_chip.nand_select_chip   = s3c2440_nand_select_chip;

        nand_chip.nand_deselect_chip = s3c2440_nand_deselect_chip;

        nand_chip.write_cmd          = s3c2440_write_cmd;

#ifdef LARGER_NAND_PAGE

        nand_chip.write_addr         = s3c2440_write_addr_lp;

#else

        nand_chip.write_addr         = s3c2440_write_addr;

#endif

        nand_chip.read_data          = s3c2440_read_data;

        // 设置时序 

        s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

        // 使能NAND Flash控制器, 初始化ECC, 禁止片选 

        s3c2440nand->NFCONT = (1<<4)|(1<<1)|(1<<0);

    }

    

    // 复位NAND Flash 

    nand_reset();

}

// 读函数 

void nand_read(unsigned char *buf, unsigned long start_addr, int size)

{

    int i, j;

#ifdef LARGER_NAND_PAGE

    if ((start_addr & NAND_BLOCK_MASK_LP) || (size & NAND_BLOCK_MASK_LP)) {

        return ;    // 地址或长度不对齐 

    }

#else

    if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {

        return ;    // 地址或长度不对齐 

    }

#endif    

    // 选中芯片 

    nand_select_chip();

    for(i=start_addr; i < (start_addr + size);) 

    {

      // 发出READ0命令 

      write_cmd(0);

      // Write Address 

      write_addr(i);

#ifdef LARGER_NAND_PAGE

      write_cmd(0x30);        

#endif

      wait_idle();

#ifdef LARGER_NAND_PAGE

      for(j=0; j < NAND_SECTOR_SIZE_LP; j++, i++) {

#else

      for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {

#endif

          *buf = read_data();

          buf++;

      }

    }

    // 取消片选信号 

    nand_deselect_chip();

    

    return ;

}

=====================================================================

interrupt.c源码:


#include "s3c24xx.h"

//extern void I2CIntHandle(void);

void (*isr_handle_array[50])(void);

void Dummy_isr(void)

{

    while(1);

}

void init_irq(void)

{

    int i = 0;

    for (i = 0; i < sizeof(isr_handle_array) / sizeof(isr_handle_array[0]); i++)

    {

        isr_handle_array[i] = Dummy_isr;

    }

    INTMOD = 0x0;               // 所有中断都设为IRQ模式

    INTMSK = BIT_ALLMSK;  // 先屏蔽所有中断

//    isr_handle_array[ISR_IIC_OFT]  = I2CIntHandle;

}

void IRQ_Handle(void)

{

    unsigned long oft = INTOFFSET;

    

    //清中断

    if (oft == 4)

        EINTPEND = 1<<7; //EINT4-7合用IRQ4,注意EINTPEND[3:0]保留未用,向这些位写入1会导致未知结果

    SRCPND = 1<

    INTPND = INTPND;     

    // 调用中断服务程序 

    isr_handle_array[oft]();

}

=====================================================================

framebuffer.h源码:

// FILE: framebuffer.h

// 在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__

=====================================================================

framebuffer.c源码:

//FILE: framebuffer.c

// 实现在framebuffer上画点、画线、画同心圆、清屏的函数

#include "framebuffer.h"

extern unsigned int fb_base_addr;

extern unsigned int bpp;

extern unsigned int xsize;

extern unsigned int ysize;

// 画点

// 输入参数:

//     x、y : 象素坐标

//     color: 颜色值

//         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),

//     需要转换为5:6:5格式

//         对于8BPP: color为调色板中的索引值,

//     其颜色取决于调色板中的数值

void PutPixel(UINT32 x, UINT32 y, UINT32 color)

{

    UINT8 red,green,blue;

    switch (bpp){

        case 16:

        {

            UINT16 *addr = (UINT16 *)fb_base_addr + (y * xsize + x);

            red   = (color >> 19) & 0x1f; // 5 BIT

            green = (color >> 10) & 0x3f; // 6 bit

            blue  = (color >>  3) & 0x1f; // 5 bit

            color = (red << 11) | (green << 5) | blue; // 格式5:6:5

            *addr = (UINT16) color;

            break;

        }

        

        case 8:

        {

            UINT8 *addr = (UINT8 *)fb_base_addr + (y * xsize + x);

            *addr = (UINT8) color;

            break;

        }

        default:

            break;

    }

}

// 画线

// 输入参数:

//     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)

{

    int dx,dy,e;

    dx=x2-x1; 

    dy=y2-y1;

    

    if(dx>=0)

    {

        if(dy >= 0)    // dy>=0

        {

            if(dx>=dy) // 1/8 octant

            {

                e=dy-dx/2;

                while(x1<=x2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){y1+=1;e-=dx;}   

                    x1+=1;

                    e+=dy;

                }

            }

            else        // 2/8 octant

            {

                e=dx-dy/2;

                while(y1<=y2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){x1+=1;e-=dy;}   

                    y1+=1;

                    e+=dx;

                }

            }

        }

        else           // dy<0

        {

            dy=-dy;    // dy=abs(dy)

            if(dx>=dy) // 8/8 octant

            {

                e=dy-dx/2;

                while(x1<=x2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){y1-=1;e-=dx;}   

                    x1+=1;

                    e+=dy;

                }

            }

            else        // 7/8 octant

            {

                e=dx-dy/2;

                while(y1>=y2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){x1+=1;e-=dy;}   

                    y1-=1;

                    e+=dx;

                }

            }

        }   

    }

    else //dx<0

    {

        dx=-dx;        //dx=abs(dx)

        if(dy >= 0)    // dy>=0

        {

            if(dx>=dy) // 4/8 octant

            {

                e=dy-dx/2;

                while(x1>=x2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){y1+=1;e-=dx;}   

                    x1-=1;

                    e+=dy;

                }

            }

            else        // 3/8 octant

            {

                e=dx-dy/2;

                while(y1<=y2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){x1-=1;e-=dy;}   

                    y1+=1;

                    e+=dx;

                }

            }

        }

        else           // dy<0

        {

            dy=-dy;    // dy=abs(dy)

            if(dx>=dy) // 5/8 octant

            {

                e=dy-dx/2;

                while(x1>=x2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){y1-=1;e-=dx;}   

                    x1-=1;

                    e+=dy;

                }

            }

            else        // 6/8 octant

            {

                e=dx-dy/2;

                while(y1>=y2)

                {

                    PutPixel(x1,y1,color);

                    if(e>0){x1-=1;e-=dy;}   

                    y1-=1;

                    e+=dx;

                }

            }

        }   

    }

}

// 绘制同心圆

void Mire(void)

{

    UINT32 x,y;

    UINT32 color;

    UINT8 red,green,blue,alpha;

    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 |= ((UINT32)alpha << 24);

            color |= ((UINT32)red   << 16);

            color |= ((UINT32)green << 8 );

            color |= ((UINT32)blue       );

            PutPixel(x,y,color);

        }

}

// 将屏幕清成单色

// 输入参数:

//     color: 颜色值

//         对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),

//     需要转换为5:6:5格式

//         对于8BPP: color为调色板中的索引值,

//     其颜色取决于调色板中的数值

void ClearScr(UINT32 color)

{   

    UINT32 x,y;

    

    for (y = 0; y < ysize; y++)

        for (x = 0; x < xsize; x++)

            PutPixel(x, y, color);

}

=====================================================================

lcddrv.h源码:

// FILE: lcddrv.h

// 操作LCD控制器、调色板等的底层函数接口

 

#ifndef __LCDDRV_H__

#define __LCDDRV_H__

#include

#define LOWER21BITS(n)  ((n) & 0x1fffff)

#define BPPMODE_1BPP    0x8

#define BPPMODE_2BPP    0x9

#define BPPMODE_4BPP    0xA

#define BPPMODE_8BPP    0xB

#define BPPMODE_16BPP   0xC

#define BPPMODE_24BPP   0xD

#define LCDTYPE_TFT     0x3

#define ENVID_DISABLE   0

#define ENVID_ENABLE    1

#define FORMAT8BPP_5551 0

#define FORMAT8BPP_565  1

#define HSYNC_NORM      0

#define HSYNC_INV       1

#define VSYNC_NORM      0

#define VSYNC_INV       1

#define BSWP            1

#define HWSWP           1

//TFT LCD Panel(240*320)

#define MODE_TFT_1BIT_240320     (0x4101)

#define MODE_TFT_8BIT_240320      (0x4102)

#define MODE_TFT_16BIT_240320    (0x4104)

#define MODE_TFT_24BIT_240320    (0x4108)

//TFT 240320

#define LCD_XSIZE_TFT_240320     (240)    

#define LCD_YSIZE_TFT_240320     (320)

//TFT 240320

#define HOZVAL_TFT_240320    (LCD_XSIZE_TFT_240320-1)

#define LINEVAL_TFT_240320    (LCD_YSIZE_TFT_240320-1)

#define CLKVAL_TFT_240320    (4)

// 60hz @133Mhz

// (9) 60hz @100Mhz

//Timing parameter for LTS350Q1(SAMSUNG) 

#define VBPD_240320        ((6-1)&0xff)

#define VFPD_240320        ((4-1)&0xff)

#define VSPW_240320        ((2-1) &0x3f)

#define HBPD_240320        ((11-1)&0x7f)

#define HFPD_240320        ((2-1)&0xff)

#define HSPW_240320        ((1-1)&0xff)

//TFT LCD Panel(640*480)

#define MODE_TFT_1BIT_640480     (0x4201)

#define MODE_TFT_8BIT_640480     (0x4202)

#define MODE_TFT_16BIT_640480    (0x4204)

#define MODE_TFT_24BIT_640480    (0x4208)

//TFT 640480

#define LCD_XSIZE_TFT_640480     (640)    

#define LCD_YSIZE_TFT_640480     (480)

//TFT640480

#define HOZVAL_TFT_640480    (LCD_XSIZE_TFT_640480-1)

#define LINEVAL_TFT_640480    (LCD_YSIZE_TFT_640480-1)

//Timing parameter for V16C6448AB(PRIME VIEW) 

#define VBPD_640480        ((33-1)&0xff)

#define VFPD_640480        ((10-1)&0xff)

#define VSPW_640480        ((2-1) &0x3f)

#define HBPD_640480        ((48-1)&0x7f)

#define HFPD_640480        ((16-1)&0xff)

#define HSPW_640480        ((96-1)&0xff)

#define CLKVAL_TFT_640480     (1)

    //53.5hz @90Mhz

    //VSYNC,HSYNC should be inverted

    //HBPD=47VCLK,HFPD=15VCLK,HSPW=95VCLK

    //VBPD=32HSYNC,VFPD=9HSYNC,VSPW=1HSYNC

#define LCDFRAMEBUFFER 0x30400000

// 初始化用于LCD的引脚

void Lcd_Port_Init(void);

// 初始化LCD控制器

// 输入参数:

// type: 显示模式

//      MODE_TFT_8BIT_640480  : 640*640 8bpp的TFT LCD

//      MODE_TFT_16BIT_640480 : 640*640 16bpp的TFT LCD

void Tft_Lcd_Init(int type);

// 设置调色板

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);

#endif //__LCDDRV_H__

=====================================================================

lcddrv.c源码:

// 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;

}

=====================================================================

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);

}

=====================================================================

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;

}

====================================================================

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

    

=====================================================================

链接文件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 = .;

}



推荐阅读

史海拾趣

Exar公司的发展小趣事

Exar公司从一个小型创业公司起步,凭借其独特的技术和创新的思维,在电子行业中崭露头角。公司初期专注于数据传输和存储技术的研发,通过不断的技术创新和产品优化,逐渐在市场上建立起良好的口碑。随着公司规模的扩大,Exar开始涉足更多的领域,包括网络通信、消费电子等,逐步发展成为一家跨行业的综合性企业。

Exar [Exar Corporation]公司的发展小趣事

Exar始终注重通过收购和合并来增强自身的技术实力和市场竞争力。例如,2012年Exar收购了Integrated Memory Logic Limited(iML),这一举措加强了其在存储和数据管理领域的地位。通过收购iML,Exar获得了更多的技术资源和市场份额,为其后续的发展提供了有力支持。

粤翔(FlyWin)公司的发展小趣事
完成电路设计后,进行严格的测试验证,确保掉电保护电路在实际应用中能够正常工作。
FCT Electronics公司的发展小趣事

在国内市场取得成功后,FCT Electronics开始将目光投向国际市场。公司积极参加国际电子展会,与多家国际知名企业建立了合作关系。凭借出色的产品性能和专业的客户服务,FCT Electronics的测试设备逐渐在海外市场上占据了一席之地,为公司的国际化发展奠定了坚实基础。

GE Power Electronics Inc公司的发展小趣事
作为家居装饰品的一部分,如声控音乐盒、声控台灯等,通过声音控制实现特定的功能或效果。
客益(Guestgood)公司的发展小趣事
在电路制作完成后,进行充分的测试验证,包括功能测试、性能测试和可靠性测试等。通过测试发现并解决潜在问题,确保电路的稳定性和可靠性。

问答坊 | AI 解惑

wince稳定性问题,欢迎探讨

我最近在做wince+2440,设计的产品为室外无人值守型产品,关于wince能否连续数年稳定可靠的运行一直有所顾虑。 希望做过这些产品的兄弟们给点意见。 另外wince对flash频繁的读写会不会引起坏区,从而要格式化重做系统?…

查看全部问答>

求高手赐教,为什么一个操作系统可以安装到不同的CPU上?

比如AMD和INTEL的CPU,----------又或者其他的牌子的CPU ,比如苹果的CPU,所用的指令系统都是不一样的吧,如果一个指令占2个字节,那么这两个字节的内容对于AMD和INTEL应该都是不同的吧。 那么操作系统如何针对各自不同的CPU生成各自不同的指令呢 ...…

查看全部问答>

蜂鸣器和二极管第四个灯 都是P1.3针脚控制?

我的AT89S52学习版 说明图纸上面 蜂鸣器和二极管第四个灯 都是P1.3针脚控制 用KEIL编程时 灯亮蜂鸣器也响 怎么去分别控制?! 谢谢…

查看全部问答>

都哪家公司有F107的开发板?

                                 想买一个,正在做产品升级,比较急,有些技术细节搞不准。…

查看全部问答>

我这个51单片机模拟的读写程序有错么?

#include <C8051F410.h> #include <intrins.h> sbit SPI_Clk = P0^2;sbit SPI_Out = P0^3;sbit SPI_In  = P0^6;sbit SPI_Cs  = P0^7; void System_Setup(void);void SPI_Write(unsigned int SPI_Data);unsigned int SPI_Read(v ...…

查看全部问答>

也在搞arm,搞硬件其实感觉差不多啊

管他什么芯片呢,让编译器去翻译就好了,我们所关心的是硬件资源怎样,复杂的东西不容易一下就搞出来而已。   linux算除了写驱动都算搞软件吧。   “程序和程序差别很大”初学者很少有人能理解。…

查看全部问答>

下载中心分类调查开始啦!投票有惊喜!(第一期)

为了进一步完善下载中心,方便大家检索资源,我们准备对资料分类进行调整和修改。本着从群众中来到群众中去的理念,我们决定——发布分类调查投票 特别提示:第二期调查已开始,传送门:https://bbs.eeworld.com.cn/thread-431477-1-1.html ...…

查看全部问答>

有没有必要给所有的输入IO口都加上拉电阻?

为了提高抗干扰性能,有没有必要给所有的输入IO口都加上拉电阻?请指点一下。…

查看全部问答>

你经常使用哪些嵌入式操作系统呢?

大家来说说你都用哪些嵌入式操作系统呢,是windowsce,是linux ,是ucos,还是???看看哪种使用最广泛! …

查看全部问答>

凔海笔记之FPGA(七):触发器和锁存器

       大多数数字系统中,除了需要具有逻辑运算和算数功能的组合逻辑电路外,还需要具有存储功能的电路,组合逻辑与时序逻辑可构成时序逻辑电路,简称时序电路。现在讨论实现存储功能的两种逻辑单元电路,即锁存器和触发器。 ...…

查看全部问答>