嵌入式Linux学习——Framebuffer应用

嵌入式Linux学习——Framebuffer应用

LCD的基本操作原理

  1. 驱动程序设置好LCD控制器:根据LCD的参数设置LCD控制器的时序、信号极性;根据LCD分辨率、bpp分配Framebuffer
  2. APP通过 ioctl获得LCD分辨率、BPP
  3. APP通过 mmap 映射Framebuffer,在Framebuffer中写入数据

LCD操作原理示意

1.地址和RGB格式

fb_base 为使用mmap 后获得的地址,要确定 LCD中(x,y)坐标的地址由下面公式计算得到
(x,y)像素起始地址 = fb_base +(xres * bpp / 8)*y + x * bpp / 8
其中 xres表示 每行像素的个数。
bpp表示像素元素的表示格式,RGB三元素(红绿蓝),如下图有RGB888、RGB565、RBG555等格式。

RGB格式
RGB888就表示 红绿蓝每个颜色都用 8位来表示,颜色位占用低24位,高8为表示透明度,但一般的LCD不支持。
RGB888就是32BPP,对24BPP,硬件上为了方便处理,Framebuffer也是用32位来表示。
16BPP,常用的为RGB565。

2.涉及的API函数

2.1 open函数

头文件 
#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种。
Mode表示创建文件的权限,使用O_CREATE时有效。
返回值:打开成功返回文件描述符,失败返回-1。

参数打开方式
O_RDWR可读可写
O_RDONLY只读
O_WRONLY只写
O_APPEND若文件有内容,新写入的内容会接续到原内容后面
O_TRUNC如果文件原本有内容,原来的内容会被丢弃、截断
O_CREATE文件不存在,创建并打开它,与O_EXCL结合使用
O_EXCL没有文件创建文件时,有这个文件时会报错提醒,返回 -1

2.2 ioctl函数

ioctl(输入输出控制)是一个系统调用,用于设备驱动程序和用户空间之间的特殊控制操作。它允许程序通过特定的命令与设备进行交互,通常用于设置设备参数或获取设备状态。

函数原型

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

fd: 设备文件描述符,通过 open 函数获得。
request: 控制命令,用于指定要执行的操作。
…: 可选参数,通常是指向数据的指针,用于传递命令相关的信息。
常见用法
设备控制:设置或获取设备状态,例如配置串口参数、获取设备统计信息等。
网络接口控制:在网络编程中,ioctl 常用于配置网络接口,例如设置IP地址或获取网络接口信息。
示例

#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int fd;
    int result;

    // 打开设备文件
    fd = open("/dev/mydevice", O_RDWR);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 执行ioctl操作(假设IOCTL_CMD是一个定义的命令)
    result = ioctl(fd, IOCTL_CMD, NULL);
    if (result == -1) {
        perror("ioctl");
        close(fd);
        return 1;
    }

    // 关闭设备文件
    close(fd);
    return 0;
}

注意事项
命令定义:request 参数通常是通过宏定义的命令,例如 IOCTL_CMD,这些宏定义可能在设备驱动的头文件中找到。
权限问题:确保你有足够的权限来执行特定的 ioctl 操作。
设备依赖:ioctl 操作依赖于具体的设备驱动程序,因此不同设备支持的命令和操作可能有所不同。
ioctl 提供了与设备进行细粒度控制的能力,但它的具体实现和使用方式取决于设备的驱动程序。

2.3 mmap函数

mmap 是一个系统调用,用于将文件或设备的内容映射到进程的虚拟地址空间中,从而允许程序直接访问这些内容。它通常用于实现高效的文件 I/O 操作和共享内存。

函数原型

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

参数解释

  • addr: 映射的起始地址,通常设置为 NULL 让系统选择。
  • length: 映射的字节数。
  • prot: 内存保护标志,如 PROT_READ(可读)、PROT_WRITE(可写)。
  • flags: 映射选项,如MAP_PRIVATE(私有映射)、MAP_SHARED(共享映射)。
  • fd: 文件描述符,指向要映射的文件或设备。
  • offset: 文件的偏移量,必须是页面大小的整数倍。

示例

#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main() {
    int fd;
    void *mapped;
    size_t length = 4096; // 映射的字节数(例如1页大小)

    // 打开文件
    fd = open("example.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 映射文件到内存
    mapped = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
    if (mapped == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return 1;
    }

    // 使用映射的内存(例如打印内容)
    printf("Mapped content: %s\n", (char *)mapped);

    // 解除映射
    munmap(mapped, length);

    // 关闭文件
    close(fd);
    return 0;
}

常见标志和选项
PROT_READ: 允许读取。
PROT_WRITE: 允许写入。
MAP_PRIVATE: 创建私有映射,写入时不会影响原文件。
MAP_SHARED: 创建共享映射,写入时会影响原文件。
注意事项
页面对齐: offset 必须是页面大小的整数倍。
错误处理: mmap 可能失败,通常返回 MAP_FAILED。
权限管理: 根据需要设置适当的 prot 和 flags 选项。
mmap 允许高效的文件访问和进程间通信,但需要注意正确管理映射区域的权限和生命周期。

3. 流程分析

请添加图片描述

#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坐标,颜色
 * 输出参数: 无
 * 返 回 值: 会
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2020/05/12	     V1.0	  zh(angenao)	      创建
 ***********************************************************************/ 
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;	
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值