目录
1、Framebuffer设备驱动
帧缓冲(framebuffer)是 Linux 系统中的一种显示驱动接口,它将显示设备(譬如 LCD) 进行抽象、 屏蔽了不同显示设备硬件的实现,对应用层抽象为一块显示内存(显存),它允许上层应用程序直接对显示缓冲区进行读写操作,而用户不必关心物理显存的位置等具体细节,这些都由Framebuffer设备驱动来完成。
注:FrameBuffer设备对应的设备文件为/dev/fbX。
2、读写/dev/fbX 测试
应用程序读写/dev/fbX 就相当于读写显示设备的显示缓冲区(显存),譬如 LCD 的分辨率是800*480,每一个像素点的颜色用 24 位(譬如 RGB888)来表示,那么这个显示缓冲区的大小就是 800 x 480 x 24 / 8 =1152000 个字节。 譬如执行下面这条命令将 LCD 清屏,也就是将其填充为黑色(假设 LCD 对应的设备节点是/dev/fb0,分辨率为 800*480, RGB888 格式):
dd if=/dev/zero of=/dev/fb0 bs=1024 count=1125
3、LCD应用编程
4、ioctl()操作
定义在<linux/fb.h>头文件中。
常用宏 | 说明 | 结构体 |
FBIOGET_VSCREENINFO | 获取FrameBuffer 设备的可变参数信息 | struct fb_var_screeninfo |
FBIOGET_FSCREENINFO | 获取 FrameBuffer 设备的固定参数信息 | struct fb_fix_screeninfo |
FBIOPUT_VSCREENINFO | 设置FrameBuffer 设备的可变参数信息 | struct fb_var_screeninfo |
struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix;
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
4.1、结构体
定义在<linux/fb.h>头文件中。
4.1.1、fb_var_screeninfo结构体
struct fb_var_screeninfo {
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible */
__u32 yoffset; /* resolution */
__u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* 0 = color, 1 = grayscale, */
/* >1 = FOURCC */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
__u32 nonstd; /* != 0 Non standard pixel format */
__u32 activate; /* see FB_ACTIVATE_* */
__u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 rotate; /* angle we rotate counter clockwise */
__u32 colorspace; /* colorspace for FOURCC-based modes */
__u32 reserved[4]; /* Reserved for future compatibility */
}
xres | 可视区域 |
yres | |
xres_virtual | 虚拟区域 |
yres_virtual | |
xoffset | 虚拟区域到可视区域之间的偏移 |
yoffset | |
bits_per_pixel | 像素深度 bpp。每个像素点使用多少个 bit 来描述 |
grayscale | =0 表示彩色, =1 表示灰度, >1 表示 FOURCC 颜色 |
red | Red 颜色分量色域偏移 |
green | Green 颜色分量色域偏移 |
blue | Blue 颜色分量色域偏移 |
transp | 透明度分量色域偏移 |
nonstd | nonstd 等于 0,表示标准像素格式;不等于 0 则表示非标准像素格式 |
height | 用来描述 LCD 屏显示图像的高度(以毫米为单位) |
width | 用来描述 LCD 屏显示图像的宽度(以毫米为单位) |
注:通过 xres * yres * bits_per_pixel / 8 计算可得到整个显示缓存区的大小。
red、 green、 blue 描述了 RGB 颜色值中 R、 G、 B 三种颜色通道分别使用多少位以及它们各自的偏移量,通过 red、 green、 blue 变量可知道 LCD 的 RGB 像素格式(RGB888/RGB565)。
struct fb_bitfield {
__u32 offset; /* beginning of bitfield */
__u32 length; /* length of bitfield */
__u32 msb_right; /* != 0 : Most significant bit is */
/* right */
};
4.1.2、fb_fix_screeninfo结构体
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Indicate to driver which */
/* specific chip/card we have */
__u16 capabilities; /* see FB_CAP_* */
__u16 reserved[2]; /* Reserved for future compatibility */
};
id | 字符串形式的标识符 |
smem_start | 显存的起始地址(物理地址) 注:在应用层无法直接使用 |
smem_len | 显存的长度 |
line_length | 一行的字节数 |
5、测试代码
5.1、获取fb设备信息
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
void fb_get_var_screeninfo(int fd)
{
struct fb_var_screeninfo fb_var;
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
printf("分辨率: %d*%d\n",fb_var.xres, fb_var.yres);
printf("像素深度 bpp: %d\n",fb_var.bits_per_pixel);
printf("虚拟分辨率: %d*%d\n",fb_var.xres_virtual, fb_var.yres_virtual);
printf("虚拟分辨率->可视分辨率的偏移: x=%d,y=%d\n",fb_var.xoffset, fb_var.yoffset);
printf("grayscale: %d\n",fb_var.grayscale);
printf("nonstd: %d\n",fb_var.nonstd);
printf("像素格式:A<%d %d %d> R<%d %d %d> G<%d %d %d> B<%d %d %d>\n",
fb_var.transp.offset, fb_var.transp.length, fb_var.transp.msb_right,
fb_var.red.offset, fb_var.red.length,fb_var.red.msb_right,
fb_var.green.offset, fb_var.green.length,fb_var.green.msb_right,
fb_var.blue.offset, fb_var.blue.length,fb_var.blue.msb_right);
printf("height: %d\n",fb_var.height);
printf("width: %d\n",fb_var.width);
}
void fb_get_fix_screeninfo(int fd)
{
struct fb_fix_screeninfo fb_fix;
ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
printf("id: %s\n",fb_fix.id);
printf("line_length: %d\n",fb_fix.line_length);
}
int main(int argc, char *argv[])
{
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
int fd;
/* 打开 framebuffer 设备 */
if (0 > (fd = open("/dev/fb0", O_WRONLY))) {
perror("open error");
exit(-1);
}
fb_get_var_screeninfo(fd);
fb_get_fix_screeninfo(fd);
close(fd);
exit(0);
}
5.2、fb设备画点画线
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
static int width; //LCD X分辨率
static int height; //LCD Y分辨率
static unsigned int *screen_base = NULL; //映射后的显存基地址
/********************************************************************
* 函数名称: lcd_draw_point
* 功能描述: 打点
* 输入参数: x, y, color
* 返 回 值: 无
********************************************************************/
static void lcd_draw_point(unsigned int x, unsigned int y, unsigned int color)
{
/* 对传入参数的校验 */
if (x >= width)
x = width - 1;
if (y >= height)
y = height - 1;
/* 填充颜色 */
screen_base[y * width + x] = color;
}
/********************************************************************
* 函数名称: lcd_draw_line
* 功能描述: 画线(水平或垂直线)
* 输入参数: x, y, dir, length, color
* 返 回 值: 无
********************************************************************/
static void lcd_draw_line(unsigned int x, unsigned int y, int dir,
unsigned int length, unsigned int color)
{
unsigned int end;
unsigned long temp;
/* 对传入参数的校验 */
if (x >= width)
x = width - 1;
if (y >= height)
y = height - 1;
/* 填充颜色 */
temp = y * width + x; //定位到起点
if (dir) { //水平线
end = x + length - 1;
if (end >= width)
end = width - 1;
for ( ; x <= end; x++, temp++)
screen_base[temp] = color;
}
else { //垂直线
end = y + length - 1;
if (end >= height)
end = height - 1;
for ( ; y <= end; y++, temp += width)
screen_base[temp] = color;
}
}
/********************************************************************
* 函数名称: lcd_draw_rectangle
* 功能描述: 画矩形
* 输入参数: start_x, end_x, start_y, end_y, color
* 返 回 值: 无
********************************************************************/
static void lcd_draw_rectangle(unsigned int start_x, unsigned int end_x,
unsigned int start_y, unsigned int end_y,
unsigned int color)
{
int x_len = end_x - start_x + 1;
int y_len = end_y - start_y - 1;
lcd_draw_line(start_x, start_y, 1, x_len, color);//上边
lcd_draw_line(start_x, end_y, 1, x_len, color); //下边
lcd_draw_line(start_x, start_y + 1, 0, y_len, color);//左边
lcd_draw_line(end_x, start_y + 1, 0, y_len, color);//右边
}
/********************************************************************
* 函数名称: lcd_fill
* 功能描述: 将一个矩形区域填充为参数color所指定的颜色
* 输入参数: start_x, end_x, start_y, end_y, color
* 返 回 值: 无
********************************************************************/
static void lcd_fill(unsigned int start_x, unsigned int end_x,
unsigned int start_y, unsigned int end_y,
unsigned int color)
{
unsigned long temp;
unsigned int x;
/* 对传入参数的校验 */
if (end_x >= width)
end_x = width - 1;
if (end_y >= height)
end_y = height - 1;
/* 填充颜色 */
temp = start_y * width;
for ( ; start_y <= end_y; start_y++, temp+=width) {
for (x = start_x; x <= end_x; x++)
screen_base[temp + x] = color;
}
}
int main(int argc, char *argv[])
{
struct fb_fix_screeninfo fb_fix;
struct fb_var_screeninfo fb_var;
unsigned int screen_size;
int fd;
/* 打开framebuffer设备 */
if (0 > (fd = open("/dev/fb0", O_RDWR))) {
perror("open error");
exit(EXIT_FAILURE);
}
/* 获取参数信息 */
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
ioctl(fd, FBIOGET_FSCREENINFO, &fb_fix);
screen_size = fb_fix.line_length * fb_var.yres;
width = fb_var.xres;
height = fb_var.yres;
/* 将显示缓冲区映射到进程地址空间 */
screen_base = mmap(NULL, screen_size, PROT_WRITE, MAP_SHARED, fd, 0);
if (MAP_FAILED == (void *)screen_base) {
perror("mmap error");
close(fd);
exit(EXIT_FAILURE);
}
/* 画正方形方块 */
int w = height * 0.25; //方块的宽度为1/4屏幕高度
lcd_fill(0, width-1, 0, height-1, 0x0); //清屏(屏幕显示黑色)
lcd_fill(0, w, 0, w, 0xFF0000); //红色方块
lcd_fill(width-w, width-1, 0, w, 0xFF00); //绿色方块
lcd_fill(0, w, height-w, height-1, 0xFF); //蓝色方块
lcd_fill(width-w, width-1, height-w, height-1, 0xFFFF00); //黄色方块
/* 画白线 */
lcd_draw_line(0, height * 0.5, 1, width, 0xFFFFFF);
lcd_draw_line(width * 0.5, 0, 0, height, 0xFFFFFF);
/* 画矩形 */
unsigned int s_x, s_y, e_x, e_y;
s_x = 0.25 * width;
s_y = w;
e_x = width - s_x;
e_y = height - s_y;
for ( ; (s_x <= e_x) && (s_y <= e_y);
s_x+=5, s_y+=5, e_x-=5, e_y-=5)
lcd_draw_rectangle(s_x, e_x, s_y, e_y, 0xFFFFFF);
munmap(screen_base, screen_size);
close(fd);
exit(EXIT_SUCCESS);
}