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提供接口。

雖然第一種方案被客戶否定,但在實現的過程中對截屏,圖片數據轉換,屏驅動的相關機制有比較深的瞭解,這也算是一種收穫吧。

發佈了14 篇原創文章 · 獲贊 9 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章