uboot2010.3关于LCD输出的处理-字符处理

来源:互联网 发布:腾讯云域名dns未修改 编辑:程序博客网 时间:2024/06/06 18:12

1.uboot用来LCD输出的最底层函数为:static void video_drawchars (int xx, int yy, unsigned char *s, int count),该函数位于driver/video/cfb_console.c中。

static void video_drawchars (int xx, int yy, unsigned char *s, int count)
{
u8 *cdat, *dest, *dest0;
int rows, offset, c;


offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;
dest0 = video_fb_address + offset;


switch (VIDEO_DATA_FORMAT) {
case GDF__8BIT_INDEX:
case GDF__8BIT_332RGB:
while (count--) {
c = *s;
cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
    rows--;
    dest += VIDEO_LINE_LEN) {
u8 bits = *cdat++;


((u32 *) dest)[0] = (video_font_draw_table8[bits >> 4] & eorx) ^ bgx;
((u32 *) dest)[1] = (video_font_draw_table8[bits & 15] & eorx) ^ bgx;
}
dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
s++;
}
break;


case GDF_15BIT_555RGB:
while (count--) {
c = *s;
cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
    rows--;
    dest += VIDEO_LINE_LEN) {
u8 bits = *cdat++;


((u32 *) dest)[0] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 6] & eorx) ^ bgx);
((u32 *) dest)[1] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 4 & 3] & eorx) ^ bgx);
((u32 *) dest)[2] = SHORTSWAP32 ((video_font_draw_table15 [bits >> 2 & 3] & eorx) ^ bgx);
((u32 *) dest)[3] = SHORTSWAP32 ((video_font_draw_table15 [bits & 3] & eorx) ^ bgx);
}
dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
s++;
}
break;


case GDF_16BIT_565RGB:
while (count--) {
c = *s;
cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
    rows--;
    dest += VIDEO_LINE_LEN) {
u8 bits = *cdat++;


((u32 *) dest)[0] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 6] & eorx) ^ bgx);
((u32 *) dest)[1] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 4 & 3] & eorx) ^ bgx);
((u32 *) dest)[2] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 2 & 3] & eorx) ^ bgx);
((u32 *) dest)[3] = SHORTSWAP32 ((video_font_draw_table16 [bits & 3] & eorx) ^ bgx);
}
dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
s++;
}
break;


case GDF_32BIT_X888RGB:
while (count--) {
c = *s;
cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
    rows--;
    dest += VIDEO_LINE_LEN) {
u8 bits = *cdat++;


((u32 *) dest)[0] = SWAP32 ((video_font_draw_table32 [bits >> 4][0] & eorx) ^ bgx);
((u32 *) dest)[1] = SWAP32 ((video_font_draw_table32 [bits >> 4][1] & eorx) ^ bgx);
((u32 *) dest)[2] = SWAP32 ((video_font_draw_table32 [bits >> 4][2] & eorx) ^ bgx);
((u32 *) dest)[3] = SWAP32 ((video_font_draw_table32 [bits >> 4][3] & eorx) ^ bgx);
((u32 *) dest)[4] = SWAP32 ((video_font_draw_table32 [bits & 15][0] & eorx) ^ bgx);
((u32 *) dest)[5] = SWAP32 ((video_font_draw_table32 [bits & 15][1] & eorx) ^ bgx);
((u32 *) dest)[6] = SWAP32 ((video_font_draw_table32 [bits & 15][2] & eorx) ^ bgx);
((u32 *) dest)[7] = SWAP32 ((video_font_draw_table32 [bits & 15][3] & eorx) ^ bgx);
}
dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
s++;
}
break;


case GDF_24BIT_888RGB:
while (count--) {
c = *s;
cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;
for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
    rows--;
    dest += VIDEO_LINE_LEN) {
u8 bits = *cdat++;


((u32 *) dest)[0] = (video_font_draw_table24[bits >> 4][0] & eorx) ^ bgx;
((u32 *) dest)[1] = (video_font_draw_table24[bits >> 4][1] & eorx) ^ bgx;
((u32 *) dest)[2] = (video_font_draw_table24[bits >> 4][2] & eorx) ^ bgx;
((u32 *) dest)[3] = (video_font_draw_table24[bits & 15][0] & eorx) ^ bgx;
((u32 *) dest)[4] = (video_font_draw_table24[bits & 15][1] & eorx) ^ bgx;
((u32 *) dest)[5] = (video_font_draw_table24[bits & 15][2] & eorx) ^ bgx;
}
dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;
s++;
}
break;
}
}

1> VIDEO_LINE_LEN 为一行所占的字节数,我使用的LCD为240*320并且设置的bpp模式为16bpp,所以该值为(240*2=480); 

2> VIDEO_PIXEL_SIZE为每个像素点所占用的字节数,因为使用的是16bpp,所以该值为(2);

3> offset = yy * VIDEO_LINE_LEN + xx * VIDEO_PIXEL_SIZE;该语句就是求出(xx,yy)坐标点,对于缓存framebuffer的偏移地址offset,其中xx,yy是以像素点为基准单位的;

4> dest0 = video_fb_address + offset;其中video_fb_address是LCD帧缓存fb(framebuffer)的起始地址,加上偏移量,即得到坐标点的真正地址;

5> case GDF_16BIT_565RGB:采用的bpp模式为16bpp-565模式,其他模式的处理方式是平行的;

6> cdat = video_fontdata + c * VIDEO_FONT_HEIGHT;在ASC2II表中找到字符c对应的点阵图的起始位置;

7> for (rows = VIDEO_FONT_HEIGHT, dest = dest0;
     rows--;
     dest += VIDEO_LINE_LEN) 一个字符需要VIDEO_FONT_HEIGHT(16)行像素。每一行的起始地址为:dest += VIDEO_LINE_LEN;

8> ((u32 *) dest)[0] = SHORTSWAP32 ((video_font_draw_table16 [bits >> 6] & eorx) ^ bgx);其中 eorx=fgx^bgx,所以(video_font_draw_table16 [bits >> 6] & eorx) ^ bgx就相当于video_font_draw_table16 [bits >> 6] &fgx,fgx为前景色(front ground color)。static const int video_font_draw_table16[] = {

   0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff };至此可以看到,uboot对于字符的处理是字符的两个像素点一起处理的,两个像素点的颜色一同处理,两个像素点的写入也是一同处理,每个像素点占用16bit,两个正好是一个字的长度。SHORTSWAP32()的作用是调整字节在帧缓存中的格式,根据格式是大端方式还是小端方式,

是否存在半字交换等,在编译时选择相应的宏定义。其中有一点比较困惑,(video_font_draw_table16 [bits >> 6] & eorx) ^ bgx为什么不直接写成video_font_draw_table16

 [bits >> 6] &fgx。

9> dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE;当写完一个字的像素点时,求下一个字的像素点的起始坐标。

2.static void video_putchar (int xx, int yy, unsigned char c)
{
video_drawchars (xx, yy + video_logo_height, &c, 1);
}

video_putchar()函数在特定坐标输出一个字符,每个字符的输出都在控制之下,因此在上层输出函数中直接调用的是单字符输出函数video_putchar()而不是多字符输出函数video_drawchars()。可能是个人的偏执吧,人为没必要将最底层输出函数设置为多字符输出,应该是简单的单字符输出,可能更正宗一些,但是程序有时候要的不是正宗,而是效率......其中video_logo_height是logo的高度,单位是像素个数。在LCD显示时,界面的格式是,上方显示logo,下方显示字符。

3.void video_putc (const char c)
{
static int nl = 1;


switch (c) {
case 13: /* back to first column */
console_cr ();
break;


case '\n': /* next line */
if (console_col || (!console_col && nl))
console_newline ();
nl = 1;
break;


case 9: /* tab 8 */
CURSOR_OFF console_col |= 0x0008;
console_col &= ~0x0007;


if (console_col >= CONSOLE_COLS)
console_newline ();
break;


case 8: /* backspace */
console_back ();
break;


default: /* draw the char */
video_putchar (console_col * VIDEO_FONT_WIDTH,
      console_row * VIDEO_FONT_HEIGHT,
      c);
console_col++;


/* check for newline */
if (console_col >= CONSOLE_COLS) {
console_newline ();
nl = 0;
}
}
CURSOR_SET}

1> 该函数是格式输出的单字符输出函数,针对输出的字符分类,可分为控制字符和实义字符,控制字符分为,回车\r,换行\r,制表符\t,回退\b;

2> 在字符输出的时候,要注意一个问题,那就是屏宽和屏长的问题。为了方便管理,我们引进了,横坐标和纵坐标的体系,坐标值和屏幕一一对应。当字符写到屏幕右边时,我们要检测到,并且将横坐标归零,纵坐标加1,来维护管理体系。(实际上如果你一直写,字符自然会出现在下一行)。当字符输出到最后一行右边时,纵坐标已达最大值,这时我们也要检测到,并且将内存中数据依次向前搬移,将第一行的数据完全覆盖,并将最后一行的数据清零。在具体处理时,有些处理手段很是巧妙。

3> if (console_col || (!console_col && nl))这时换行符输出的限制条件,也可以理解为格式输出的规则,当字符输出到屏幕右边自动换行并且换行后的第一个字符为换行符时,该换行符不输出。当console!=0是,会换行,console=0的情况1.输出自动换行;2.输出回车符。当console==0且nl!=0时,会换行。当输出自动换行时,nl==0。也就是当console==0且nl==0时,不会换行。即输出自动换行后不输出换行符。

4> CURSOR_SET是一个宏定义,开启后会输出静态光标。

1 0