概述
一、Framebuffer介绍
在Linux系统中通过Framebuffer(帧缓冲)驱动程序来控制LCD。
Framebuffer就是一块内存,里面保存着一帧图像。Framebuffer中保存着一帧图像的每一个像素颜色值。LCD控制器周而复始地从Framebuffer中逐一取出每个像素的颜色值发送到LCD,这样LCD便能显示出图像。
假设LCD的分辨率是1024x768,每一个像素的颜色用32位来表示,那么Framebuffer的大小就是:1024x768x32/8=3145728字节。
二、确定LCD某坐标像素对应的Frambuffer地址
若LCD中存在某一点的坐标是(x,y),LCD最开始坐标是(0,0)。
(x,y)与(0,0)在Y方向距离y行,在X方向距离x个像素点。那么可以得出该点的偏移地址为(xres*bpp/8)*y + x *bpp/8(xres表示在纵方向的像素点数即分辨率)
xres * bpp/8即表示每一行所占用多少字节的内存
由偏移地址即可得出某点坐标处像素的起始地址:
(x,y)像素起始地址=fb_base+(xres*bpp/8)y + xbpp/8
bpp: bits per pixel 每个像素用多少位来表示它的颜色
fb_base是程序执行mmap后得到的Framebuffer地址
三、像素颜色的表示
颜色是由三原色构成,以下是三种表示方式
对于32BPP,一般只设置其中的低24位,高8位表示透明度,一般的LCD都不支持。
对于24BPP,硬件上为了方便处理,在Framebuffer中也是用32位来表示,效果跟32BPP是一样的。
对于16BPP,常用的是RGB565;很少的场合会用到RGB555,这可以通过ioctl读取驱动程序中的RGB位偏移来确定使用哪一种格式。
若想从以RGB888表示的颜色值得到以RGB565表示的值,只需要保留RGB888中相应高位即可。
比如RGB888的低八位表示蓝色,需要保留这八位的高5位即可得出RGB565中的蓝色数值。
四、API函数
1.ioctl函数
int ioctl(int fd, unsigned long request, ...);
// request表示与驱动程序交互的命令
//用不同的命令控制驱动程序输出我们需要的数据;
// … 表示可变参数arg,根据request命令,设备驱动程序返回输出的数据。
不同的驱动程序内部会实现不同的ioctl,APP可以使用各种ioctl跟驱动程序交互:可以传数据给驱动程序,也可以从驱动程序中读出数据。
2.mmap函数
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
// 关闭内存映射
munmap(void *start, size_t lenght)
- addr表示指定映射的內存起始地址,通常设为 NULL表示让系统自动选定地址,并在成功映射后返回该地址;
- length表示将文件中多大的内容映射到内存中;
- prot 表示映射区域的保护方式,可以为以下4种方式的组合
a. PROT_EXEC 映射区域可被执行
b. PROT_READ 映射区域可被读出
c. PROT_WRITE 映射区域可被写入
d. PROT_NONE 映射区域不能存取 - Flags 表示影响映射区域的不同特性,常用的有以下两种
a. MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。
b. MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中。 - 参数offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
- 返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。
五、代码实例
需要用ioctl函数获取LCD参数,在ioctl函数中用FBIOGET_VSCREENINFO获得屏幕的可变信息。
LCD驱动程序给APP提供2类参数:可变的参数fb_var_screeninfo、固定的参数fb_fix_screeninfo。编写应用程序时主要关心可变参数,它的结构体定义如下(#include <linux/fb.h>):
1 struct fb_var_screeninfo {
2 __u32 xres; // LCD的水平像素大小
3 __u32 yres; // LCD的垂直像素大小
4 __u32 xres_virtual; // LCD的虚拟水平像素大小
5 __u32 yres_virtual; // LCD的虚拟垂直像素大小
6 __u32 xoffset; // 水平像素偏移量
7 __u32 yoffset; // 垂直像素偏移量
8
9 __u32 bits_per_pixel; // 像素深度bpp
10 __u32 grayscale; /* != 0 Graylevels instead of colors */
11
12 struct fb_bitfield red; /* bitfield in fb mem if true color, */
13 struct fb_bitfield green; /* else only length is significant */
14 struct fb_bitfield blue;
15 struct fb_bitfield transp; /* transparency */
16
17 __u32 nonstd; /* != 0 Non standard pixel format */
18
19 __u32 activate; /* see FB_ACTIVATE_* */
20
21 __u32 height; // LCD的物理高度 mm
22 __u32 width; // LCD的物理宽度 mm
23
24 __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
25
27 __u32 pixclock; // 像素时钟
28
29 /* 下面是六个时序参数 */
30 __u32 left_margin; /* time from sync to picture */
31 __u32 right_margin; /* time from picture to sync */
32 __u32 upper_margin; /* time from sync to picture */
33 __u32 lower_margin;
34 __u32 hsync_len; /* length of horizontal sync */
35 __u32 vsync_len; /* length of vertical sync */
36
37 __u32 sync; /* see FB_SYNC_* */
38 __u32 vmode; /* see FB_VMODE_* */
39 __u32 rotate; /* angle we rotate counter clockwise */
40 __u32 reserved[5]; /* Reserved for future compatibility */
41 };
具体代码如下:
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <linux/fb.h>
struct fb_var_screeninfo var;
unsigned char *fb_base;
unsigned int line_width;
unsigned int pixel_width;
unsigned int screen_size;
// 描点函数
// 传入的color的格式是RGB888格式
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;
pen_16 = (unsigned short*)pen_8;
pen_32 = (unsigned int*)pen_8;
unsigned int red,green,blue;
switch (var.bits_per_pixel)
{
case 16:
{
// 从color变量中把R、G、B抽出来
red = (color>>16) & 0xff;
green = (color>>8) & 0xff;
blue = (color>>0) & 0xff;
// 根据RGB565的格式,只保留red中的高5位、green中的高6位、blue中的高5位,组合成一个新的16位颜色值
color = ((red>>3)<<11)|((green>>2)<<5)|(blue>>3);
*pen_16 = color;
break;
}
case 32:
{
*pen_32 = color;
break;
}
default:
{
printf("can not support bits_per_pixel:%dn",var.bits_per_pixel);
break;
}
}
}
int main(int argc, char * * argv)
{
// 打开设备文件
fd_fb = open("/dev/fb0",O_RDWR);
if(fd_fb==-1){
printf("open fb0 failedn");
}
// 获取屏幕的可变信息
if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&var)==-1){
printf("can not get varn");
}
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;
// 映射framebuffer
fb_base = (unsigned char*)mmap(NULL,screen_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd_fb,0);
if(fb_base==(unsigned char*)-1){
printf("fb_base errorn");
}
// 清屏 设置为白色
memset(fb_base,0xff,screen_size);
int i;
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;
}
运行平台:100ask-imx6ull开发板
交叉编译工具链:arm-linux-gnueabihf-gcc
在虚拟机已经开启NFS服务前提下,将编译好的文件复制到NFS目录下:
cp pixel ~/nfs_rootfs/
在ARM开发板上,若VMware使用桥接网络,使用下面命令挂载NFS
mount -t nfs -o nolock,vers=3 "ubuntu IP":/home/heavysea/nfs_rootfs /mnt
最后
以上就是顺心猎豹为你收集整理的Framebuffer应用编程一、Framebuffer介绍二、确定LCD某坐标像素对应的Frambuffer地址三、像素颜色的表示四、API函数五、代码实例的全部内容,希望文章能够帮你解决Framebuffer应用编程一、Framebuffer介绍二、确定LCD某坐标像素对应的Frambuffer地址三、像素颜色的表示四、API函数五、代码实例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复