【Tiny6410 And Linux】—(6.2)—LCD 驅動測試程式(BMP 顯示點陣圖)——程式碼
阿新 • • 發佈:2019-01-28
剛才看個小視訊,關於華山遊客滯留的,哎,真是花錢買罪吃,下回一定得選好旅遊地點!
少點廢話,上一篇文章是關於 LCD 測試程式(BMP 顯示點陣圖)的基本原理的介紹,今天就發一下程式碼吧,由於中間遇到點小問題,我的測試程式總是出現Segmentation Fault這樣的錯誤,上網查了查也沒有看到什麼好的解決方法,最後還是找的國嵌的原始碼來對應的,是一個關於指標和傳遞函式的問題,這裡我會在我的程式碼中指出,說實話,我還是不明白為什麼我那樣做就不行!
1、測試程式
①、tiny6410_ bmp_lib.h
#ifndef __TINY6410_BMP_LIB_H__ #define __TINY6410_BMP_LIB_H__ #include <string.h> /* bitmap 格式的點陣圖檔案會帶有 54 位元組的資訊頭,這些資訊是固定不變的,可以通過read 來讀取 */ /* 檔案資訊頭(14位元組) */ typedef struct { char type[2]; /* 檔案型別,必須為"BMP" (0X4D42) */ char size[4]; /* 檔案的大小(位元組) */ char reserved[4]; /* 保留,必須為0 */ char off[4]; /* 點陣圖陣列相對於檔案頭的偏移量(位元組) */ } bmp_file_header_t; /* 點陣圖資訊頭(40位元組) */ typedef struct { char size[4]; /* 說明BITMAPINFOHEADER 結構所需要的字數 */ char width[4]; /* 點陣圖寬度(畫素) */ char height[4]; /* 點陣圖高度(畫素),如果該值是一個正數,說明影象是倒像的,大多數BMP 檔案都是倒像的 */ char planes[2]; /* 目標裝置的位平面數,必須置為1 */ char bitcount[2]; /* 每個畫素的位數,1, 4, 8, 16, 24, 32 */ char compress[4]; /* 點陣圖陣列的壓縮方法,0表示不壓縮 */ char img_size[4]; /* 影象大小(位元組) */ char xpel[4]; /* 說明水平解析度,用 畫素/米 表示 */ char ypel[4]; /* 垂直 */ char clr_used[4]; /* 點陣圖實際使用的顏色表的顏色數 */ char clr_important[4]; /* 重要顏色索引的個數 */ } bmp_info_header_t; /* 這裡應用程式可以相容24 位和32位的點陣圖,其中red,green,blue這三個顏色所佔的位置應該倒置 */ typedef struct { char blue; char green; char red; char reserved; } rgb_32_t; /* 對點陣圖操作進行封裝 */ typedef struct { int fd; /* 影象檔案描述符 */ rgb_32_t *curp; /* 指向當前的畫素點 */ int width; /* 影象寬度 */ int height; /* 影象高度 */ int bitcount; /* 影象每個畫素的位數 */ int size; /* 影象大小 */ void *data; /* 影象有效資料指標 */ } bmp_t; /* 由於開發板幀緩衝在驅動中被設定為16 位資料表示一個畫素點(16bpp),這裡需要對24 位或者32 位的點陣圖進行轉化 */ static short transfer_to_16bit(char red,char green,char blue) { return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3); } /* 獲取一個被轉化為16 位的畫素值 */ static short bmp_get_pixel_16bit(bmp_t *bmp) { return transfer_to_16bit(bmp->curp->red, bmp->curp->green, bmp->curp->blue); } /* 字串變成整形的函式 */ static long char_to_int(char *str) { return *((int *)str); } /* 使bmp->curp 指向下一個畫素點 */ static void bmp_next_pixel(bmp_t *bmp) { if (24 == bmp->bitcount) bmp->curp = (rgb_32_t*)((int)bmp->curp + 3); else if (32 == bmp->bitcount) bmp->curp = (rgb_32_t*)((int)bmp->curp + 4); } /* 使bmp->curp 指向影象有效資料的初始位置 */ static void bmp_reset_pixel(bmp_t *bmp) { bmp->curp = (rgb_32_t*)bmp->data; } extern int bmp_open(bmp_t *bmp, char *bmpn); extern void bmp_close(bmp_t *bmp); #endif
②、tiny6410_ bmp_lib.c
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include "tiny6410_bmp_lib.h" int bmp_open(bmp_t *bmp, char *bmpn) { int ret; bmp_file_header_t fhr; bmp_info_header_t ihr; printf("[Call bmp_open.]\n"); if (-1 == (bmp->fd=open(bmpn, O_RDONLY))) { printf("Error: cannot open framebuffer device.\n"); _exit(EXIT_FAILURE); } // printf("Open done!\n"); read(bmp->fd, &fhr, sizeof(bmp_file_header_t)); /* 讀取檔案資訊頭 */ read(bmp->fd, &ihr, sizeof(bmp_info_header_t)); /* 讀取點陣圖資訊頭 */ bmp->width = char_to_int(ihr.width); bmp->height = char_to_int(ihr.height); bmp->bitcount = char_to_int(ihr.bitcount); bmp->size = (bmp->width * bmp->height * bmp->bitcount) / 8; printf("bmp->width = %d\n", bmp->width); printf("bmp->height = %d\n", bmp->height); printf("bmp->bitcount = %d\n", bmp->bitcount); printf("bmp->siz = %d\n", bmp->size); bmp->data = malloc(bmp->size); ret = read(bmp->fd, bmp->data, bmp->size); /* 讀取實際的影象資料 */ bmp->curp = (rgb_32_t*)bmp->data; /* 指向當前影象有效資料,即指向影象的起始資料 */ return 0; } void bmp_close(bmp_t *bmp) { close(bmp->fd); free(bmp->data);}
③、tiny6410_ bmp_app.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include "tiny6410_bmp_lib.h"
#define FB_DEVICE_NAME "/dev/fb0"
#define RED_COLOR565 0X0F100
#define GREEN_COLOR565 0X007E0
#define BLUE_COLOR565 0X0001F
typedef struct fb_dev {
int fd; /* 幀緩衝裝置硬體描述符 */
void *pfb; /* 指向幀緩衝對映到使用者空間的首地址 */
int xres; /* 一幀影象的寬度 */
int yres; /* 一幀影象的高度 */
int size; /* 一幀影象的大小 */
int bits_per_pixel; /* 每個畫素的大小 */
} fb_dev_t;
int fb_open(fb_dev_t *fbd, char *fbn)
{
struct fb_var_screeninfo vinfo;
if((fbd->fd = open(fbn, O_RDWR)) == -1) {
printf("Error: Cannot open framebuffer device.\n");
_exit(EXIT_FAILURE);
}
/* 獲取LCD 的可變引數 */
ioctl(fbd->fd, FBIOGET_VSCREENINFO, &vinfo);
fbd->xres = vinfo.xres;
fbd->yres = vinfo.yres;
fbd->bits_per_pixel = vinfo.bits_per_pixel;
/* 計算一幀影象的大小 */
fbd->size = fbd->xres * fbd->yres * fbd->bits_per_pixel / 8;
printf("%d * %d,%d bits_per_pixel,screensize = %d.\n",fbd->xres,fbd->yres,fbd->bits_per_pixel,fbd->size);
/* 將幀對映到記憶體 */
/* mmap的應用 */
/* mmap可以把檔案內容對映到一段記憶體中,準確說是虛擬記憶體,通過對這段記憶體的讀取和修改,實現對檔案的讀取和修改。 */
/* addr:指定對映的起始地址,通常為NULL,由系統指定 */
/* length:將檔案的多大長度對映到記憶體 */
/* prot:對映區的保護方式,可以是可被執行(PROT_EXEC),可被寫入(PROT_WRITE),可被讀取(PROT_READ),對映區不能存取(PROT_NONE) */
/* flags:對映區的特性,對對映區的寫入資料會複製迴文件,且允許其他對映檔案的進城共享(MAP_SHARED),對對映區的寫入操作會產生一個對映的複製,對此區域所做的修改不會寫會原始檔(MAP_PRIVATE) */
/* fd:由open返回的檔案描述符,代表要對映的檔案 */
/* offset:以檔案開始出的偏移,必須是分頁大小的整數倍,通常為0,表示從頭開始對映 */
/* 注意:在修改對映檔案時,只能在原長度上修改,不能增加檔案長度,因為記憶體是已經分配好的 */
fbd->pfb = mmap(NULL, fbd->size, PROT_READ | PROT_WRITE, MAP_SHARED, fbd->fd, 0);
if((int)fbd->pfb == -1) {
printf("Error: Failed to map frambuffer device to memory!\n");
_exit(EXIT_FAILURE);
}
return 0;
}
void fb_close(fb_dev_t *fbd)
{
/* 解除對映 */
munmap(fbd->pfb,fbd->size);
/* 關閉裝置檔案 */
close(fbd->fd);
}
int fb_drawrect(fb_dev_t *fbd, int x0, int y0, int w, int h, int color)
{
int x,y;
for(y=y0; y<y0+h; y++) {
for(x=x0; x<x0+w; x++) {
*((short *)(fbd->pfb) + y*fbd->xres +x) = color;
}
}
return 0;
}
/* 用於螢幕顯示圖片函式 */
int fb_drawbmp(fb_dev_t *fbd, int x0, int y0, char *bmpn)
{
int x, y, x1, y1;
bmp_t bmpt; /* 就是這裡,我如果定義一個指標型的變數就會出現我一開始說的問題,當然我傳遞的時候是個地址,但是還是不行! */
bmp_open(&bmpt, bmpn);
x1 = x0 + bmpt.width;
y1 = y0 + bmpt.height;
for(y=y1; y>y0; y--) {
for(x=x0; x<x1; x++) {
if(x1>fbd->xres || y1>fbd->yres) {
bmp_next_pixel(&bmpt);
continue;
}
*((short *)(fbd->pfb) + y*fbd->xres + x) = bmp_get_pixel_16bit(&bmpt);
bmp_next_pixel(&bmpt);
}
}
bmp_close(&bmpt);
return 0;
}
int main(int argc, char **argv)
{
fb_dev_t *fbd;
fbd = (fb_dev_t *)malloc(sizeof(fb_dev_t));
fb_open(fbd, FB_DEVICE_NAME);
if(fbd->bits_per_pixel == 16) {
printf("Red/Green/Blue Screen And a picture!\n");
fb_drawrect(fbd, 0, 0, fbd->xres, fbd->yres/3, RED_COLOR565);
fb_drawrect(fbd, 0, fbd->yres/3, fbd->xres, fbd->yres/3, GREEN_COLOR565);
fb_drawrect(fbd, 0, fbd->yres*2/3, fbd->xres, fbd->yres/3, BLUE_COLOR565);
fb_drawbmp(fbd, 0, 0, argv[1]);
}
else
printf("16 bits only!");
fb_close(fbd);
free((void *)fbd);
return 0;
}
2、測試結果
不得不說現在CSDN真心該修理一下 Bug 問題了!