lcd的显像原理:将DDR内存的一部分划分出来作为显存,显存与lcd显示屏幕之间做一个双向的映射,然后用户只需要将需要显示的内容放入显存之中,然后显存中的内容就会刷新到lcd的储存器中进行显示。
显存:在内核之中申请一块内存作为显存,由于内核空间和用户空间,也就是驱动和应用不能直接进行内容的复制,需要借助专门的接口函数copy_to_user和copy_from_user,而这两个函数的效率很慢,所以我们将在内核空间中申请的这块虚拟地址,而这个虚拟地址肯定会对应一块真实的物理地址,然后应用层mmap申请一段内存,进而进行虚拟地址映射,与我们之前显存对应的物理地址绑定,这样应用对于显存进行操作,驱动就可以将其显示在lcd上。
freamebuffer设备:
(1)由于lcd显示设备包括显示器的驱动器,显卡,以及各种不同位数的显示器,所以linux内核虚拟出来一个framebuffer设备向应用层提供一个统一的标准接口的显示设备(一般在/dev/fb0),应用可以使用open、read、write等对设备进行操作。
(2)fb设备是一个字符设备,他的设备框架自己创建了一个类/sys/class/graphic;
对于fb设备的简单操作:
#include
#include
#include
#include
#include
#include
#include
// 宏定义
#define FBDEVICE "/dev/fb0"
#define WIDTH 1024 //开发板的lcd显示屏的长宽
#define HEIGHT 600
#define WHITE 0xffffffff
#define BLACK 0x00000000
#define RED 0xffff0000
#define GREEN 0xff00ff00
#define BLUE 0xff0000ff
#define GREENP 0x0000ff00
// 函数声明
void draw_back(unsigned int width, unsigned int height, unsigned int color);
void draw_line(unsigned int color);
// 全局变量
unsigned int *pfb = NULL;
int main(void)
{
int fd = -1, ret = -1;
struct fb_fix_screeninfo finfo = {0};
struct fb_var_screeninfo vinfo = {0};
// 第1步:打开设备
fd = open(FBDEVICE, O_RDWR);
if (fd < 0)
{
perror("open");
return -1;
}
printf("open %s success.\n", FBDEVICE);
// 第2步:获取设备的硬件信息
ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
if (ret < 0)
{
perror("ioctl");
return -1;
}
printf("smem_start = 0x%x, smem_len = %u.\n", finfo.smem_start, finfo.smem_len);
ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
if (ret < 0)
{
perror("ioctl");
return -1;
}
printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
printf("bpp = %u.\n", vinfo.bits_per_pixel);
// 修改驱动中屏幕的分辨率
vinfo.xres = 1024;
vinfo.yres = 600;
vinfo.xres_virtual = 1024;
vinfo.yres_virtual = 1200;
ret = ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo);
if (ret < 0)
{
perror("ioctl");
return -1;
}
// 再次读出来检验一下
ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinfo);
if (ret < 0)
{
perror("ioctl");
return -1;
}
printf("修改过之后的参数:\n");
printf("xres = %u, yres = %u.\n", vinfo.xres, vinfo.yres);
printf("xres_virtual = %u, yres_virtual = %u.\n", vinfo.xres_virtual, vinfo.yres_virtual);
printf("bpp = %u.\n", vinfo.bits_per_pixel);
// 第3步:进行mmap
unsigned long len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel / 8;
printf("len = %ld\n", len);
pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (NULL == pfb)
{
perror("mmap");
return -1;
}
printf("pfb = %p.\n", pfb);
draw_back(WIDTH, HEIGHT, WHITE);
draw_line(RED);
close(fd);
return 0;
}
void draw_back(unsigned int width, unsigned int height, unsigned int color)
{
unsigned int x, y;
for (y=0; y
(1)打开fb设备:
fd = open(FBDEVICE, O_RDWR);
(2)获取lcd设备的具体参数如:分辨率信息:
ret = ioctl(fd, FBIOGET_FSCREENINFO, &finfo);
其中 FBIOGET_FSCREENINFO 代表读取参数,FBIOPUT_VSCREENINFO 代表设置参数。
(3)应用申请内存,并进行虚拟地址映射:
pfb = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
mmap函数的原型为:
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
第一个参数:想要映射的虚拟地址,第二个参数:映射的长度、第三个:映射内存的权限、第四个:打开的fb设备为文件描述符、第五个:映射的地址的偏移量。
在这里NULL表示使用系统分配的虚拟地址、PROT_READ | PROT_WRITE表示映射的地址可读可写、MAP_SHARED表示内存可被其他的进程共享打开使用、0表示偏移地址量为0.
(4)接着可以进行freambuffer显存内容的填充,之后就可以显示了。
End。。。。。。