1. 增加Nandflash读取代码
因为要显示图片,而图片明显是放在Nandflash中比较合适,因此需要有能够操作Nandflash的函数。在U-boot中已经有能操作Nandflash的函数了,但是我找了半天也不知道该怎么调用,因此还是上自己的代码吧。
#define NFCONF *(volatile unsigned int *)0x70200000
#define NFCONT *(volatile unsigned int *)0x70200004
#define NFCMMD *(volatile unsigned char *)0x70200008
#define NFADDR *(volatile unsigned int *)0x7020000c
#define NFDATA *(volatile unsigned char *)0x70200010
#define NFSTAT *(volatile unsigned int *)0x70200028
#define NAND_SECTOR_SIZE 2048
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1) #define TACLS 7
#define TWRPH0 7
#define TWRPH1 7 /**
* \brief Nandflash初始化
*/
static void __nand_init(void)
{
NFCONF = (TACLS<<) | (TWRPH0<<) | (TWRPH1<<);
NFCONT = (<<) | (<<) | ();
} static void __nand_select(void)
{
NFCONT &= ~(<<);
} static void __nand_deselect(void)
{
NFCONT |= (<<);
} static void __nand_cmd(unsigned char cmd)
{
NFCMMD = cmd;
} static void __nand_addr (unsigned int addr)
{
unsigned int col = addr&NAND_BLOCK_MASK;
unsigned int page = addr/NAND_SECTOR_SIZE; NFADDR = col & 0xff;
NFADDR = (col>>) & 0xff;
NFADDR = page & 0xff;
NFADDR = (page >> ) & 0xff;
NFADDR = (page >> ) & 0x3;
} static void __nand_wait_teady(void)
{
int i;
while (!(NFSTAT & ))
for (i = ; i < ; i++);
} static unsigned char __nand_data(void)
{
unsigned char p;
p = NFDATA;
return p;
} /**
* \brief 从Nandflash中读取数据至内存中
*/
static void __nand_read (unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % ;
int i = ;
__nand_select();
while (i < len) {
__nand_cmd();
__nand_addr(addr);
__nand_cmd(0x30);
__nand_wait_teady(); for (; col < &&(i < len); col++) {
buf[i] = __nand_data();
i++;
addr++;
}
col = ;
}
__nand_deselect();
} static void __nand_reset(void)
{
__nand_select();
__nand_cmd(0xff);
__nand_wait_teady();
__nand_deselect();
} /**
* \brief 将Nandflash中的内容读取至内存
*/
void nand_copy2ram(unsigned int addr, unsigned char *buff, unsigned int len)
{
//__nand_init();
__nand_reset();
__nand_read(addr, buff, len);
}
注意第101行我把__nand_init注释掉了,因为U-boot起来之后肯定已经对Nandflash初始化过了。
2. 修改LCD代码
lcd.c
#include "lcd.h" static int PEN_COLOR = LCD_RED; /* 定义画笔(前景)颜色 */
static int BK_COLOR = LCD_BLACK; /* 定义背景颜色 */ /**
* \brief LCD初始化
*/
void lcd_init (void)
{
GPICON = ;
GPICON |= 0xaaaaaaaa;
GPJCON = ;
GPJCON |= 0xaaaaaa; MIFPCON &= ~(0x1<<);
SPCON &= ~0x3;
SPCON |= 0x1; VIDCON0 = (<<) | (0x1<<) | (0x3);
VIDCON1 = (0x1<) | (0x1<<); VIDTCON0 = (<<) | (<<) | ();
VIDTCON1 = (<<) | (<<) | (); VIDTCON2 = ((LCD_HEIGHT - ) << ) | (LCD_WIDTH - );
WINCON0 = (0xb<<) | (0x1); VIDOSD0A = ;
VIDOSD0B = ((LCD_WIDTH - ) << ) | ((LCD_HEIGHT - )); VIDOSD0C = LCD_WIDTH * LCD_HEIGHT; VIDW00ADD0B0 = SHOW_BUF;
} /**
* \brief 设置画笔颜色
*/
void lcd_set_pen_color (int color)
{
PEN_COLOR = color;
} /**
* \brief 设置背景颜色
*/
void lcd_set_bk_color (int color)
{
BK_COLOR = color;
} /**
* \brief 绘制一个点
*/
void lcd_draw_point (int x, int y)
{
*((int *)SHOW_BUF + x + y * LCD_WIDTH) = PEN_COLOR;
} void lcd_draw_bk (int x, int y)
{
*((int *)SHOW_BUF + x + y * LCD_WIDTH) = BK_COLOR;
} /**
* \brief 清屏(填充背景色)
*/
void lcd_clean (void)
{
int i, j;
for(i=; i<LCD_HEIGHT; i++) {
for(j=; j<LCD_WIDTH; j++) {
lcd_draw_bk(j, i);
}
}
} /**
* \brief 显示一张BMP图片
*/
void lcd_show_bmp (int x , int y , unsigned char *pic)
{
col_t c;
BITMAPFILEHEADER filehead;
BITMAPINFOHEADER infohead;
int i, j;
unsigned char *p = ;
int width_error = ;
int old_pen_color; memcpy(&filehead , pic, sizeof(filehead));
memcpy(&infohead , pic + sizeof(filehead), sizeof(infohead)); width_error = ( - infohead.biWidth * % ) % ; p = pic + sizeof(filehead) + sizeof(infohead); old_pen_color = PEN_COLOR; c.c.non = ;
for (j = infohead.biHeight-; j>=; j--) {
for (i = ; i < infohead.biWidth; i++) {
c.c.b = *p++;
c.c.g = *p++;
c.c.r = *p++; PEN_COLOR = c.l;
lcd_draw_point(x + i, y + j);
}
p += width_error;
}
PEN_COLOR = old_pen_color;
}
lcd.h
#ifndef __LCD_H
#define __LCD_H /* 定义寄存器地址 */
#define GPICON (*(unsigned int *)0x7F008100)
#define SPCON (*(unsigned int *)0x7F0081A0)
#define MIFPCON (*(unsigned int *)0x7410800c)
#define GPJCON (*(unsigned int *)0x7F008120) #define VIDCON0 (*(unsigned int *)0x77100000)
#define VIDCON1 (*(unsigned int *)0x77100004)
#define VIDCON2 (*(unsigned int *)0x77100008)
#define VIDTCON0 (*(unsigned int *)0x77100010)
#define VIDTCON1 (*(unsigned int *)0x77100014)
#define VIDTCON2 (*(unsigned int *)0x77100018)
#define WINCON0 (*(unsigned int *)0x77100020)
#define WINCON1 (*(unsigned int *)0x77100024)
#define WINCON2 (*(unsigned int *)0x77100028)
#define WINCON3 (*(unsigned int *)0x7710002C)
#define WINCON4 (*(unsigned int *)0x77100030)
#define VIDOSD0A (*(unsigned int *)0x77100040)
#define VIDOSD0B (*(unsigned int *)0x77100044)
#define VIDOSD0C (*(unsigned int *)0x77100048)
#define VIDOSD1A (*(unsigned int *)0x77100050)
#define VIDOSD1B (*(unsigned int *)0x77100054)
#define VIDOSD1C (*(unsigned int *)0x77100058)
#define VIDW00ADD0B0 (*(unsigned int *)0x771000A0)
#define GPECON (*(unsigned int *)0x7f008080)
#define GPEDAT (*(unsigned int *)0x7f008084) #define LCD_WIDTH 480 /* 定义LCD宽度 */
#define LCD_HEIGHT 272 /* 定义LCD高度 */ /* 定义显存地址 */
#define SHOW_BUF 0x54000000 /* 定义常用颜色 */
#define COL(R,G,B) ((R<<16) | (G<<8) | (B))
#define LCD_RED COL(0xFF, 0, 0)
#define LCD_GREEN COL(0, 0xFF, 0)
#define LCD_BLUE COL(0, 0, 0xFF)
#define LCD_WHITE COL(0xFF, 0xFF, 0xFF)
#define LCD_BLACK COL(0, 0, 0) typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned int DWORD;
typedef int LONG; #pragma pack(2)
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 位图文件的类型,必须为BM
DWORD bfSize; // 位图文件的大小,以字节为单位
WORD bfReserved1; // 位图文件保留字,必须为0
WORD bfReserved2; // 位图文件保留字,必须为0
DWORD bfOffBits; // 位图数据的起始位置,以相对于位图
// 文件头的偏移量表示,以字节为单位
} BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 本结构所占用字节数
LONG biWidth; // 位图的宽度,以像素为单位
LONG biHeight; // 位图的高度,以像素为单位
WORD biPlanes; // 目标设备的级别,必须为1
WORD biBitCount; // 每个像素所需的位数,必须是1(双色),
// 4(16色),8(256色)或24(真彩色)之一
DWORD biCompression; // 位图压缩类型,必须是 0(不压缩),
// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
DWORD biSizeImage; // 位图的大小,以字节为单位
LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数
LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数
DWORD biClrUsed; // 位图实际使用的颜色表中的颜色数
DWORD biClrImportant; // 位图显示过程中重要的颜色数
} BITMAPINFOHEADER;
#pragma pack(4) struct _rgb_
{
unsigned char b;
unsigned char g;
unsigned char r;
unsigned char non;
}; typedef union _color_
{
struct _rgb_ c;
unsigned int l;
} col_t; /******************************* 函数声明 **************************/
/**
* \brief LCD初始化
*/
extern void lcd_init (void); /**
* \brief 设置画笔颜色
*/
extern void lcd_set_pen_color (int color); /**
* \brief 设置背景颜色
*/
extern void lcd_set_bk_color (int color); /**
* \brief 绘制一个点
*/
extern void lcd_draw_point (int x, int y); /**
* \brief 清屏(填充背景色)
*/
extern void lcd_clean (void); /**
* \brief 显示一张BMP图片
*/
extern void lcd_show_bmp (int x , int y , unsigned char *pic); #endif
3. 修改board.c和Makefile
去掉原先填充纯色的代码,改为显示图片的代码:
nand_copy2ram第一个参数为Nandflash中要读取的地址,在这里我写的是0x100000,因此运行程序前需要保证该地址有我想要的图片;第二个参数为内存地址,需要与保证其他程序不会使用该地址,且与lcd_show_bmp传入的地址相同;第三个参数为拷贝数据大小,一张480*272的24位图大小不会超过400K,这里传入0x80000足够了。
此外还要修改lib_arm下的Makefile,在COBJS后面加上nand.o后编译。
4. 下载程序
编译成功后在U-boot中将新编译出的U-boot下载进Nandflash的0地址,将BMP图片下载到0x100000地址。重启开发板,能看到LCD上显示出图片。