uboot里开机LOGO显示功能解析
开机LOGO,对于绝大多数带显示屏的电子产品都是必备的一个功能,是产品开机的第一印象,重要性不言而喻的,那我们下面就看看这个是怎么实现的。
要尽早的显示出LOGO就需要在系统真正起来之前的boot阶段就能打通显示,而这个任务大多是以U-BOOT这样的角色来充当,全志平台在android4.4平台就是在u-boot里面实现的,支持的是BMP图片。大家分为几个步骤了,首先要读取图片,再解析图片数据,然后再送到显示部分,最后显示出来。事就是这么个事,说起来简单,理起来也简单,真正写出来的人并不简单,需要对这几个部分都很了解,当然对于平台来说,难度倒不是太大。下面一起看看吧!
/*****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/edsam49原创,转载请注明出处,谢谢!
/*****************************************************************************************************/
首先,加载图片到内存中。加载的话,大家比较熟悉的也就是fatload,就是挂载一个fat的文件系统,从这个文件系统里面去读取这个文件的数据到指定内存位置,看看代码吧,也不难!
char *const bmp_argv[6] = { "fatload", "sunxi_flash", "0", "40000000", bmp_name, NULL }; memset(bmp_name, 0, 32); strcpy(bmp_name, name); if(do_fat_fsload(0, 0, 5, bmp_argv)) { printf("sunxi bmp info error : unable to open logo file %s\n", bmp_argv[4]); return -1; }
其次,得到图片原始数据了就需要做解析了,当然BMP图片的数据格式也是确定的,数据头确定,一般是54个字节,我们看看数据头的数据结构:
typedef struct bmp_header { /* Header */ char signature[2]; __u32 file_size; __u32 reserved; __u32 data_offset; /* InfoHeader */ __u32 size; __u32 width; __u32 height; __u16 planes; __u16 bit_count; __u32 compression; __u32 image_size; __u32 x_pixels_per_m; __u32 y_pixels_per_m; __u32 colors_used; __u32 colors_important; /* ColorTable */ } __attribute__ ((packed)) bmp_header_t;
打印出来又是怎么一个效果呢?如下:
bmp signature[] B, M bmp file_size 1536054 bmp reserved -1 bmp data_offset 54 bmp size 40 bmp width 800 bmp height -480 bmp planes 1 bmp bit_count 32 bmp compression 0 bmp image_size 1536000 bmp x_pixels_per_m 0 bmp y_pixels_per_m 0 bmp colors_used 0 bmp colors_important 0 bmp x = 320, bmp y = 1e0笔者测试的这个BMP图片用工具处理过,就是调整它的透明度,所以显示的高度有一点异常,取反就好了。看看下面的处理:
if((bmp->header.signature[0]!='B') || (bmp->header.signature[1] !='M')) { printf("this is not a bmp picture\n"); return -1; } debug("bmp dectece\n"); bmp_bpix = bmp->header.bit_count/8; if((bmp_bpix != 3) && (bmp_bpix != 4)) { printf("no support bmp picture without bpix 24 or 32\n"); return -1; } if(bmp_bpix ==3) { zero_num = (4 - ((3*bmp->header.width) % 4))&3; } debug("bmp bitcount %d\n", bmp->header.bit_count); x = bmp->header.width; y = (bmp->header.height & 0x80000000) ? (-bmp->header.height):(bmp->header.height); printf("bmp x = %x, bmp y = %x\n", x, y); tmp_buffer = (char *)bmp_info->buffer; bmp_data = (char *)(addr + bmp->header.data_offset); if(bmp->header.height & 0x80000000) { if(zero_num == 0) { memcpy(tmp_buffer,bmp_data,x*y*bmp_bpix); } else { int i, line_bytes, real_line_byte; char *src; line_bytes = (x * bmp_bpix) + zero_num; real_line_byte = x * bmp_bpix; for(i=0; i<y; i++) { src = bmp_data + i*line_bytes; memcpy(tmp_buffer, src, real_line_byte); tmp_buffer += real_line_byte; } } } else { uint i, line_bytes, real_line_byte; char *src; line_bytes = (x * bmp_bpix) + zero_num; real_line_byte = x * bmp_bpix; for(i=0; i<y; i++) { src = bmp_data + (y - i - 1) * line_bytes; memcpy(tmp_buffer, src, real_line_byte); tmp_buffer += real_line_byte; } } bmp_info->x = x; bmp_info->y = y; bmp_info->bit = bmp->header.bit_count; flush_cache((uint)bmp_info->buffer, x * y * bmp_bpix);
然后就是送到显示的地方了,因为解码buffer的地址是确定的,只要在显示layer的参数里挂上钩就可以了,申请layer,设置参数,打开layer,顺理成章!简单代码如下:
debug("begin to set framebuffer\n"); if(board_display_framebuffer_set(bmp_info.x, bmp_info.y, bmp_info.bit, (void *)bmp_info.buffer)) { printf("sunxi bmp display error : set frame buffer error\n"); return -2; } debug("begin to show layer\n"); board_display_show(0); debug("bmp display finish\n");
board_display_layer_para_set(); board_display_layer_open();
整个流程确实就是这样的,有深度的地方就是把各个部分有机的串联起来,组织起来,不会做的事情都难,会做了的事情都不难!当然,我们不要在不懂的情况下就去评说这个事情难不难,难不难谁做谁知道!谦虚谨慎,低调潜行!