前言
GUI的开发可以有多种方式,比如使用Qt等,而Linux下的Framebuffer可直接类似于操作显存的方式直接写点的颜色,更简单直接,开发环境也更简单,不需要像Qt一样搭建比较复杂的开发环境。所以我们先从简单开始测试下基于Framebuffer的LCD显示,后面基于该方式进行GUI程序的开发。
过程
基于Frambebuffer开发只需要安装编译器即可,环境搭建很简单,
安装GCC编译器
sudo apt-get install gcc-aarch64-linux-gnu
查看编译器版本
aarch64-linux-gnu-gcc -v
编写代码framebuffer.c如下
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/fb.h>
int main(int argc, char *argv[])
{
int fd = -1;
int ret = -1;
uint8_t *p_fb = 0;
struct fb_fix_screeninfo finfo;
struct fb_var_screeninfo vinfo;
memset(&finfo,0,sizeof(finfo));
memset(&vinfo,0,sizeof(vinfo));
fd = open(argv[1],O_RDWR);
if(fd < 0)
{
fprintf(stderr,"open %s err, %s\n",argv[1],strerror(errno));
return -1;
}
ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
if(ret < 0)
{
fprintf(stderr,"ioctl finfo err, %s\n",strerror(errno));
close(fd);
return -1;
}
ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
if(ret < 0)
{
fprintf(stderr,"ioctl vinfo err, %s\n",strerror(errno));
close(fd);
return -1;
}
vinfo.yoffset = 0;
ret = ioctl(fd, FBIOPAN_DISPLAY, &vinfo);
if(ret < 0)
{
fprintf(stderr,"ioctl vinfo err, %s\n",strerror(errno));
close(fd);
return -1;
}
unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
p_fb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if(p_fb == NULL)
{
fprintf(stderr,"mmap len %ld err\n",len);
close(fd);
return -1;
}
fprintf(stderr,"x = %d, y = %d\r\n",vinfo.xres,vinfo.yres);
fprintf(stderr,"vx = %d, vy = %d\r\n",vinfo.xres_virtual,vinfo.yres_virtual);
fprintf(stderr,"ox = %d, oy = %d\r\n",vinfo.xoffset,vinfo.yoffset);
fprintf(stderr,"bits = %d\r\n",vinfo.bits_per_pixel);
fprintf(stderr,"gray = %d\r\n",vinfo.grayscale);
fprintf(stderr,"red offset:%d length:%d msb_right:%d\r\n",vinfo.red.offset,vinfo.red.length,vinfo.red.msb_right);
fprintf(stderr,"green offset:%d length:%d msb_right:%d\r\n",vinfo.green.offset,vinfo.green.length,vinfo.green.msb_right);
fprintf(stderr,"blue offset:%d length:%d msb_right:%d\r\n",vinfo.blue.offset,vinfo.blue.length,vinfo.blue.msb_right);
fprintf(stderr,"transp offset:%d length:%d msb_right:%d\r\n",vinfo.transp.offset,vinfo.transp.length,vinfo.transp.msb_right);
volatile int times = 30;
while(times--)
{
if(vinfo.bits_per_pixel == 16)
{
for(unsigned int i=0; i< len; )
{
*((uint16_t*)(p_fb + i)) = 0xF800;
i+=2;
}
usleep(atoi(argv[2])*1000);
for(unsigned int i=0; i< len;)
{
*((uint16_t*)(p_fb + i)) = 0x07E0;
i+=2;
}
usleep(atoi(argv[2])*1000);
for(unsigned int i=0; i< len;)
{
*((uint16_t*)(p_fb + i)) = 0x001F;
i+=2;
}
usleep(atoi(argv[2])*1000);
}
else
{
for(unsigned int i=0; i< len;)
{
*((uint32_t*)(p_fb + i)) = 0xFFFF0000;
i+=4;
}
usleep(atoi(argv[2])*1000);
for(unsigned int i=0; i< len;)
{
*((uint32_t*)(p_fb + i)) = 0xFF00FF00;
i+=4;
}
usleep(atoi(argv[2])*1000);
for(unsigned int i=0; i< len;)
{
*((uint32_t*)(p_fb + i)) = 0xFF0000FF;
i+=4;
}
usleep(atoi(argv[2])*1000);
}
}
munmap(p_fb,len);
close(fd);
return 0;
}
编译代码
aarch64-linux-gnu-gcc framebuffer.c -o framebuffer
将代码通过串口rz导入到开发板
将代码添加可执行权限
chmod +x framebuffer
运行
./framebuffer /dev/fb0 1000
打印了一些fb_var_screeninfo信息
root@forlinx:/# ./framebuffer /dev/fb0 1000
x = 1024, y = 600
vx = 1024, vy = 1200
ox = 0, oy = 0
bits = 32
gray = 0
red offset:16 length:8 msb_right:0
green offset:8 length:8 msb_right:0
blue offset:0 length:8 msb_right:0
见视频
其他相关操作
关闭默认桌面程序
/etc/init.d/S60Matrix_Browser stop
清除显示
fbinit 0
官方自带的颜色条测试程序
echo 1 > /sys/class/disp/disp/attr/colorbar
禁止自启动桌面Demo程序
vi /etc/autorun.sh
注释掉/usr/bin/matrix-browser 127.0.0.1 &
即可
总结
基于Framebuffer进行显示操作十分简单直接,开发环境也很简单,本文简单的测试了下LCD的刷屏。
注意有个坑:32位颜色值高8位表示透明度,但是逻辑是反的,255一般表示透明度最大,也就是全透明,而这里表示不透明。0表示全透明。这个坑一开始导致颜色值显示不了,还耽误了一些时间。