该教程适用于LubanCat-RK系列板卡,可以接入野火mipi屏以及HDMI屏幕进行使用。
本章的示例代码目录为:base_linux/screen/framebuffer
FrameBuffer中文译名为帧缓冲驱动,它是出现在2.2.xx内核中的一种驱动程序接口。主设备号为29,次设备号递增。
Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。FrameBuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过FrameBuffer的读写直接对显存进行操作。用户可以将FrameBuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。
用户不必关心物理显存的位置、换页机制等等具体细节,这些都是由FrameBuffer设备驱动来完成的。
FrameBuffer实际上就是嵌入式系统中专门为GPU所保留的一块连续的物理内存,LCD通过专门的总线从framebuffer读取数据,显示到屏幕上。
FrameBuffer本质上是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。所以说FrameBuffer就是一块白板。
屏幕位置从上到下,从左至右与内存地址是顺序的线性关系
屏幕除了RGB888的格式外,还具有其他的格式
注意
如果你使用的是带桌面版的镜像,在使用framebuffer前要注意先把图形界面关闭,不然会出现触摸后屏幕不断闪烁的情况
123456 /*--------------第一步--------------*/ fd=open("/dev/fb0",O_RDWR); //打开framebuffer设备 if(fd==-1){ perror("OpenLCD"); return-1; }这一步是打开framebuffer设备,这一步成功后会返回文件描述符–fd,我们后面可以操作这个文件描述符操作该设备。
123456789101112 /*--------------第二步--------------*/ //获取屏幕的可变参数 ioctl(fd,FBIOGET_VSCREENINFO,&var); //获取屏幕的固定参数 ioctl(fd,FBIOGET_FSCREENINFO,&fix); //打印分辨率 printf("xres=%d,yres=%d\n",var.xres,var.yres); //打印总字节数和每行的长度 printf("line_length=%d,smem_len=%d\n",fix.line_length,fix.smem_len); printf("xpanstep=%d,ypanstep=%d\n",fix.xpanstep,fix.ypanstep);这一步获取屏幕的参数以及设置屏幕
获取屏幕的可变参数ioctl(fd,FBIOGET_VSCREENINFO,&var);
获取屏幕的固定参数ioctl(fd,FBIOGET_FSCREENINFO,&fix);
这两个目的是获取fb_var_screeninfo,fb_fix_screeninfo结构体
我们看一下结构体所包含的内容
ioctl:在framebuffer里除了FBIOGET_VSCREENINFO,FBIOGET_FSCREENINFO还有其他的选项进行配置
选项名
功能
用法
FBIOGET_VSCREENINFO
ioctl(fd,FBIOGET_VSCREENINFO,&var);
获取屏幕可变参数
FBIOPUT_VSCREENINFO
ioctl(fd,FBIOPUT_VSCREENINFO,&var);
修改屏幕的可变参数
FBIOGET_FSCREENINFO
ioctl(fd,FBIOGET_FSCREENINFO,&fix);
获取屏幕的固定参数
FBIOPAN_DISPLAY
ioctl(fd,FBIOPAN_DISPLAY,&var);
平移显示,设置屏幕的显示,可用于双缓冲framebuffer设计
其他
ioctl(fd,xxxxxx,&xxx);
其他参数可以阅读内核源码:/kernel/drivers/video/fbdev/core/fbmem.c1113行~1267行
12345678910unsignedint*fb_mem=NULL; //设置显存的位数为32位 /*--------------第三步--------------*/ fb_mem=(unsignedint*)mmap(NULL,var.xres*var.yres*4, //获取显存,映射内存 PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); if(fb_mem==MAP_FAILED){ perror("MmapLCD"); return-1; }这一步操作是把设备的内存映射到用户空间里,用户只需要对着这块内存操作就可以改变屏幕的内容,与传统的write函数相比,数据传输的速度以及便捷性都得到了大幅的提高
第一行设置fb_mem为32位,可以让我能够方便的使用32位的数据操作24位屏幕数据RGB888,如果使用想要节省空间的话,可以使用unsignedchar型,不过颜色分量就需要解析,然后分别改写。
12mmap的原型如下caddr_tmmap(caddr_taddr,size_tlen,intprot,intflags,intfd,off_toffset);返回值为地址
addr:申请的地址,如果为空,系统会自动分配地址空间
len:申请内存空间的大小,单位为字节
prot:prot参数指定访问权限,可取如下几个值的“或”:PROT_READ(可读)、PROT_WRITE(可写)、PROT_EXEC(可执行)和PROT_NONE(不可访问)
fd:文件描述符,fd=-1,匿名映射
offset:映射文件的偏移量,从文件的哪里开始操作
更详细的操作可以前往pc上的Ubuntu在命令行里输入man2mmap获得
与之相对应的是第64行的munmap(fb_mem,var.xres*var.yres*4);
12#函数功能:释放内存空间intmunmap(void*addr,size_tlength);addr:mmap返回的地址
length:要回收的内存空间大小
1234 /*--------------第四步--------------*/ //将屏幕全部设置成蓝色 for(i=0;i 本小结仅提供双缓冲framebuffer的应用程序设计思路,想在LubanCat-RK系列板卡中实现这个功能需要自行修改内核源码适配 双缓冲的设计在drm中有较高的支持,我们推荐使用drm应用编程替代framebuffer,如果不想修改内核源码,但是想体验双缓冲framebuffer,可以前往下一章节学习 以横向扩充为例 内核修改: 修改fb_fix_screeninfo.smem_len这个参数,而固定参数不能在应用层修改,所以需要在内核里扩充它的长度 修改内核中mmap函数的分配内存的长度,dma的传输范围 修改内核中fb_pan_display,以适配显示 应用层修改: 在应用层需要把xres_virtual扩充到xres的两倍 如果想在主屏幕上显示的话,需要设置fb_var_screeninfo.xoffset=0;在副屏幕上显示的话,需要设置fb_var_screeninfo.xoffset=xres; 通过ioctl(fd,FBIOPUT_VSCREENINFO,&var);修改参数 通过ioctl(fd,FBIOPAN_DISPLAY,&var);把参数传入到内核里,就可以切换屏幕了