LCD Framebuffer应用开发 - 操作原理

1.1 LCD Framebuffer操作原理

​ LCD Framebuffer 就是一块显存,在嵌入式系统中,显存是被包含在内存中。LCD Framebuffer里的若干字节(根据驱动程序对LCD控制器的配置而定)表示LCD屏幕中的一个像素点,一一对应整个LCD屏幕。举个例子,LCD屏幕是800* 600的分辨率,即LCD屏幕存在480000个像素点,若每个像素点4个字节表示,那么LCD Framebuffer显存大小为480000 * 4=960000字节,即1.92MB。因此我们的内存将会分割至少1.92MB的空间用作显存。具体地址在哪里,这个就是又驱动程序去定,应用程序只需直接使用即可,硬件相关操作已由驱动程序封装好。

FramebufferAPP_Image00001

​ 如上图,我们只需要往Framebuffer中填入不同的值,驱动程序和硬件控制器就会把这些数据传输到对应LCD屏幕上的像素点,从而显示不同的颜色。由此可知,我们应用程序只需要针对Framebuffer操作即可,其他交给驱动程序和硬件。

#1.2 Framebuffer API接口

#1.2.1 open系统调用

FramebufferAPP_Image00002

头文件:#include <sys/types.h>,#include <sys/stat.h>,#include <fcntl.h>

函数原型:

  • int open(const char *pathname, int flags);
  • int open(const char *pathname, int flags, mode_t mode);

函数说明:

  • pathname 表示打开文件的路径;

  • Flags表示打开文件的方式,常用的有以下6种,

    ①:O_RDWR表示可读可写方式打开;

    ②:O_RDONLY表示只读方式打开;

    ③:O_WRONLY表示只写方式打开;

    ④:O_APPEND 表示如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面;

    ⑤:O_TRUNC表示如果这个文件中本来是有内容的,则原来的内容会被丢弃,截断;

    ⑥:O_CREAT表示当前打开文件不存在,我们创建它并打开它,通常与O_EXCL结合使用,当没有文件时创建文件,有这个文件时会报错提醒我们;

Mode表示创建文件的权限,只有在flags中使用了O_CREAT时才有效,否则忽略。

返回值:打开成功返回文件描述符,失败将返回-1。

#1.2.2 ioctl系统调用

FramebufferAPP_Image00003

头文件:#include <sys/ioctl.h>

函数原型:

  • int ioctl(int fd, unsigned long request, ...);

函数说明:

  • fd 表示文件描述符;
  • request表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据;
  • … 表示可变参数arg,根据request命令,设备驱动程序返回输出的数据。

返回值:打开成功返回文件描述符,失败将返回-1。

#1.2.3 mmap系统调用

FramebufferAPP_Image00004

头文件:#include <sys/mman.h>

函数原型:

  • void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

函数说明:

  • addr表示指定映射的內存起始地址,通常设为 NULL表示让系统自动选定地址,并在成功映射后返回该地址;

  • length表示将文件中多大的内容映射到内存中;

  • prot 表示映射区域的保护方式,可以为以下4种方式的组合

    ①PROT_EXEC 映射区域可被执行

    ②PROT_READ 映射区域可被读写

    ③PROT_WRITE 映射区域可被写入

    ④PROT_NONE 映射区域不能存取

  • Flags 表示影响映射区域的不同特性,常用的有以下两种

    ①MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。

    ②MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中。

返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。

#1.3 在LCD上描点操作

1.3.1 在LCD上显示点阵理论基础

FramebufferAPP_Image00005

​ 如上图,当我们需要显示一个字母‘A’时,是通过判断点阵的每一个位数值状态,来填充颜色,达到显示字符效果。其中‘1’表示一种颜色,‘0’表示填充另一种颜色。上图的是8*16的点阵,我们也可以用其他不同大小点阵,只要有这个点阵,我们就可以在LCD上面描点,达到显示字符的效果。

#1.3.2 获取fb_var_screeninfo结构体

​ 在用点阵显示字符之前,我们需要先从设备fb0中获取相关的LCD信息,下图截取我们将用到的fb_info结构体部分内容。

FramebufferAPP_Image00006

​ 通过系统调用ioctl,获取xres(x方向总像素点),yres(y方向总像素点),bits_per_pixel(每个像素点占据的位数),根据获取的三个资源,外加点阵,根据这四个资源,我们就可以显示一个字符。

程序文件:show_ascii.c

4718        fd_fb = open("/dev/fb0", O_RDWR);
4719        if (fd_fb < 0)
4720        {
4721            printf("can't open /dev/fb0\n");
4722            return -1;
4723        }
4724        if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
4725        {
4726			printf("can't get var\n");
4727			return -1;
4728		}	

​ 先打开LCD设备(fb0),获得文件描述符,再通过ioctl获取fb_var_screeninfo信息并保存在var变量,后续只需访问var这个结构体,就可以获得xres(x方向总像素点),yres(y方向总像素点),bits_per_pixel(每个像素点占据的位数)这三个关于fb0的资源。

#1.3.3 根据fb_var_screeninfo计算变量

fb_var_screeninfo已保存在var结构体变量中,接着来访问var结构体变量即可

根据xres与bits_per_pixel算出每行像素点所占据的字节数

程序文件:show_ascii.c

4730	line_width  = var.xres * var.bits_per_pixel / 8;

根据bits_per_pixel算出每个像素点所占据的字节数

程序文件:show_ascii.c

4731    pixel_width = var.bits_per_pixel / 8;

根据xres,yres,bits_per_pixel算出全部像素点所占据的字节总和

程序文件:show_ascii.c

4732    screen_size = var.xres * var.yres * var.bits_per_pixel / 8;

#1.3.4 使用mmap系统调用,映射内存

程序文件:show_ascii.c

4733	fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | 			PROT_WRITE, MAP_SHARED, fd_fb, 0);
4734	if (fbmem == (unsigned char *)-1)
4735	{
4736		printf("can't mmap\n");
4737		return -1;
4738	}
4739
4740	/* 清屏: 全部设为黑色 */
4741	memset(fbmem, 0, screen_size);

​ 调用mmap将显存映射在内存中,以可读可写(PROT_READ | PROT_WRITE)及内存回写(MAP_SHARED)的方式映射,从而获得一个指向映射在内存空间的首地址fbmem,后续操作就是在这个首地址的基础上计算各种不同的偏移量,填充颜色值。

#1.3.5 描点函数编写

程序文件:show_ascii.c

4641	void lcd_put_pixel(int x, int y, unsigned int color)

描点函数有3个参数,x坐标,y坐标,像素点颜色值。

程序文件:show_ascii.c

4643		unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width;
4644		unsigned short *pen_16;	
4645		unsigned int *pen_32;	
4646
4647		unsigned int red, green, blue;	
4648
4649		pen_16 = (unsigned short *)pen_8;
4650		pen_32 = (unsigned int *)pen_8;

​ 在此处函数参数x与y表示的是像素点的坐标,而单个像素点所占据的显存大小可能会有不同的情况出现,如1字节表示一个像素点,2字节表示一个像素点,4字节表示一个像素点等,为了更多的兼容不同的情况,因此申请3个指针,pen_8指向的是占据1个字节的像素点空间, pen_16指向的是占据2个字节的像素点空间,pen_32指向的是占据4个字节的像素点空间。

fbmem是系统调用mmap返回的显存首地址,根据fbmem计算填充颜色的内存空间。

当像素点占据1个字节空间时

对应描点地址= fbmem+Y * 一行所占据的字节数 + x * 每个像素点所占据的字节数

程序文件:show_ascii.c

4652		switch (var.bits_per_pixel)
4653		{
4654			case 8:
4655			{
4656				*pen_8 = color;
4657				break;
4658			}
4659			case 16:
4660			{
4661				/* 565 */
4662				red   = (color >> 16) & 0xff;
4663				green = (color >> 8) & 0xff;
4664				blue  = (color >> 0) & 0xff;
4665				color = ((red >> 3) << 11) | ((green >> 2) << 5) | 						(blue >> 3);
4666				*pen_16 = color;
4667				break;
4668			}
4669			case 32:
4670			{
4671				*pen_32 = color;
4672				break;
4673			}
4674			default:
4675			{
4676				printf("can't surport %dbpp\n", var.bits_per_pixel);
4677				break;
4678			}
4679		}
4680	}

​ 根据设备fb0实际的bits_per_pixel值,选择对应的pen(pen_8,pen_16,pen_32其中一个),最后把color颜色变量传入选择的pen中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值