Framebuffer
开发环境
韦东山Linux开发板:IMX6ULL PRO 开发板
简介
Framebuffer 是用一个视频输出设备从包含完整的帧数据的一个内存缓冲区中来驱动一个视频显示设备。在内存缓冲区中标准上包含了屏幕上每个像素的色彩值组成。色彩值通常存储成1-bit(黑白色彩),4-bit调色版,8-bit调色板,16-bit高色彩,24-bit真色彩格式。一个额外的alpha通道有时用来保存像素透明度信息。帧缓冲设备提供了显卡的抽象描述。他同时代表了显卡上的显存,应用程序通过定义好的接口可以访问显卡,而不需要知道底层的任何操作。该设备使用特殊的设备节点,通常位于/dev/fbx目录。
Framebuffer的API函数
1、open函数
我们在虚拟机中可以使用man 2 open指令可以查看open函数的说明。即:
在这打开的open函数我们可以看到其中要包含的头文件和函数的说明。
open函数里有三个参数,即pathname、 flags、 mode三个参数。
①pathname英文是“路径名称”,即说明第一个参数是打开路径名称。在简介中已经说明其设备节点,通常位于/dev/fbx目录。
②而flags,则表示打开文件的方式、手段。而常用的一般是:
- O_RDWR 用可读可写方式打开。
- O_RDONLY 用只读方式打开。
- O_WRONLY 用只写方式打开。
- O_APPEND 如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面。
- O_TRUNC 如果这个文件中本来是有内容的,则原来的内容会被丢弃,截断。
- O_CREAT 当前打开文件不存在,我们创建它并打开它,通常与 O_EXCL 结合使用,当没有文件时创建文件,有这个文件时会报错提醒我们。
一般情况下我们都是使用第一种方式。
③ Mode 表示创建文件的权限,只有在 flags 中使用了 O_CREAT 时才有效,否则忽略。
2、ioctl 函数
同样我们在虚拟机中使用man指令查看其函数说明。
说明:
① fd 表示文件描述符;
② request 表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据;在framebuffer中常用FBIOGET_VSCREENINFO指令。
③ … 表示可变参数 arg,根据 request 命令,设备驱动程序返回输出的数据。
3、mmap 函数
同样打开mmap函数使用man指令。
说明:
① addr 表示指定映射的內存起始地址,通常设为 NULL 表示让系统自动选定地址,并在成功映射后返回该地址;
② length 表示将文件中多大的内容映射到内存中;
③ prot 表示映射区域的保护方式,可以为以下 4 种方式的组合
1)PROT_EXEC 映射区域可被执行
2)PROT_READ 映射区域可被读出
3) PROT_WRITE 映射区域可被写入
4) PROT_NONE 映射区域不能存取
framebuffer长用PROT_READ | PROT_WRITE进行组合
④ Flags 表示影响映射区域的不同特性,常用的有以下两种
1)MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。(常用)
2) MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中。
编写函数操作
1、打开我们的设备节点(open函数):
fd_fb = open("/dev/fb0", O_RDWR); //打开节点/dev/fb0,用可读可写方式
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
2、获取我们的lcd参数(ioctl函数):
在我们的LCD 驱动程序给 APP 提供 2 类参数:可变的参数fb_var_screeninfo、固定的参数 fb_fix_screeninfo。编写应用程序时主要关心可变参数,它的结构体定义如下(#include <linux/fb.h>)。
struct fb_var_screeninfo {
/*分辨率*/
__u32 xres;
__u32 yres;
__u32 bits_per_pixel; //bpp
/*****RGB的位表示*********/
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
}
知道这些之后我们就可以使用ioctl函数进行获取这些重要的参数:
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
3、内存的映射(mmap函数):
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fbmem == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
5、全部
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
static int fd_fb;
static struct fb_var_screeninfo var; /* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;
/**********************************************************************
* 函数名称: lcd_put_pixel
* 功能描述: 在LCD指定位置上输出指定颜色(描点)
* 输入参数: x坐标,y坐标,颜色
***********************************************************************/
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
unsigned short *pen_16;
unsigned int *pen_32;
unsigned int red, green, blue;
pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;
switch (var.bits_per_pixel)
{
case 8:
{
*pen_8 = color;
break;
}
case 16:
{
/* 565 */
red = (color >> 16) & 0xff;
green = (color >> 8) & 0xff;
blue = (color >> 0) & 0xff;
color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;
break;
}
default:
{
printf("can't surport %dbpp\n", var.bits_per_pixel);
break;
}
}
}
int main(int argc, char **argv)
{
int i;
fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{
printf("can't open /dev/fb0\n");
return -1;
}
if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{
printf("can't get var\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if (fb_base == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
/* 清屏: 全部设为白色 */
memset(fb_base, 0xff, screen_size);
/* 随便设置出100个为红色 */
for (i = 0; i < 100; i++)
lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);
munmap(fb_base , screen_size);
close(fd_fb);
return 0;
}