android平台1.3寸OLED屏调试

引言:

Android平台为彩色屏,图片格式为RGB8888,而1.3OLED屏为黑白屏,即像素为1,让屏正常工作能采用的方案有:

1. 方便apk开发,减少应用层开发的工作量,采取读取framebuf中的数据,将彩色转为单色图片,用8080并口的方式发送数据至GRAM.

2. 加字库与图片,用单色屏开发的方式,省却图片数据转换的步骤。

当时与客户讨论屏幕显示的效果等细节时,客户需要至少一种字体,二种字号字体显示及跑马灯等动画要求。因没接触过增加字库,不了解apk软件对屏幕的处理;另客户要求的时间短,综合考虑,先采用第1种实现方案。

 

实现步骤:

1. 在FAE的协助下,OLED屏能正常点亮,并且发送单色图片通过Img2Lcd.exe转换工具转换好的图片数据能正常显示该图片。

2. 图片格式转换:

   修改frameworks\base\cmds\screenshot\Screenshot.c,先用截图的方式尝试将RGB8888 转换成RGB888RGB565、单色图,保存为BMP格式,adb pull出来看实际效果。在网上参考相关转换算法后,转换代码如下:

   1). RGB888,其实质是将RGB8888的后一字节给丢掉。

static int get_rgb888_header(int w, int h, BMPHEADER * head, BMPINFO * info)

{

int size = 0;

if (head && info) {

size = w * h * 3;

memset(head, 0, sizeof(* head));

memset(info, 0, sizeof(* info));

head->bfType[0] = 'B';

head->bfType[1] = 'M';

head->bfOffBits = 14 + sizeof(* info);

head->bfSize = head->bfOffBits + size;

head->bfSize = (head->bfSize + 3) & ~3;//windows要求文件大小必须是4的倍数

size = head->bfSize - head->bfOffBits;

 

info->biSize = sizeof(BMPINFO);

info->biWidth = w;

info->biHeight = -h;

info->biPlanes = 1;

info->biBitCount = 24;

info->biCompression = 0;//BI_RGB;

info->biSizeImage = size;

printf("rgb888:%dbit,%d*%d,%d\n", info->biBitCount, w, h, head->bfSize);

}

return size;

}

 

void bmp_create_rgb888(FILE *fb_in, unsigned int rowlen, unsigned int col)

{

FILE * hfile = NULL;

char imgbuf[0x10000];

unsigned int r;

int i;

int size = 0;

BMPHEADER head;

BMPINFO info;

 

hfile = fopen(BMP_FILE_PATH, "wb");

if (hfile == NULL) {

printf("open(%s) failed!\n", BMP_FILE_PATH);

return;

}

 

size = get_rgb888_header(128, 64, &head, &info);

fwrite(head.bfType, 1, 14, hfile);

fwrite(&info, 1, sizeof(info), hfile);

 

fseek(fb_in, 0, SEEK_SET);

 

for(r=0; r<col; r++) {

        int len = fread(imgbuf, 1, rowlen, fb_in);

        if (len <= 0) break;

for(i=0; i<rowlen; i+=4)

{

         fwrite(&imgbuf[i], 1, 3, hfile);

}

    }

 

if (hfile != NULL)

fclose(hfile);

 

}

 

2). RGB565

static int get_rgb565_header(int w, int h, BMPHEADER * head, BITMAPINFO * info)

{

int size = 0;

if (head && info) {

size = w * h * 2;

memset(head, 0, sizeof(* head));

memset(info, 0, sizeof(* info));

head->bfType[0] = 'B';

head->bfType[1] = 'M';

head->bfOffBits = 14 + sizeof(* info);

head->bfSize = head->bfOffBits + size;

head->bfSize = (head->bfSize + 3) & ~3;

size = head->bfSize - head->bfOffBits;

info->bmiHeader.biSize = sizeof(info->bmiHeader);

info->bmiHeader.biWidth = w;

info->bmiHeader.biHeight = -h;

info->bmiHeader.biPlanes = 1;

info->bmiHeader.biBitCount = 16;

info->bmiHeader.biCompression = 0;//BI_BITFIELDS;

info->bmiHeader.biSizeImage = size;

info->rgb[0] = 0xF800;

info->rgb[1] = 0x07E0;

info->rgb[2] = 0x001F;

printf("rgb565:%dbit,%d*%d,%d\n", info->bmiHeader.biBitCount, w, h, head->bfSize);

}

return size;

}

 

 

void bmp_create_rgb565(FILE *fb_in, unsigned int rowlen, unsigned int col)

{

FILE * hfile = NULL;

char imgbuf[0x10000];

unsigned int r;

int i;

int size = 0;

BMPHEADER head;

BITMAPINFO info;

unsigned short data;

 

hfile = fopen(BMP_FILE_PATH, "wb");

if (hfile == NULL) {

printf("open(%s) failed!\n", BMP_FILE_PATH);

return;

}

 

size = get_rgb565_header(128, 64, &head, &info);

fwrite(head.bfType, 1, 14, hfile);

fwrite(&info, 1, sizeof(info), hfile);

 

fseek(fb_in, 0, SEEK_SET);

 

for(r=0; r<col; r++) {

        int len = fread(imgbuf, 1, rowlen, fb_in);

        if (len <= 0) break;

for(i=0; i<rowlen; i+=4)

{

data = (unsigned short)((((imgbuf[i] >> 3) & 0x1F)<<0)

| (((imgbuf[i+1] >> 2)&0x3F)<<5)

| (((imgbuf[i+2] >> 3)&0x1F)<<11));

         fwrite(&data, 1, sizeof(unsigned short), hfile);

}

    }

 

if (hfile != NULL)

fclose(hfile);

 

}

 

3). 单色图

#define  LCD_DRV_RGB_TO_BW(color,bit)   ( (unsigned char)((( (((color)&0xf800)>>11) + (((color)&0x07e0)>>5) + ((color)&0x001f) ) & 0x40) ? (1<<bit) : 0) )

 

const unsigned char bmp_head[64] = 

{

0X42,0X4D,0X40,0X04,0X00,0X00,0X00,0X00,0X00,0X00,0X3E,0X00,0X00,0X00,0X28,0X00,

0X00,0X00,0X80,0X00,0X00,0X00,0X40,0X00,0X00,0X00,0X01,0X00,0X01,0X00,0X00,0X00,

0X00,0X00,0X02,0X04,0X00,0X00,0X12,0X0B,0X00,0X00,0X12,0X0B,0X00,0X00,0X00,0X00,

0X00,0X00,0X00,0X00,0X00,0X00,0XFF,0XFF,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,

};

 

void F_LCD_ColorTranslate(unsigned short *image, unsigned short size, unsigned char *tmp)

{   

    unsigned short cnt;

    unsigned short index = 0;

    unsigned short bit = 0;

int temp = 128;

 

    for (cnt = size-1; cnt != 0; --cnt)

    {

       index =  cnt/temp/8*temp + cnt%temp;

       bit   =  cnt/temp%8;

       tmp[index] |= LCD_DRV_RGB_TO_BW(image[cnt], bit);

    }

}

 

void F_LCD_ColorTranslate2(unsigned short *image, unsigned short size, unsigned char *tmp)

{   

    unsigned short cnt;

    unsigned short index = 0;

    unsigned short bit = 0;

int temp = 128;

int i = 0, j = 0;

    for (cnt = 0; cnt < size; cnt+=8)

    {

     for(j=0; j<8; j++)

{

        tmp[i] |= ((( (((image[cnt+j])&0xf800)>>11) + (((image[cnt+j])&0x07e0)>>5) + ((image[cnt+j])&0x001f) ) & 0x40)?1<<j:0);

    }

i++;

    }

}

 

void bmp_create(FILE *fb_in, unsigned int rowlen, unsigned int col)

{

FILE * hfile = NULL;

char imgbuf[0x10000];

unsigned int r;

int i, j;

int size = 0;

BMPHEADER head;

BMPINFO info;

unsigned short data[8192] = {0};

unsigned char tmp[1032] = {0};

hfile = fopen(BMP_FILE_PATH, "wb");

if (hfile == NULL) {

printf("open(%s) failed!\n", BMP_FILE_PATH);

return;

}

 

fwrite(bmp_head, 1, 64, hfile);

fseek(fb_in, 0, SEEK_SET);

j = 0;

 

for(r=0; r<col; r++) {

        int len = fread(imgbuf, 1, rowlen, fb_in);

        if (len <= 0) break;

for(i=0; i<rowlen; i+=4)

{

data[j] = (unsigned short)((((imgbuf[i] >> 3) & 0x1F)<<0)

| (((imgbuf[i+1] >> 2)&0x3F)<<5)

| (((imgbuf[i+2] >> 3)&0x1F)<<11));

         j++;

}

    }

 

F_LCD_ColorTranslate2(data, 8192, tmp);

fwrite(tmp, 1, 1024, hfile);

 

if (hfile != NULL)

fclose(hfile);

 

}

 

4). BMP相关结构体

typedef struct bmp_header 

{

short twobyte ;//两个字节,用来保证下面成员紧凑排列,这两个字符不能写到文件中

//14B

char bfType[2];//!文件的类型,该值必需是0x4D42,也就是字符'BM'

unsigned int bfSize ;//!说明文件的大小,用字节为单位

unsigned int bfReserved1;//保留,必须设置为0

unsigned int bfOffBits;//!说明从文件头开始到实际的图象数据之间的字节的偏移量,这里为14B+sizeof(BMPINFO)

}BMPHEADER;

 

typedef struct bmp_info

{

//40B

unsigned int biSize;

int biWidth ;

int biHeight;

unsigned short biPlanes ;

unsigned short biBitCount ;

unsigned int biCompression;

#define BI_RGB0L

#define BI_RLE8 1L

#define BI_RLE4 2L

#define BI_BITFIELDS3L

unsigned int biSizeImage;

int biXPelsPerMeter;

int biYPelsPerMeter;

unsigned int biClrUsed;

unsigned int biClrImportant;

}BMPINFO;

 

typedef struct tagBITMAPINFO {

BMPINFO bmiHeader;

//RGBQUADbmiColors[1];

unsigned int rgb[3];

} BITMAPINFO;

 

3. 经过上一步骤,已能将framebuf中的数据转换成单色数据,数据与像素显示的关系如右图,而屏的像素排列与图片的数据关系如左图,故还需要将数据进行一次调整。具体转换见后续代码。

           


驱动层相关代码修改如下(为减少数据转换的计算量,将RGB8888直接转换成单色图并如3所述进行数据调整):

static int p = 0;

static u8 __iomem *src = NULL;

static unsigned char flush_flag = 0;

extern void flush_screen_handle(unsigned char *image);

void flush_screen()

{

if(src == NULL)

{

src = kmalloc(32768 , GFP_KERNEL);

}

 

if(mtkfb_fbi->var.bits_per_pixel != 32 || src == NULL)

{

return;

}

 

p = (mtkfb_fbi->var.xoffset + mtkfb_fbi->var.xres * mtkfb_fbi->var.yoffset) * 4;

if(flush_flag == 0)

{

flush_flag = 1;

fb_memcpy_fromfb(src, (mtkfb_fbi->screen_base + p), 32768);

flush_screen_handle(src);

flush_flag = 0;

}

}

EXPORT_SYMBOL(flush_screen);

 

 

void F_LCD_WriteAll(unsigned char * pbtData)

{

unsigned int j,i;

 

for(i=0xB0;i<0xB8;i++)

{

send_ctrl_cmd(i);

send_ctrl_cmd(0x02);

send_ctrl_cmd(0x10);

for(j=0;j<128;j++)

{

send_data_cmd(*(pbtData++));

}

}

static int LCD_ColorTranslate(unsigned char * psrc, unsigned short size)

{

unsigned short i;

    unsigned short cnt = 0;

    unsigned short index = 0;

    unsigned short bit = 0;

 

if (!psrc || size <= 0) {

return -1;

}

 

memset(R_LCD_BWBuffer, 0, 1024);

 

for(i=0; i<size; i+=4)

{

index =  cnt/FRAME_WIDTH/8*FRAME_WIDTH + cnt%FRAME_WIDTH;

bit   =  cnt/FRAME_WIDTH%8;

 

R_LCD_BWBuffer[index] |= (unsigned char)(((((psrc[i] >> 3) & 0x1F)

+ ((psrc[i+1] >> 2)&0x3F)

+ ((psrc[i+2] >> 3)&0x1F))& 0x40)? (1<<bit) : 0);

cnt++;

}

 

return 0;

}

void flush_screen_handle(unsigned char *image)

{

LCD_ColorTranslate(image, 32768);

F_LCD_WriteAll(R_LCD_BWBuffer);

}

 

结论:

按照原计划,基本功能已完成,在交付给客户看效果时,提出两个问题:

1. 屏幕刷新有一点点延时,原因是系统原有的刷屏方式是通过DMA传输数据,而修改后,a、有图片数据转换的计算量,b、屏幕数据刷新时,是整个屏幕数据更新。

2.  图片数据转换有失真,字体显示效果不好。

签于这两个大问题,这种方案被否定,采用第二种方案。 客户在HAL添加一种字库,所有屏幕数据的处理都用C在内存中模拟处理,数据处理好后,通过kernel提供的接口,直接发送给GRAM,kernel仅仅发送数据,不作任何处理。HAL层向apk提供接口。

虽然第一种方案被客户否定,但在实现的过程中对截屏,图片数据转换,屏驱动的相关机制有比较深的了解,这也算是一种收获吧。

你可能感兴趣的:(android,oled,screenshot截屏,RGB几种格式之间的转换)