Linux framebuffer的框架非常简单, 对于应用程序就是操作一块内存(俗称帧缓存), 当然也有可能是双缓存, 一般用于高帧率场景, 一块帧在填充数据时, 另一块在显示, 接着对调过来,
那通过设置哪里告知驱动层读取哪块帧数据呢? 答案是用vinfo.xoffset, vinfo.yoffset
需要注意的是, 无论用write()、还是mmap()后直接操作内存都只是填充内存而已, 并不代表能够立马显示, 这得看驱动, 如果驱动实现了自刷新(不断从帧缓存拿数据刷到LCD上), 那填充数据到帧缓存就会立马显示出来,
如果驱动没有实现,那应用程序需要主动的调用 ioctl(fp, FBIOPAN_DISPLAY, &vinfo);, 告知驱动可以刷数据了, 如果这都没显示出来, 估计驱动没实现FBIOPAN_DISPLAY功能。
示例代码:(驱动实现自刷新, 应用依次显示黄、蓝、红,最后画线)
#include <unistd.h>#include <stdio.h>#include <fcntl.h>#include <linux/fb.h>#include <sys/mman.h>#include <stdlib.h>#include <string.h>#define RED 0xF800#define YELLOW 0xFFE0#define BLUE 0x001F#define WHITE 0xFFFF#define BLACK 0x0000void fill_color16(short *fb_addr, short bit_map, int psize){int i;for(i=0; i<psize; i++) {*fb_addr = bit_map;fb_addr++;}}int main (){int fp=0;struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;long screensize=0;char *fbp = NULL, *test_fbp=NULL;int x = 0, y = 0;long location = 0;int i;int num = 5;int pix_size=0;fp = open("/dev/graphics/fb0", O_RDWR);if(fp < 0) {printf("Error : Can not open framebuffer device/n");exit(1);}if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)){printf("Error reading fixed information/n");exit(2);}if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){printf("Error reading variable information/n");exit(3);}screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;printf("The phy mem = 0x%x, total size = %d(byte)\n", finfo.smem_start, finfo.smem_len);printf("xres = %d, yres = %d, bits_per_pixel = %d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);printf("So the screensize = %d(byte), using %d frame\n", screensize, finfo.smem_len/screensize);printf("vinfo.xoffset = %d, vinfo.yoffset = %d\n", vinfo.xoffset, vinfo.yoffset);printf("vinfo.vmode is :%d\n", vinfo.vmode);printf("finfo.ypanstep is :%d\n", finfo.ypanstep);printf("vinfo.red.offset=0x%x\n", vinfo.red.offset);printf("vinfo.red.length=0x%x\n", vinfo.red.length);printf("vinfo.green.offset=0x%x\n", vinfo.green.offset);printf("vinfo.green.length=0x%x\n", vinfo.green.length);printf("vinfo.blue.offset=0x%x\n", vinfo.blue.offset);printf("vinfo.blue.length=0x%x\n", vinfo.blue.length);printf("vinfo.transp.offset=0x%x\n", vinfo.transp.offset);printf("vinfo.transp.length=0x%x\n", vinfo.transp.length);fbp =(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);if ((int)fbp == -1){printf ("Error: failed to map framebuffer device to memory./n");exit (4);}printf("Get virt mem = %p\n", fbp);pix_size = vinfo.xres * vinfo.yres;/* using first frame, for FBIOPAN_DISPLAY* 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数* 如果使用第二帧buffer -> vinfo.xoffset = 0; vinfo.yoffset = vinfo.yres;*/vinfo.xoffset = 0;vinfo.yoffset = 0;/* show color loop */while(num--) {printf("\ndrawing YELLOW......\n");fill_color16((short *)fbp, YELLOW, pix_size);//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);sleep(3);printf("\ndrawing BLUE......\n");fill_color16((short *)fbp, BLUE, pix_size);//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);sleep(3);printf("\ndrawing RED......\n");fill_color16((short *)fbp, RED, pix_size);//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);sleep(3);}#if 1/*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/x = 10;y = 10;location = x * (vinfo.bits_per_pixel / 8) + y * finfo.line_length;test_fbp = fbp + location;printf("draw line.......\n");for(i = 0; i < (vinfo.xres - x); i++)*test_fbp++ = i+30;//ioctl(fp, FBIOPAN_DISPLAY, &vinfo);#endifmunmap(fbp, screensize); /*解除映射*/close (fp);return 0;}
当然用read()/write(), 也可以, 就是效率非常低, 太多系统调用导致系统在用户态和kernel态切换, 而且每次还传输一个字节, 但作为例子可以参考一下:
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#define RED 0xF800
#define YELLOW 0xFFE0
#define BLUE 0x001F
#define WHITE 0xFFFF
#define BLACK 0x0000
int main ()
{
int fp=0;
struct fb_var_screeninfo vinfo;
int i;
int pix_size=0;
unsigned char color1, color2;
fp = open("/dev/graphics/fb0", O_RDWR);
if(fp < 0) {
printf("Error : Can not open framebuffer device/n");
exit(1);
}
if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){
printf("Error reading variable information/n");
exit(3);
}
pix_size = vinfo.xres * vinfo.yres;
color1 = 0;
color2 = 0xf8;
for(i=0; i<pix_size; i++) {
write(fp, &color1, 1);
write(fp, &color2, 1);
}
close (fp);
return 0;
}
