历史上的今天
今天是: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 = .;
}
史海拾趣
|
我最近在做wince+2440,设计的产品为室外无人值守型产品,关于wince能否连续数年稳定可靠的运行一直有所顾虑。 希望做过这些产品的兄弟们给点意见。 另外wince对flash频繁的读写会不会引起坏区,从而要格式化重做系统?… 查看全部问答> |
|
比如AMD和INTEL的CPU,----------又或者其他的牌子的CPU ,比如苹果的CPU,所用的指令系统都是不一样的吧,如果一个指令占2个字节,那么这两个字节的内容对于AMD和INTEL应该都是不同的吧。 那么操作系统如何针对各自不同的CPU生成各自不同的指令呢 ...… 查看全部问答> |
|
我的AT89S52学习版 说明图纸上面 蜂鸣器和二极管第四个灯 都是P1.3针脚控制 用KEIL编程时 灯亮蜂鸣器也响 怎么去分别控制?! 谢谢… 查看全部问答> |
|
#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 ...… 查看全部问答> |
|
管他什么芯片呢,让编译器去翻译就好了,我们所关心的是硬件资源怎样,复杂的东西不容易一下就搞出来而已。 linux算除了写驱动都算搞软件吧。 “程序和程序差别很大”初学者很少有人能理解。… 查看全部问答> |
|
为了进一步完善下载中心,方便大家检索资源,我们准备对资料分类进行调整和修改。本着从群众中来到群众中去的理念,我们决定——发布分类调查投票 特别提示:第二期调查已开始,传送门:https://bbs.eeworld.com.cn/thread-431477-1-1.html ...… 查看全部问答> |
|
大多数数字系统中,除了需要具有逻辑运算和算数功能的组合逻辑电路外,还需要具有存储功能的电路,组合逻辑与时序逻辑可构成时序逻辑电路,简称时序电路。现在讨论实现存储功能的两种逻辑单元电路,即锁存器和触发器。 ...… 查看全部问答> |




