大家好,欢迎来到IT知识分享网。
目录
LCD 显示驱动
一、LCD屏幕参数
1. 像素的颜色怎么表示
用红绿蓝三颜色来表示,可以用24位数据来表示红绿蓝,也可以用16位等等格式,比如:
- bpp:bits per pixel,每个像素用多少位来表示
- 24bpp:实际上会用到32位,其中8位未使用,其余24位中分别用8位表示红®、绿(G)、蓝(B)
- 16bpp:有rbg565,rgb555
- rgb565:用5位表示红、6位表示绿、5位表示蓝
- rgb555:16位数据中用5位表示红、5位表示绿、5位表示蓝,浪费一位
2. 怎么把颜色发给LCD
- Framebuffer中每块数据对应一个像素
- 每块数据的大小可能是16位、32位,这跟LCD上像素的颜色格式有关
- 设置好LCD硬件后,只需要把颜色数据写入Framebuffer即可
3. 应用工程师需要做什么?
只需通过修改fb中特定位置的像素来改变颜色,所以需要掌握:
- fb中每个像素用多少位表示?颜色格式是怎样的?
- fb显存的基地址是多少?
- 屏幕的分辨率?
4. 驱动工程师需要做什么?
- fb显存的位置是在哪里?
- LCD控制从fb中读取数据用来更新,那谁来传输这个数据?
二、统一的LCD硬件模型
1. LCD屏幕主要分为三种:
- MIPI-DBI(Display Bus Interface) ,MCU常用的8080接口LCD模组。
- 既然是Bus(总线),就是既能发送数据,也能发送命令,常用的8080接口就属于DBI接口。
- Type B (i-80 system), 8-/9-/16-/18-/24-bit bus
- Type C (Serial data transfer interface, 3/4-line SPI)
- MIPI-DPI (Display Pixel Interface) ,即搭载MPU的Linux开发板使用的(TFT RGB接口)。
- Pixel(像素),强调的是操作单个像素,在MPU上的LCD控制器就是这种接口
- Supports 24 bit/pixel (R: 8-bit, G: 8-bit, B: 8-bit)
- Supports 18 bit/pixel (R: 6-bit, G: 6-bit, B: 6-bit)
- Supports 16 bit/pixel (R: 5-bit, G: 6-bit, B: 5-bit)
MIPI-DSI (Display Serial Interface)
- Serial,相比于DBI、DPI需要使用很多接口线,DSI需要的接口线大为减少
- Supports one data lane/maximum speed 500Mbps
- Supports DSI version 1.01
- Supports D-PHY version 1.00
三、Frambuffer驱动框架
1. 怎么编写字符设备驱动程序
- 驱动主设备号
- 构造file_operations结构体,填充open/read/write等成员函数
- 注册驱动:register_chrdev(major, name, &fops)
- 入口函数
- 出口函数
2. Framebuffer驱动程序框架
分为上下两层:
- fbmem.c:承上启下
- 在字符设备驱动框架基础上
- 实现、注册file_operations结构体
- 把APP的调用向下转发到具体的硬件驱动程序
- xxx_fb.c:硬件相关的驱动程序
- 实现、注册fb_info结构体
- 实现硬件操作
核心:
- 分配fb_info
- framebuffer_alloc
- 设置fb_info
- var,屏幕分辨率,颜色格式
- fix,屏幕物理地址,虚拟地址,需要开辟空间大小
- fbops
- 硬件相关操作
- 引脚设置,pinctrl子系统
- 时钟设置
- LCD控制器设置
- 注册fb_info
- register_framebuffer
Framebuffer驱动和底层显示驱动之间的数据传输是一个关键过程,它涉及将图像数据从内存(或称为帧缓冲区)传输到显示设备上。这个过程在Linux内核中得到了良好的抽象和封装,以下是详细的解释:
3. Framebuffer驱动的作用
4. 数据传输机制
4.1 帧缓冲区的创建与映射
- 创建帧缓冲区:Framebuffer驱动在内核中申请一块显存,用于存放将要显示的图像数据。
- 映射帧缓冲区:通过mmap(内存映射)机制,将这块显存映射到用户空间的虚拟地址空间中,使得应用层可以直接访问和操作这块显存。
4.2 数据的写入与显示
- 数据写入:上层应用通过mmap映射的虚拟地址,将图像数据写入帧缓冲区。
- 显示驱动:底层显示驱动负责监控帧缓冲区的变化。当帧缓冲区中的数据更新时,显示驱动会将新的数据从帧缓冲区传输到显示设备的SRAM(静态随机存取存储器)中。
- LCD控制器:LCD控制器负责将SRAM中的数据转换成LCD屏幕可以识别的信号,从而驱动LCD屏幕显示图像。
4.3 传输的具体实现
- DMA(直接内存访问):在很多情况下,CPU并不直接参与帧缓冲区到显示设备SRAM的数据传输过程。相反,它使用DMA控制器来完成这一任务。DMA控制器可以独立于CPU运行,直接从帧缓冲区读取数据并写入到显示设备的SRAM中,从而大大提高了数据传输的效率。
- 寄存器配置:底层显示驱动还需要配置LCD控制器的相关寄存器,以确保数据能够正确地从帧缓冲区传输到显示设备,并在LCD屏幕上正确显示。
四、Framebuffer应用编程
在应用程序中,操作/dev/fbX 的一般步骤如下:
- 首先打开/dev/fbX 设备文件。
- 使用 ioctl()函数获取到当前显示设备的参数信息,譬如屏幕的分辨率大小、像素格式,根据屏幕参
数计算显示缓冲区的大小。 - 通过存储映射 I/O 方式将屏幕的显示缓冲区映射到用户空间(mmap)。
- 映射成功后就可以直接读写屏幕的显示缓冲区,进行绘图或图片显示等操作了。
- 完成显示后,调用 munmap()取消映射、并调用 close()关闭设备文件。
fb显示之刷背景和划线
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/ioctl.h> #include <sys/mman.h> // 宏定义 #define FBDEVICE "/dev/fb0" #define WIDTH 1024 #define HEIGHT 600 #define WHITE 0xffffffff // test ok #define BLACK 0x00000000 #define RED 0xffff0000 #define GREEN 0xff00ff00 // test ok #define BLUE 0xff0000ff #define GREENP 0x0000ff00 // 一样,说明前2个ff透明位不起作用 // 函数声明 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); // 第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<height; y++) {
for (x=0; x<width; x++) {
*(pfb + y * WIDTH + x) = color; } } } //画线函数 void draw_line(unsigned int color) {
unsigned int x, y; for (x=50; x<600; x++) {
*(pfb + 200 * WIDTH + x) = color; } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/127508.html