本文使用的uboot版本是2010.12版本。首先讲述下显示的基本原理。
一、位图、调色板和bmp文件格式
1.1、位图和调色板
显示器屏幕是由许许多多点构成的,我们称之为象素。显示时采用扫描的方法:电子枪每次从左到右扫描一行,为每个象素着色,然后从上到下这样扫描若干行,就扫过了一屏。为了防止闪烁,每秒要重复上述过程几十次。例如我们常说的屏幕分辨率为800×480,刷新频率为70Hz,意思是说每行要扫描800个象素,一共有480行,每秒重复扫描屏幕70次。 我们称这种显示器为位映象设备。所谓位映象,就是指一个二维的象素矩阵,而位图就是采用位映象方法显示和存储的图象。
自然界中的所有颜色都可以由红、绿、蓝(R,G,B)组合而成。有的颜色含有红色成分多一些,如深红;有的含有红色成分少一些,如浅红。针对含有红色成分的多少,可以分成0到255共256个等级,0级表示不含红色成分;255级表示含有100%的红色成分。同样绿色和蓝色也被分成256级。这种分级概念称为量化。这样根据红、绿、蓝各种不同的组合就能表示出256×256×256,约1600万种颜色。
表1.1 常见颜色的RGB组合值
颜色
|
R
|
G
|
B
|
红
|
255
|
0
|
0
|
蓝
|
0
|
255
|
0
|
绿
|
0
|
0
|
255
|
黄
|
255
|
255
|
0
|
紫
|
255
|
0
|
255
|
青
|
0
|
255
|
255
|
白
|
255
|
255
|
255
|
黑
|
0
|
0
|
0
|
灰
|
128
|
128
|
128
|
当一幅图中每个象素赋予不同的RGB值时,能呈现出五彩缤纷的颜色,这样就形成了彩色图。
例如有一个长宽各为200个象素,颜色数为16色的彩色图,每一个象素都用R、G、B三个分量表示。因为每个分量有256个级别,要用8位(bit),即一个字节(byte)来表示,所以每个象素需要用3个字节。整个图象要用200×200×3,约120k字节,如果用下面的方法就能省的多。因为是一个16色图,也就是说这幅图中最多只有16种颜色,我们可以用一个表:表中的每一行记录一种颜色的R、G、B值。这样当我们表示一个象素的颜色时,只需要指出该颜色是在第几行,即该颜色在表中的索引值。举个例子,如果表的第0行为255,0,0(红色),那么当某个象素为红色时,只需要标明0即可。
16种状态可以用4位(bit)表示,所以一个象素要用半个字节。整个图象要用200×200×0.5,约20k字节,再加上表占用的字节为3×16=48字节。整个占用的字节数约为前面的1/6。这张R、G、B的表,就是我们常说的调色板(Palette),另一种叫法是颜色查找表LUT(Look
Up Table)。
本文中使用的是RGB565彩色模式, 一个像素占两个字节,其中:低字节的前5位用来表示B(BLUE),低的后三位+高字节的前三位用来表示G(Green)高字节的后5位用来表示R(RED)。
有一种图,它的颜色数高达256×256×256种,也就是说包含我们上述提到的R、G、B颜色表示方法中所有的颜色,这种图叫做真彩色图(true color)。真彩色图并不是说一幅图包含了所有的颜色,而是说它具有显示所有颜色的能力,即最多可以包含所有的颜色。表示真彩色图时,每个象素直接用R、G、B三个分量字节表示,而不采用调色板技术。原因很明显:如果用调色板,表示一个象素也要用24位,这是因为每种颜色的索引要用24位(因为总共有224种颜色,即调色板有224行),和直接用R,G,B三个分量表示用的字节数一样,还要加上一个256×256×256×3个字节的大调色板。所以真彩色图直接用R、G、B三个分量表示,它又叫做24位色图。
1.2、bmp文件格式
bmp文件大体上分成四个部分,如下图所示。
位图文件头BITMAPFILEHEADER
|
位图信息头BITMAPINFOHEADER
|
调色板Palette
|
实际的位图数据ImageDate
|
Windows位图文件结构示意图
第一部分为位图文件头BITMAPFILEHEADER,是一个结构,其定义如下:
typedef struct tagBITMAPFILEHEADER
{
WORD
bfType;
DWORD bfSize;
WORD
bfReserved1;
WORD
bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
这个结构的长度是固定的,为14个字节(WORD为无符号16位整数,DWORD为无符号32位整数),各个域的说明如下:
bfType:指定文件类型,必须是0x424D,即字符串“BM”,也就是说所有.bmp文件的头两个字节都是“BM”。在4.3中打开文件后即判别是否为此字符,如果不是,错误退出。
bfSize:指定文件大小,包括这14个字节。
bfReserved1,bfReserved2:为保留字,不用考虑
bfOffBits:为从文件头到实际的位图数据的偏移字节数,即上图中前三个部分的长度之和。
第二部分为位图信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG
biWidth;
LONG
biHeight;
WORD
biPlanes;
WORD
biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG
biXPelsPerMeter;
LONG
biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
这个结构的长度是固定的,为40个字节(LONG为32位整数),各个域的说明如下:
biSize:指定这个结构体的长度,为40。
biWidth:指定图象的宽度,单位是象素。
biHeight:指定图象的高度,单位是象素。
biPlanes:必须是1,不用考虑。
biBitCount:指定表示颜色时要用到的位数,常用的值为1(黑白二色图), 4(16色图), 8(256色), 24(真彩色图)。
biCompression:指定位图是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS。
biSizeImage:指定实际的位图数据占用的字节数,其实也可以从以下的公式中计算出来:
biSizeImage=biWidth’
× biHeight
要注意的是:上述公式中的biWidth’必须是4的整倍数(所以不是biWidth,而是biWidth’,表示大于或等于biWidth的,最接近4的整倍数。举个例子,如果biWidth=240,则biWidth’=240;如果biWidth=241,biWidth’=244)。
如果biCompression为BI_RGB,则该项可能为零
biXPelsPerMeter:指定目标设备的水平分辨率,单位是每米的象素个数,关于分辨率的概念,我们将在第4章详细介绍。
biYPelsPerMeter:指定目标设备的垂直分辨率,单位同上。
biClrUsed:指定本图象实际用到的颜色数,如果该值为零,则用到的颜色数为2biBitCount。
biClrImportant:指定本图象中重要的颜色数,如果该值为零,则认为所有的颜色都是重要的。
第三部分为调色板Palette,当然这里是对那些需要调色板的位图文件而言的。有些位图,如真彩色图是不需要调色板的,BITMAPINFOHEADER后直接是位图数据。
调色板实际上是一个数组,共有biClrUsed个元素(如果该值为零,则有2biBitCount个元素)。数组中每个元素的类型是一个RGBQUAD结构,占4个字节,其定义如下:
typedef struct tagRGBQUAD {
BYTE rgbBlue; //该颜色的蓝色分量
BYTE rgbGreen; //该颜色的绿色分量
BYTE rgbRed; //该颜色的红色分量
BYTE rgbReserved; //保留值
} RGBQUAD;
第四部分就是实际的图象数据了。对于用到调色板的位图,图象数据就是该象素颜在调色板中的索引值。对于真彩色图,图象数据就是实际的R、G、B值。下面针对2色、16色、256色位图和真彩色位图分别介绍。
对于2色位图,用1位就可以表示该象素的颜色(一般0表示黑,1表示白),所以一个字节可以表示8个象素。
对于16色位图,用4位可以表示一个象素的颜色,所以一个字节可以表示2个象素。
对于256色位图,一个字节刚好可以表示1个象素。
对于真彩色图,三个字节才能表示1个象素。
要注意两点:
(1) 每一行的字节数必须是4的整倍数,如果不是,则需要补齐。这在前面介绍biSizeImage时已经提到了。
(2) 一般来说,.bMP文件的数据从下到上,从左到右的。也就是说,从文件中最先读到的是图象最下面一行的左边第一个象素,然后是左边第二个象素……接下来是倒数第二行左边第一个象素,左边第二个象素……依次类推 ,最后得到的是最上面一行的最右一个象素。
二、logo显示调用流程
在uboot移植(二)中讲述了uboot执行的第二个步骤是进入board_init_r()函数(/arch/mips/lib/board.c文件中),现在来讲述下logo显示的调用流程:
board_init_r()->stdio_init()(common/stdio.c文件中)->drv_video_init()(drivers/video/cfb_console.c文件中)->video_init()(drivers/video/cfb_console.c文件中)。
在video_init()函数中,首先调用了video_hw_init()函数,该函数初始化GSC3280芯片的LCD控制器和GraphicDevice结构体。video_init()函数调用video_logo()函数显示logo图片。
接下来主要讲述video_hw_init()和video_logo()函数。
三、GSC3280 LCD初始化
芯片初始化包括初始化芯片内部控制寄存器和设置像素信息等。
在uboot源码的根目录下,drivers/video/目录下建立gsc3280_lcdfb.c文件,video_hw_init()程序如下:
-
GraphicDevice fb;
-
-
static void gsc3280_lcd_init(void)
-
{
-
printf("init lcd sysctl\n");
-
lcdc_disable();
-
lcd_sysctl();
-
gsc3280_ctr_init();
-
lcdc_dma_init((void *)DEFAULT_VIDEO_HW_ADDR);
-
lcdc_monitor_para(0);
-
lcd_enable();
-
}
-
void *video_hw_init(void)
-
{
-
memset(&fb, 0, sizeof(GraphicDevice));
-
fb.winSizeX = MAX_VIDEO_WIDTH_LEN;
-
fb.winSizeY = MAX_VIDEO_HIGH_LEN;
-
//over 16M from the head of kseg1, unmapped and uncacheable ddr2 address
-
fb.frameAdrs = DEFAULT_VIDEO_BASE_ADDR;
-
fb.plnSizeX = fb.winSizeX;
-
fb.plnSizeY = fb.winSizeY;
-
fb.gdfBytesPP = COLOR_PIXEL_SIZE / 8;
-
fb.gdfIndex = GDF_16BIT_565RGB;
-
fb.isaBase = 0;
-
fb.pciBase = 0;
-
fb.memSize = fb.winSizeX * fb.winSizeY * fb.gdfBytesPP;
-
/* Cursor Start Address */
-
fb.dprBase = 0;
-
fb.vprBase = 0;
-
fb.cprBase = 0;
-
gsc3280_lcd_init();
-
return &fb;
-
}
说明:
1) 第16和17行分别定义了X和Y方向的分辨率,为800*480。
2) 接下来初始化了GraphicDevice结构体成员。
3) gsc3280_lcd_init()函数完成GSC3280的LCD模块、DMA等初始化。
四、uboot显示logo
video_logo()函数完成显示logo,该函数位于/drivers/video/cfb_console.c文件中。
4.1、宏定义
在显示图片时,需要定义一些宏,这些宏在显示流程中会被使用,它们定义在“include/config/blx.h”文件中,包括:
-
#define CONFIG_VIDEO
-
#define CONFIG_CMD_BMP
-
#define CONFIG_VIDEO_LOGO
-
#define CONFIG_CFB_CONSOLE
-
#define CONFIG_VIDEO_BMP_LOGO
-
#define VIDEO_FB_16BPP_WORD_SWAP
-
-
#define CONFIG_GSC3280_LCD
-
#define CONFIG_GSC3280_CMD_LCD
4.2、制作logo图片
logo图片必须是bmp格式的,这个bmp文件位深度必须为8位,大小也有限制,自己做个格式为".jpg"的logo图片即可,使用linux下的图片工具转成8位的bmp文件,命令如下:
-
jpegtopnm logo.jpg | ppmquant 31 | ppmtobmp -bpp 8 > denx.bmp
将生成的”denx.bmp“文件覆盖”tools/logo/“下的原文件即可。
4.3、制作图片显示数据
”tools/bmp_logo.c“文件实现将图片转换为数组数据,该文件中有main()函数,这说明此文件是单独执行的,具体的执行程序地点就在:”tools/Makefile“文件中有如下语句:
-
LOGO_H = $(OBJTREE)/include/bmp_logo.h
-
-
ifeq ($(LOGO_BMP),)
-
LOGO_BMP= logos/denx.bmp
-
endif
-
-
$(LOGO_H): $(obj)bmp_logo $(LOGO_BMP)
-
$(obj)./bmp_logo $(LOGO_BMP) >$@
说明:
1) 第7行实现了logo显示数组的生成,调用"bmp_logo"可执行文件,有一个参数即是我们在4.2中拷贝的图片,最后生成的数据保存在”include/bmp_logo.h“文件中。
”tools/bmp_logo.c“文件中的main函数如下:
-
int main (int argc, char *argv[])
-
{
-
int i, x;
-
FILE *fp;
-
bitmap_t bmp;
-
bitmap_t *b = &bmp;
-
uint16_t data_offset, n_colors;
-
-
if (argc < 2) {
-
fprintf (stderr, "Usage: %s file\n", argv[0]);
-
exit (EXIT_FAILURE);
-
}
-
-
if ((fp = fopen (argv[1], "rb")) == NULL) {
-
perror (argv[1]);
-
exit (EXIT_FAILURE);
-
}
-
-
if (fgetc (fp) != 'B' || fgetc (fp) != 'M')
-
error ("Input file is not a bitmap", fp);
-
-
/*
-
* read width and height of the image, and the number of colors used;
-
* ignore the rest
-
*/
-
skip_bytes (fp, 8);
-
if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1)
-
error ("Couldn't read bitmap data offset", fp);
-
skip_bytes (fp, 6);
-
if (fread (&b->width, sizeof (uint16_t), 1, fp) != 1)
-
error ("Couldn't read bitmap width", fp);
-
skip_bytes (fp, 2);
-
if (fread (&b->height, sizeof (uint16_t), 1, fp) != 1)
-
error ("Couldn't read bitmap height", fp);
-
skip_bytes (fp, 22);
-
if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1)
-
error ("Couldn't read bitmap colors", fp);
-
skip_bytes (fp, 6);
-
-
/*
-
* Repair endianess.
-
*/
-
data_offset = le_short(data_offset);
-
b->width = le_short(b->width);
-
b->height = le_short(b->height);
-
n_colors = le_short(n_colors);
-
-
/* assume we are working with an 8-bit file */
-
if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
-
/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
-
n_colors = 256 - DEFAULT_CMAP_SIZE;
-
}
-
-
printf ("/*\n"
-
" * Automatically generated by \"tools/bmp_logo\"\n"
-
" *\n"
-
" * DO NOT EDIT\n"
-
" *\n"
-
" */\n\n\n"
-
"#ifndef __BMP_LOGO_H__\n"
-
"#define __BMP_LOGO_H__\n\n"
-
"#define BMP_LOGO_WIDTH\t\t%d\n"
-
"#define BMP_LOGO_HEIGHT\t\t%d\n"
-
"#define BMP_LOGO_COLORS\t\t%d\n"
-
"#define BMP_LOGO_OFFSET\t\t%d\n"
-
"\n",
-
b->width, b->height, n_colors,
-
DEFAULT_CMAP_SIZE);
-
-
/* allocate memory */
-
if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL)
-
error ("Error allocating memory for file", fp);
-
-
/* read and print the palette information */
-
printf ("unsigned short bmp_logo_palette[] = {\n");
-
-
for (i=0; i<n_colors; ++i) {
-
b->palette[(int)(i*3+2)] = fgetc(fp);
-
b->palette[(int)(i*3+1)] = fgetc(fp);
-
b->palette[(int)(i*3+0)] = fgetc(fp);
-
x=fgetc(fp);
-
-
printf ("%s0x0%X%X%X,%s",
-
((i%8) == 0) ? "\t" : " ",
-
(b->palette[(int)(i*3+0)] >> 4) & 0x0F,
-
(b->palette[(int)(i*3+1)] >> 4) & 0x0F,
-
(b->palette[(int)(i*3+2)] >> 4) & 0x0F,
-
((i%8) == 7) ? "\n" : ""
-
);
-
}
-
-
/* seek to offset indicated by file header */
-
fseek(fp, (long)data_offset, SEEK_SET);
-
-
/* read the bitmap; leave room for default color map */
-
printf ("\n");
-
printf ("};\n");
-
printf ("\n");
-
printf ("unsigned char bmp_logo_bitmap[] = {\n");
-
for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
-
for (x = 0; x < b->width; x++) {
-
b->data[(uint32_t) i + x] = (uint8_t) fgetc (fp) \
-
+ DEFAULT_CMAP_SIZE;
-
}
-
}
-
fclose (fp);
-
-
for (i=0; i<(b->height*b->width); ++i) {
-
if ((i%8) == 0)
-
putchar ('\t');
-
printf ("0x%02X,%c",
-
b->data[i],
-
((i%8) == 7) ? '\n' : ' '
-
);
-
}
-
printf ("\n"
-
"};\n\n"
-
"#endif /* __BMP_LOGO_H__ */\n"
-
);
-
-
return (0);
-
}
说明:
1) 第9-12行检查参数是否正确,如果错误直接返回。
2) 第14行以二进制读的方式打开图片文件,如果打开错误直接返回,如果打开正确,返回文件描述符fd。
3) 第19行判断此图片是否为bmp格式,如果不是,打印错误。
4) 第26-38行从图片中读取图片的像素和颜色值。
5) 第71行根据从图片取得的像素值分配数据存储空间。
6) 第77-90行从图片中取得调色板数组的值。
7) 第100-105行从图片取得调色板中的索引值。
8) 上面取数据的顺序按照1.2的bmp图片存储格式来获取的。
9) bmp_logo.c文件中,有一个地方程序需要更改,如果不改,只能显示半屏数据,修改的是bmp_logo.c文件中main()函数语句,内容如下:
-
for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
-
for (x = 0; x < b->width; x++) {
-
b->data[(uint32_t) i + x] = (uint8_t) fgetc (fp) \
-
+ DEFAULT_CMAP_SIZE;
-
}
-
}
红色部分即为修改内容,原来为uint16_t。
4.4、显示logo函数
video_logo()函数调用“void logo_plot (void *screen, int width, int x, int y)”函数完成最终的显示,该函数有四个形参,为:
*screen:显示区域内存首地址。
width:显示屏幕的宽度,对于此处即为800。
x,y:屏幕显示的起始位置,我们可以让logo从屏幕头开始显示,那么此处x和y的值就是(0,0),当然我们也可以让它从屏幕上其它点开始显示,只要输入相应的起点坐标即可。比如我们现在需要显示的图片的像素为300*77,经过计算,如果想要这个图片显示在800*480屏幕的中间,那么起始坐标为(250,202),即调用logo_plot()函数为:
-
logo_plot (video_fb_address, VIDEO_COLS, 250, 202);
logo_plot()程序如下:
-
#ifdef CONFIG_VIDEO_LOGO
-
void logo_plot (void *screen, int width, int x, int y)
-
{
-
-
int xcount, i;
-
int skip = (width - VIDEO_LOGO_WIDTH) * VIDEO_PIXEL_SIZE;
-
volatile int ycount = video_logo_height;
-
unsigned char r, g, b, *logo_red, *logo_blue, *logo_green;
-
unsigned char *source;
-
unsigned char *dest = (unsigned char *)screen +
-
((y * width * VIDEO_PIXEL_SIZE) +
-
x * VIDEO_PIXEL_SIZE);
-
-
#ifdef CONFIG_VIDEO_BMP_LOGO
-
source = bmp_logo_bitmap;
-
-
/* Allocate temporary space for computing colormap */
-
logo_red = malloc (BMP_LOGO_COLORS);
-
logo_green = malloc (BMP_LOGO_COLORS);
-
logo_blue = malloc (BMP_LOGO_COLORS);
-
/* Compute color map */
-
for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
-
logo_red[i] = (bmp_logo_palette[i] & 0x0f00) >> 4;
-
logo_green[i] = (bmp_logo_palette[i] & 0x00f0);
-
logo_blue[i] = (bmp_logo_palette[i] & 0x000f) << 4;
-
}
-
#else
-
source = linux_logo;
-
logo_red = linux_logo_red;
-
logo_green = linux_logo_green;
-
logo_blue = linux_logo_blue;
-
#endif
-
-
if (VIDEO_DATA_FORMAT == GDF__8BIT_INDEX) {
-
for (i = 0; i < VIDEO_LOGO_COLORS; i++) {
-
video_set_lut (i + VIDEO_LOGO_LUT_OFFSET,
-
logo_red[i], logo_green[i], logo_blue[i]);
-
}
-
}
-
-
//plot the blackground 800 * 480
-
#if 1
-
ycount = 480;
-
while (ycount--) {
-
xcount = 800;
-
while (xcount--) {
-
r = 0;
-
g = 0;
-
b = 0;
-
*(unsigned short *) dest =
-
SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
-
//source++;
-
dest += VIDEO_PIXEL_SIZE;
-
}
-
//dest += skip;
-
}
-
#endif
-
-
#if 1
-
ycount = video_logo_height;
-
source = bmp_logo_bitmap;
-
dest = (unsigned char *)screen +
-
((y * width * VIDEO_PIXEL_SIZE) +
-
x * VIDEO_PIXEL_SIZE);
-
-
while (ycount--) {
-
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
-
int xpos = x;
-
#endif
-
xcount = VIDEO_LOGO_WIDTH;
-
while (xcount--) {
-
r = logo_red[*source - VIDEO_LOGO_LUT_OFFSET];
-
g = logo_green[*source - VIDEO_LOGO_LUT_OFFSET];
-
b = logo_blue[*source - VIDEO_LOGO_LUT_OFFSET];
-
-
switch (VIDEO_DATA_FORMAT) {
-
case GDF__8BIT_INDEX:
-
*dest = *source;
-
break;
-
case GDF__8BIT_332RGB:
-
*dest = ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
-
break;
-
case GDF_15BIT_555RGB:
-
#if defined(VIDEO_FB_16BPP_PIXEL_SWAP)
-
fill_555rgb_pswap (dest, xpos++, r, g, b);
-
#else
-
*(unsigned short *) dest =
-
SWAP16 ((unsigned short) (((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3)));
-
#endif
-
break;
-
case GDF_16BIT_565RGB:
-
*(unsigned short *) dest =
-
SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
-
break;
-
case GDF_32BIT_X888RGB:
-
*(unsigned long *) dest =
-
SWAP32 ((unsigned long) ((r << 16) | (g << 8) | b));
-
break;
-
case GDF_24BIT_888RGB:
-
#ifdef VIDEO_FB_LITTLE_ENDIAN
-
dest[0] = b;
-
dest[1] = g;
-
dest[2] = r;
-
#else
-
dest[0] = r;
-
dest[1] = g;
-
dest[2] = b;
-
#endif
-
break;
-
}
-
source++;
-
dest += VIDEO_PIXEL_SIZE;
-
}
-
dest += skip;
-
}
-
#endif
-
-
//plot the bottom
-
#if 1
-
ycount = 204;
-
x = 0;
-
y = 0;
-
dest = (unsigned char *)screen +
-
((y * width * VIDEO_PIXEL_SIZE) +
-
x * VIDEO_PIXEL_SIZE);
-
while (ycount--) {
-
xcount = 800;
-
while (xcount--) {
-
r = 0;
-
g = 0;
-
b = 0;
-
*(unsigned short *) dest =
-
SWAP16 ((unsigned short) (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)));
-
dest += VIDEO_PIXEL_SIZE;
-
}
-
//dest += skip;
-
}
-
#endif
-
-
#ifdef CONFIG_VIDEO_BMP_LOGO
-
free (logo_red);
-
free (logo_green);
-
free (logo_blue);
-
#endif
-
}
说明:
1) 函数的开头以”#ifdef CONFIG_VIDEO_LOGO“宏定义开始,所以想要显示图片首先需要定义宏”CONFIG_VIDEO_LOGO“。即为4.1所示。
2) 第6行指定了行扫描时跳过的字节数,”width - VIDEO_LOGO_WIDTH“中,width是屏幕的实际宽度,本文为800,VIDEO_LOGO_WIDTH为”tools/logo/denx.bmp“图片的实际宽度,最大为800。VIDEO_PIXEL_SIZE为2,表示一个像素占用两个字节。
3) 第10行定义了显示内存的实际地址,如果我们从(0,0)开始显示,那么此处即为"screen"。
4) 第15行取得实际位图数据数组的起始地址。
5) 第18-26行首先申请内存,然后从调色板中取得RGB相应的值。
6) 第43-56行首先将屏幕刷黑,RGB数据全为0,此时也不需要skip,因为是刷全屏。
7) 第60-115行实现将图片显示在屏幕上,ycount即为实际图片高度,xcount为实际图片的宽度,72-74行取得RGB数据,然后将其赋值在显示内存上。switch分支中走的case为"GDF_16BIT_565RGB”。
8) 第120-137行将图片的上半部再一次刷黑。
注意,在调试中发现,需要将int ycount = video_logo_height;定义为volatile类型,否则会造成外层循环退不出来,即改为:volatile int ycount = video_logo_height;。
阅读(5464) | 评论(1) | 转发(0) |