当前位置: 首页 > web >正文

framebuffer框架与示例

        Framebuffer(帧缓冲)是计算机图形系统中用于存储图像数据的一块内存区域,这些区域直接对应屏幕上的每个像素。当图形系统需要更新屏幕显示时,会从帧缓冲中读取数据并传输到显示设备。

基本概念:

   1.物理帧缓冲:直接连接到显示设备的内存区域,修改其中的数据会立即反映在屏幕上。

   2.虚拟帧缓冲:在内存中创建的临时缓冲区,可用于离屏渲染(后台图形处理),之后再将结果复制到物理帧缓冲。

   3.像素格式:帧缓冲中的数据通常按特点格式组织,如 RGB(红、绿、蓝)或 RGBA(包含透明度),每个颜色分量占用 1 字节(8位)。

工作原理:

   1.直接映射:帧缓冲中的每个内存位置对应屏幕上的一个像素,其值决定了像素的颜色。

   2.双缓冲技术:为避免屏幕闪烁,系统通常使用两个缓冲区(前缓冲和后缓冲)。渲染时先更新后缓冲,完成后再与前缓冲交换。

Framebuffer 设备文件:

        在 linux 系统中,Framebuffer 设备通常映射为 /dev/fbx (x为数字,通常为 0)。s3c2440 平台上,默认设备为 /dev/fb0 ,通过操作该文件,可实现对屏幕的读写。

Framebuffer 编程接口:

   1.open():打开设备文件。

   2.ioctl():获取 / 设置显示参数(分辨率、位深等)。

   3.mmap():将设备内存映射到用户空间。

   4.write()/  read():直接读写设备文件(极少)。

应用层与内核层交互的方式:

   1.系统调用

   2.copy_to_user      copy_from_user

   3.信号

应用层向内核层的系统调用(传统字符设备驱动的流程)

流程:

        应用层操作设备文件------》设备文件对应有一个主次设备号-----》根据主次设备号可以找到 cdev 结构体-----》这个结构体里有 file_operations 结构体-----》重写open、read、write、release 函数接口。

弊端:

        当数据量特别大的时候,比如屏幕显示,有很多的像素点,每个像素点又有红绿蓝三种颜色,每一秒可能还要显示20帧的画面。由此,Framebuffer 就是一种针对这样的问题的一个解决方案。

解决方案:

        Framebuffer 就是linux系统中为显示设备提供的一种框架,在内核层有帧缓冲区

主要是为了解决数据频繁的搬移而引起的系统资源开销大的问题。

所以应用层就不用read、write函数了,主要用 mmap 进行内存映射。

一般来说,应用层是无法直接操作内核层的,但是通过 mmap ,我们就可以操作内核层的帧缓冲区域。

那么,再使用 Framebuffer 之前,需要做哪些准备呢?

Framebuffer 驱动架构

        首先,需要让硬件设备适配 Framebuffer 驱动架构,之前注册混杂设备是用 misc_register,那么这个就主要是 Framebuffer_register 。也就是写一个硬件屏幕驱动。

        但无论是硬件屏幕驱动还是Framebuffer驱动架构,都是比较复杂的,而友善之臂也已经写好了这些驱动,我们只需要学习如何调用即可,Framebuffer 在应用层是有一个标准的框架的。

linux 提供的 Framebuffer 应用层接口操作流程:

   1.打开设备,通常是 /dev/fb0

   2.向驱动发送获取屏幕信息的命令(宽度、高度、格式(是RGB 565还是RGB 888))。RGB 565对应 5 位红、6 位绿、5 位蓝。共 16 个像素点,对应 2 个字节。

   3.用mmap申请显存空间(宽度 * 高度 * 一个像素点所占字节数)

   4.向对应的位置写入 RGB 信息,然后封装绘点、绘线、绘面、绘图、绘汉字等相关功能。

具体操作:

首先根据显示设备的不同,需要进行不同的设置。

比如我所选用的显示设备是 td35的,那么就

cp config_mini2440_td35    .config

接着

make  menuconfig

直接退出再保存一下即可。

然后

make  UImage

重新生成一下 UImage

这样子,linux 系统就可以支持屏幕驱动了。

具体步骤:

   1.驱动友善之臂已经写好了。

   2.将内核目录顶层的所用的屏幕设备对应的 config (这里面就包含了这个屏幕的驱动)替换成 .config

   3.make menuconfig(根据 .config 来生成对应的配置)

   4.make  UImage 生成带有屏幕驱动的内核。

   5.将内核文件拷贝到 ~/tftpboot 目录下,因为每次内核都是重新下载的,所以就可以开机启动 uboot 下载 ~/tftpboot 目录下的 UImage

   6.现在该 linux 系统就成功带有屏幕驱动了。

启动之后:

        启动完之后,出现一个小企鹅,这就是 linux 系统的一个标志。有时候会出现一个 QT pi的软件界面,需要手动关掉。

开发板端输入:

vi  /etc/init.d/rcS

找到 /bin/qtopia &,把这个用 # 注释掉,然后wq保存退出即可,不然会显示乱码:


        OK,现在可以测试一下是否正常显示画面,我的这个显示设备是 240 x 320 的。首先得拷贝一下字库,不然显示不出来。

cp ziku2_w32_h32 ~/nfs/roots -rf

在 main.c 文件中,可以用以下命令:

draw_clear(0x00000000);        //清屏
draw_point(100,100,0xffff); //在100x100的位置画个点
draw_x_line(5,5,5,100,0xffff) //画条线

运行完后,发现显示的太大了,需要重新取一个字库。

打开易木雨,点阵字库生成器,

   1.编码选择:UNICODE

   2.宋体、12.

   3.高16、宽16

   4.字库格式选择:DZK

   5.创建

   6.chmod  +x  ziku

   7.chmod  0777  ziku

   7.cp  ziku  ~/nfs/rootfs

   8.回到内核层,./a.out 即可显示。

显示 adxl345 加速度传感器数据:

同理,可以将传感器所采集到的数据传到显示屏幕上了,如显示 adxl345 加速度传感器数据:

typedef struct {short x, y, z;
} adxl345_data_t;// 简单的文本绘制函数
void draw_text(char *text, int x, int y, unsigned int color, unsigned char *fbmem, struct fb_var_screeninfo vinfo) 
{int i, j;for (i = 0; text[i] != '\0'; i++) {for (j = 0; j < 8; j++) {if (text[i] & (1 << j)) {int index = ((y * vinfo.xres) + (x + i * 8 + j)) * (vinfo.bits_per_pixel / 8);if (index < vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8)) {*((unsigned int *)(fbmem + index)) = color;}}}}
}int main(void) 
{int fd_adxl345 = 0, fd_fb = 0;adxl345_data_t data;unsigned char buf[6] = {0};struct fb_var_screeninfo vinfo;struct fb_fix_screeninfo finfo;unsigned char *fbmem;long int screensize = 0;// 打开ADXL345设备fd_adxl345 = open("/dev/adxl345", O_RDWR);if (fd_adxl345 == -1) {perror("fail to open adxl345");return -1;}// 打开Framebuffer设备fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb == -1) {perror("fail to open framebuffer");close(fd_adxl345);return -1;}// 获取Framebuffer的可变信息if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &vinfo) == -1) {perror("Error reading variable information");close(fd_adxl345);close(fd_fb);return -1;}// 获取Framebuffer的固定信息if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &finfo) == -1) {perror("Error reading fixed information");close(fd_adxl345);close(fd_fb);return -1;}// 计算Framebuffer的大小screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;// 映射Framebuffer到用户空间fbmem = (unsigned char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if ((int)fbmem == -1) {perror("Error mapping framebuffer");close(fd_adxl345);close(fd_fb);return -1;}while (1) {// 读取ADXL345传感器数据read(fd_adxl345, buf, sizeof(buf));data.x = (buf[1] << 8 | buf[0]);data.y = (buf[3] << 8 | buf[2]);data.z = (buf[5] << 8 | buf[4]);float ax = data.x * 0.00390625f;float ay = data.y * 0.00390625f;float az = data.z * 0.00390625f;// 清屏for (int i = 0; i < screensize; i++) {fbmem[i] = 0;}// 绘制加速度值到屏幕char text[100];sprintf(text, "Acceleration: x=%.3f g, y=%.3f g, z=%.3f g", ax, ay, az);draw_text(text, 10, 10, 0xFFFFFF, fbmem, vinfo);sleep(1);}// 解除映射munmap(fbmem, screensize);// 关闭设备close(fd_adxl345);close(fd_fb);return 0;
}

http://www.xdnf.cn/news/4290.html

相关文章:

  • 保障企业的数据安全需要做什么?
  • npm下载插件无法更新package.json和package-lock.json文件的解决办法
  • 脑机接口:从科幻到现实,它将如何改变医疗未来?
  • 岳冉RFID手持式读写器专业研发+模块定制双驱动
  • Dynadot专业版邮箱工具指南(一):创建并设置新邮箱
  • 使用 Python 监控系统资源
  • 高等数学第五章---定积分(§5.1定积分的概念、性质和应用)
  • ShardingJdbc-水平分库
  • tinyrenderer笔记(Phong光照模型)
  • 悬崖边的摄影牧歌
  • ModuleNotFoundError 错误
  • [前端]Javascript获取元素宽度
  • Blink和V8的关系
  • Ubuntu 系统详解
  • 0基础学习鸿蒙开发-HarmonyOS4
  • 购物|电商购物小程序|基于微信小程序的购物系统设计与实现(源码+数据库+文档)
  • 我用cursor 搭建了临时邮箱服务-Temp Mail 365
  • python实战:通过输入文字匹配在docx文档中的具体位置
  • Linux进程8-共享内存概念机操作、shmget/shmat/shmdt/shmctl函数用法、空间大小修改
  • 【LLIE专题】基于 CLIP 的无监督背光增强算法
  • 【HarmonyOS 5】鸿蒙用户头像编辑功能实践
  • HA: Natraj靶场渗透测试
  • 2024 ICPC武汉邀请赛暨湖北省赛 题解
  • Vue 自定义指令输入校验过滤
  • AI Agent开发第57课-AI用在销售归因分析场景中-用随机森林从0构建自己的“小模型”
  • 亿级流量系统架构设计与实战(四)
  • Select Rows组件研究
  • 指针的应用
  • SQL注入总结
  • 【C++】C++中的命名/名字/名称空间 namespace