嵌入式Linux应用开发-Framebuffer 应用编程

news2024/11/24 18:27:57

嵌入式Linux应用开发-Framebuffer 应用编程

  • 第五章 Framebuffer 应用编程
    • 5.1 LCD 操作原理
    • 5.2 涉及的 API 函数
      • 5.2.1 open 函数
      • 5.2.2 ioctl 函数
      • 5.2.3 mmap 函数
    • 5.3 Framebuffer 程序分析
      • 5.3.1 打开设备
      • 5.3.2 获取 LCD 参数
      • 5.3.3 映射 Framebuffer
      • 5.3.4 描点函数
      • 5.3.5 随便画几个点
    • 5.4 上机实验

第五章 Framebuffer 应用编程

5.1 LCD 操作原理

在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意思,buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值,假设 LCD 的分辨率是 1024x768,每一个像素的颜色用 32 位来表示,那么 Framebuffer 的大小就是:
1024x768x32/8=3145728 字节。
简单介绍 LCD 的操作原理:
① 驱动程序设置好 LCD 控制器:
根据 LCD 的参数设置 LCD 控制器的时序、信号极性;
根据 LCD 分辨率、BPP 分配 Framebuffer。
② APP 使用 ioctl 获得 LCD 分辨率、BPP
③ APP 通过 mmap 映射 Framebuffer,在 Framebuffer 中写入数据
在这里插入图片描述
假设需要设置 LCD 中坐标(x,y)处像素的颜色,首要要找到这个像素对应的内存,然后根据它的 BPP 值设置颜色。假设 fb_base 是 APP 执行 mmap 后得到的 Framebuffer 地址,如下图所示:
在这里插入图片描述

可以用以下公式算出(x,y)坐标处像素对应的 Framebuffer 地址:
(x,y)像素起始地址=fb_base+(xres*bpp/8)y + xbpp/8
最后一个要解决的问题就是像素的颜色怎么表示?它是用 RGB 三原色(红、绿、蓝)来表示的,在不同的BPP 格式中,用不同的位来分别表示 R、G、B,如下图所示:
在这里插入图片描述
对于 32BPP,一般只设置其中的低 24 位,高 8 位表示透明度,一般的 LCD 都不支持。
对于 24BPP,硬件上为了方便处理,在 Framebuffer 中也是用 32 位来表示,效果跟 32BPP 是一样的。
对于 16BPP,常用的是 RGB565;很少的场合会用到 RGB555,这可以通过 ioctl 读取驱动程序中的 RGB位偏移来确定使用哪一种格式。

5.2 涉及的 API 函数

本节程序的目的是:打开 LCD 设备节点,获取分辨率等参数,映射 Framebuffer,最后实现描点函数。

5.2.1 open 函数

在 Ubuntu 中执行“man 2 open”,可以看到 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 种,
a. O_RDWR 表示可读可写方式打开;
b. O_RDONLY 表示只读方式打开;
c. O_WRONLY 表示只写方式打开;
d. O_APPEND 表示如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面;
e. O_TRUNC 表示如果这个文件中本来是有内容的,则原来的内容会被丢弃,截断;
f. O_CREAT 表示当前打开文件不存在,我们创建它并打开它,通常与 O_EXCL 结合使用,当没有文件时
创建文件,有这个文件时会报错提醒我们;
③ Mode 表示创建文件的权限,只有在 flags 中使用了 O_CREAT 时才有效,否则忽略。
④ 返回值:打开成功返回文件描述符,失败将返回-1。

5.2.2 ioctl 函数

在 Ubuntu 中执行“man ioctl”,可以看到 ioctl 函数的说明:
在这里插入图片描述
头文件:

#include <sys/ioctl.h> 

函数原型:

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

函数说明:
① fd 表示文件描述符;
② request 表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据;
③ … 表示可变参数 arg,根据 request 命令,设备驱动程序返回输出的数据。
④ 返回值:打开成功返回文件描述符,失败将返回-1。

ioctl 的作用非常强大、灵活。不同的驱动程序内部会实现不同的 ioctl,APP 可以使用各种 ioctl 跟
驱动程序交互:可以传数据给驱动程序,也可以从驱动程序中读出数据。

5.2.3 mmap 函数

在 Ubuntu 中执行“man mmap”,可以看到 mmap 函数的说明:
在这里插入图片描述
想更深刻地理解 mmap 的内部机制,可以看《嵌入式 Linux 驱动开发基础知识》中关于 mmap 的介绍。作
为 APP 开发,只需要知道它的用法就可以了。
头文件:

#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 种方式的组合
a. PROT_EXEC 映射区域可被执行
b. PROT_READ 映射区域可被读出
c. PROT_WRITE 映射区域可被写入
d. PROT_NONE 映射区域不能存取
④ Flags 表示影响映射区域的不同特性,常用的有以下两种
a. MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。
b. MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回
原来的文件内容中。
⑤ 返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。

5.3 Framebuffer 程序分析

使用 GIT 下载所有源码后,本节源码位于如下目录:
01_all_series_quickstart\
04_嵌入式 Linux 应用开发基础知识\source\07_framebuffer\show_pixel.c

5.3.1 打开设备

首先打开设备节点:

73 fd_fb = open("/dev/fb0", O_RDWR); 
74 if (fd_fb < 0) 
75 { 
76 printf("can't open /dev/fb0\n"); 
77 return -1; 
78 } 

5.3.2 获取 LCD 参数

LCD 驱动程序给 APP 提供 2 类参数:可变的参数 fb_var_screeninfo、固定的参数 fb_fix_screeninfo。
编写应用程序时主要关心可变参数,它的结构体定义如下(#include <linux/fb.h>):
在这里插入图片描述

可以使用以下代码获取 fb_var_screeninfo:

 static struct fb_var_screeninfo var; /* Current var */ 
…… 
 if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) 
 { 
 	printf("can't get var\n"); 
 	return -1; 
 } 

注意到 ioctl 里用的参数是:FBIOGET_VSCREENINFO,它表示 get var screen info,获得屏幕的可变
信息;当然也可以使用 FBIOPUT_VSCREENINFO 来调整这些参数,但是很少用到。

对于固定的参数 fb_fix_screeninfo,在应用编程中很少用到。它的结构体定义如下:
在这里插入图片描述
可以使用 ioctl FBIOGET_FSCREENINFO 来读出这些信息,但是很少用到。

5.3.3 映射 Framebuffer

要映射一块内存,需要知道它的地址──这由驱动程序来设置,需要知道它的大小──这由应用程序决
定。代码如下:

85 line_width = var.xres * var.bits_per_pixel / 8; 
86 pixel_width = var.bits_per_pixel / 8; 
87 screen_size = var.xres * var.yres * var.bits_per_pixel / 8; 
88 fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, 
fd_fb, 0); 
89 if (fb_base == (unsigned char *)-1) 
90 { 
91 printf("can't mmap\n"); 
92 return -1; 
93 } 

第 88 行中,screen_size 是整个 Framebuffer 的大小;PROT_READ | PROT_WRITE 表示该区域可读、可写;MAP_SHARED 表示该区域是共享的,APP 写入数据时,会直达驱动程序,这个参数的更深刻理解可以参考后面驱动基础中讲到的 mmap 知识。

5.3.4 描点函数

能够在 LCD 上描绘指定像素后,就可以写字、画图,描点函数是基础。代码如下:

28 void lcd_put_pixel(int x, int y, unsigned int color) 
29 { 
30 unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width; 
31 unsigned short *pen_16; 
32 unsigned int *pen_32; 
33 
34 unsigned int red, green, blue; 
35 
36 pen_16 = (unsigned short *)pen_8; 
37 pen_32 = (unsigned int *)pen_8; 
38 
39 switch (var.bits_per_pixel) 
40 { 
41 	case 8: 
42 	{ 
43 		*pen_8 = color; 
44 		break; 
45 	} 
46 	case 16: 
47 	{ 
48 		/* 565 */ 
49 		red = (color >> 16) & 0xff; 
50 		green = (color >> 8) & 0xff; 
51 		blue = (color >> 0) & 0xff; 
52 		color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); 
53 		*pen_16 = color; 
54 		break; 
55 	} 
56 	case 32: 
57 	{ 
58 		*pen_32 = color; 
59 		break; 
60 	} 
61 	default: 
62 	{ 
63 		printf("can't surport %dbpp\n", var.bits_per_pixel); 
64 		break; 
65 	} 
66 } 
67 }

第 28 行中传入的 color 表示颜色,它的格式永远是 0x00RRGGBB,即 RGB888。当 LCD 是 16bpp 时,要把 color 变量中的 R、G、B 抽出来再合并成 RGB565 格式。
第 30 行计算(x,y)坐标上像素对应的 Framebuffer 地址。
第 43 行,对于 8bpp,color 就不再表示 RBG 三原色了,这涉及调色板的概念,color 是调色板的值。
第 49~51 行,先从 color 变量中把 R、G、B 抽出来。
第 52 行,把 red、green、blue 这三种 8 位颜色值,根据 RGB565 的格式,只保留 red 中的高 5 位、green 中的高 6 位、blue 中的高 5 位,组合成一个新的 16 位颜色值。
第 53 行,把新的 16 位颜色值写入 Framebuffer。
第 58 行,对于 32bpp,颜色格式跟 color 参数一致,可以直接写入 Framebuffer。

5.3.5 随便画几个点

本程序的 main 函数,在最后只是简单地画了几个点:

95 	/* 清屏: 全部设为白色 */ 
96	 memset(fbmem, 0xff, screen_size); 
97 
98 	/* 随便设置出 100 个为红色 */ 
99 	for (i = 0; i < 100; i++) 
100 		lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000); 

5.4 上机实验

在 Ubuntu 中编译程序,先设置交叉编译工具链,再执行以下命令:
arm-linux-gnueabihf-gcc -o show_pixel show_pixel.c

然后在开发板上执行 show_pixel 程序。

注意:板子的出厂程序中一般都有 GUI,所以可能需要把 GUI 程序禁止掉。具体方法请看本文档,以后会补充禁止 GUI 的方法。你可以先不禁止 GUI,直接执行 show_pixel 看看 LCD 有无现象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1044071.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

主机安装elasticsearch后无法登陆

问题描述 2023年7月31日11点02分&#xff0c;主机安装elasticsearch后无法登陆&#xff0c;通过后台查看主机宕机状态&#xff0c;CPU达到100%&#xff0c;按业务侧要求执行重启操作后发现主机黑屏无法正常进入系统&#xff0c;系统卡死。 2&#xff0e;原因分析 2.1通过故障…

自定义注解实现Redis分布式锁、手动控制事务和根据异常名字或内容限流的三合一的功能

自定义注解实现Redis分布式锁、手动控制事务和根据异常名字或内容限流的三合一的功能 文章目录 [toc] 1.依赖2.Redisson配置2.1单机模式配置2.2主从模式2.3集群模式2.4哨兵模式 3.实现3.1 RedisConfig3.2 自定义注解IdempotentManualCtrlTransLimiterAnno3.3自定义切面Idempote…

「Go框架」gin框架是如何处理panic的?

本文我们介绍下recover在gin框架中的应用。 首先&#xff0c;在golang中&#xff0c;如果在子协程中遇到了panic&#xff0c;那么主协程也会被终止。如下&#xff1a; package mainimport ("github.com/gin-gonic/gin" )func main() {r : gin.Default()// 在子协程中…

Apache DolphinScheduler 在奇富科技的首个调度异地部署实践

奇富科技&#xff08;原360数科&#xff09;是人工智能驱动的信贷科技服务平台&#xff0c;致力于凭借智能服务、AI研究及应用、安全科技&#xff0c;赋能金融机构提质增效&#xff0c;助推普惠金融高质量发展&#xff0c;让更多人享受到安全便捷的金融科技服务。作为国内领先的…

【RocketMQ】sendDefaultImpl call timeout 问题及其解决办法

问题描述&#xff1a; org.apache.rocketmq.remoting.exception.RemotingTooMuchRequestException: sendDefaultImpl call timeout解决&#xff1a; 需要开放10911、10909这两个端口 需修改broker.conf&#xff0c;设置公网IP 启动broker时&#xff0c;需用-c conf/broker.…

通俗易懂-OpenCV角点检测算法(Harris、Shi-Tomas算法实现)

目录 1 图像的特征 2&#xff0c;Harris角点检测 2.1 代码实现 2.2结果展示 3&#xff0c;Shi-Tomasi角点检测算法 3.1 &#xff0c; 代码实现 3.2结果展示 1 图像的特征 2&#xff0c;Harris角点检测 、 2.1 代码实现 import cv2 as cv import matplotlib.pyplot as …

RocketMQ —消费者负载均衡

消费者从 Apache RocketMQ 获取消息消费时&#xff0c;通过消费者负载均衡策略&#xff0c;可将主题内的消息分配给指定消费者分组中的多个消费者共同分担&#xff0c;提高消费并发能力和消费者的水平扩展能力。本文介绍 Apache RocketMQ 消费者的负载均衡策略。 背景信息​ …

Magic Battery for Mac:让你的设备电量管理变得轻松简单

Mac电脑用户们&#xff0c;你们是否曾经为了给设备充电而感到烦恼&#xff1f;是否希望能够方便地查看连接设备的电量情况&#xff1f;现在&#xff0c;有了Magic Battery for macOS&#xff0c;这些问题都将成为过去&#xff01; Magic Battery是一个实用的应用程序&#xff…

Spring Boot事件机制浅析

1、概述 在设计模式中&#xff0c;观察者模式是一个比较常用的设计模式。维基百科解释如下&#xff1a; 观察者模式是软件设计模式的一种。在此种模式中&#xff0c;一个目标对象管理所有相依于它的观察者对象&#xff0c;并且在它本身的状态改变时主动发出通知。这通常透过呼…

曲线救国-通过Magisk安装burp证书到系统根目录

0x01前言 需要对某APP做渗透测试&#xff0c;但该APP做了限制&#xff1a;不信任用户证书。因此需要将burp证书导入到存放系统证书目录下。虽然手机装了Magic&#xff0c;但似乎root有点问题。其挂载有问题&#xff0c;导致无法将 最初尝试&#xff1a;mount -o rw,remount -t…

成都优优聚能带给你什么?

美团代运营是美团针对商家提供的一项全方位的代理运营服务&#xff0c;通过专业团队的协助和优质服务&#xff0c;帮助商家提高品牌知名度、在线销售额、客户粘性等多重指标。下面将详细介绍美团代运营的优势。 1. 强大的平台资源&#xff1a; 作为中国最大的外卖平台之一&…

深度学习-学习率调度,正则化,dropout

正如前面我所说的&#xff0c;各种优化函数也依赖于学习率&#xff0c;保持学习率恒定总是有所限制&#xff0c;在执行梯度下降过程中&#xff0c;我们可以使用各种方法来调节训练过程的学习率&#xff0c;这里只是稍微介绍一下&#xff0c;不会写代码实现的。同时&#xff0c;…

python基于轻量级卷积神经网络模型GhostNet开发构建养殖场景下生猪行为识别系统

养殖业的数字化和智能化是一个综合应用了互联网、物联网、人工智能、大数据、云计算、区块链等数字技术的过程&#xff0c;旨在提高养殖效率、提升产品质量以及促进产业升级。在这个过程中&#xff0c;养殖生猪的数字化智能化可以识别并管理猪的行为。通过数字化智能化系统&…

分布式微服务架构中的关键技术解析

分布式微服务架构是构建现代应用的理想选择&#xff0c;它将复杂系统拆分成小而自治的服务&#xff0c;每个服务都能独立开发、测试和部署。在实际的开发过程中&#xff0c;如何实现高效的分布式微服务架构呢&#xff1f;下面笔者根据自己多年的实战经验&#xff0c;浅谈实战过…

Linux shell编程学习笔记3:查询系统中已安装可以使用的shell

〇、更新记录 20230926 编写 一、前言 目前可以在Linux系统上运行的shell有许多种&#xff1a;sh、bash、cshell、tcsh、zsh……但是对一台具体的系统来说&#xff0c;未必包括上面列的所有这些shell&#xff0c;很可能包括其中两三个。 那么我们如何查询系统中已经安装有哪…

阿里巴巴Java开发编程规约(整理详细版)

目录 前言 1.编程规约 1.1 命名风格 1.2 常量定义 1.3 代码格式 1.4 OOP 规约 1.5 日期时间 1.6 集合处理 1.7 并发处理 1.8 控制语句 1.9 注释规约 1.10 前后端规约 1.11 其他 前言 规约依次分为【重要】、【建议】、【参考】,整理开发规范的目的在于写出更加…

Linux内核学习笔记

这个跟考试一毛钱关系没有 纯个人爱好 考试党划走 Linux 8086映像 3.1Intel 8086寄存器 INTEL处理器通常有十六个寄存器 他们之间可以相互做运算 3.2 8086的内存访问 内存的数据交换 内存和寄存器通过16根地址线建立数据的交换&#xff0c;数据线的宽度和寄存器的宽度相等 注…

最新ChatGPT网站系统源码+支持GPT4.0+支持AI绘画Midjourney绘画+支持国内全AI模型

一、SparkAI创作系统 SparkAi系统是基于很火的GPT提问进行开发的Ai智能问答系统。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT系统&#xff1f;小编这里写一个详细图文教程吧&a…

博客无限滚动加载(html、css、js)实现

介绍 这是一个简单实现了类似博客瀑布流加载功能的页面&#xff0c;使用html、css、js实现。简单易懂&#xff0c;值得学习借鉴。&#x1f44d; 演示地址&#xff1a;https://i_dog.gitee.io/easy-web-projects/infinite_scroll_blog/index.html 代码 index.html <!DOCT…

Visual Code 开发web 的hello world

我以前做过&#xff0c;后来忘了怎么做了&#xff0c;所以还是要做个记录。 本文介绍visual code 开发web 的hello world 参考&#xff1a; Exercise - Set up the structure of your web app - Training | Microsoft Learn 打开Visual Code &#xff0c; 打开目录Open fol…