IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于STM32MP157的LCD FrameBuffer驱动 -> 正文阅读

[嵌入式]基于STM32MP157的LCD FrameBuffer驱动

基于STM32MP157之 FrameBuffer框架的LCD驱动

1.什么是FrameBuffer?

Framebuffer翻译为中文即帧缓冲区,帧这个单位是影像动画中的最小单位,一帧就是一副静止的画面,连续的帧就形成了动画,那么帧缓冲区就是用来缓存一帧画面的数据。在linux内核当中它就是一种程序接口,这个接口将显示器设备抽象为帧缓冲区,这个帧缓冲区一般是根据显示设备的分辨率和图像格式(ARGB888、RGB888、RGB565等)来确定缓冲区大小,从内存中申请一块区域,当我们要显示一副图片时,我们将图片的数据写入帧缓冲区即可。

2. FrameBuffer驱动程序框架

FrameFBuffer驱动就是一个字符驱动,所以它首先是建立在字符设备基础上的,那字符驱动的一般框架时如何的呢?

  1. 字符设备操作流程

    用户操作一个硬件的过程就上图所示,对于linux而言,一切皆为文件,对于硬件上的每一个设备都抽象为文件,在根目录下的/dev目录,存放的就是我们的设备文件

    如图所示,里面有字符驱动gpio,i2c,还有块驱动mmcblk1,mmcblk1boot0等,其中的fb0就是我的开发板上的lcd framebuffer驱动。通过ls -la /dev/fb0可以查看这个驱动信息:这个c就代表它是一个字符设备,且主设备号为29,次设备号为0

  2. LCD FrameBuffer驱动程序框架分析

    对于一个普通的字符设备,通常有以下五个步骤:

    • 第一步:获取主设备号major,可以自动分配,也可以自己选没有被使用的主设备号
    • 第二步:创建file_operation结构体,初始化成员变量.open、.release、.read、.write等成员变量
    • 第三步:注册字符设备驱动
      • register_chrdev(major,name,file_operation);根据主设备号和file_operation注册设备驱动
      • class_creat();动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加到内核中。创建的逻辑类位于/sys/class中
      • device_create();在/dev目录下创建相应的设备节点
    • 第四步:入口函数,使用module_init()宏进行修饰,驱动程序加载时将执行这个函数,入口函数中调用第三部的函数
    • 第五步:出口函数,使用module_exit()宏进行修饰,当驱动程序卸载时将执行这个函数,出口函数中进行:
      • unregister_chrdev();注销字符设备驱动
      • device_destroy();删除设备
      • class_destroy();删除class

    然而字符操作的这一系列操作内核已经帮我们实现了,这一下列操作在drivers/video/fbdev/core/fbmem.c文件中实现。实现过程如下:

    • 第一步:主设备号FB_MAJOR在include/uapi/linux/major.h有定义,为29

    • 第二步:file_operation创建和初始化
    static const struct file_operations fb_fops = {
    	.owner =	THIS_MODULE,
    	.read =		fb_read,
    	.write =	fb_write,
    	.unlocked_ioctl = fb_ioctl,
    #ifdef CONFIG_COMPAT
    	.compat_ioctl = fb_compat_ioctl,
    #endif
    	.mmap =		fb_mmap,
    	.open =		fb_open,
    	.release =	fb_release,
    #if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \
    	(defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \
    	 !defined(CONFIG_MMU))
    	.get_unmapped_area = get_fb_unmapped_area,
    #endif
    #ifdef CONFIG_FB_DEFERRED_IO
    	.fsync =	fb_deferred_io_fsync,
    #endif
    	.llseek =	default_llseek,
    };
    
    • 第三步:入口函数,执行注册字符驱动操作等
    static int __init  fbmem_init(void)
    {
    	int ret;
    
    	if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops))
    		return -ENOMEM;
    
        /*注册字符设备,FB_MAJOR 为主设备号,file_operation结构体为fb_fops*/
    	ret = register_chrdev(FB_MAJOR, "fb", &fb_fops);
    	if (ret) {
    		printk("unable to get major %d for fb devs\n", FB_MAJOR);
    		goto err_chrdev;
    	}
        /* 动态创建设备的逻辑类 ,位于/sys/class/目录下,名称为graphics*/
    	fb_class = class_create(THIS_MODULE, "graphics");
    	if (IS_ERR(fb_class)) {
    		ret = PTR_ERR(fb_class);
    		pr_warn("Unable to create fb class; errno = %d\n", ret);
    		fb_class = NULL;
    		goto err_class;
    	}
    
    	fb_console_init();
    	return 0;
    
    err_class:
    	unregister_chrdev(FB_MAJOR, "fb");
    err_chrdev:
    	remove_proc_entry("fb", NULL);
    	return ret;
    }
    module_init(fbmem_init);/* 入口函数 */
    
    • 第四步:出口函数,注销字符驱动操作等
    static void __exit
    fbmem_exit(void)
    {
    	fb_console_exit();
    
    	remove_proc_entry("fb", NULL);
    	class_destroy(fb_class);/* 删除fb_class类 */
    	unregister_chrdev(FB_MAJOR, "fb");/* 注销字符驱动 */
    }
    module_exit(fbmem_exit);
    

    然后我们简单分析一下fb_fops结构体中的.open函数fb_open()

    static int fb_open(struct inode *inode, struct file *file)
    __acquires(&info->lock)
    __releases(&info->lock)
    {
        /* 获得次设备号 inode结构体中存放了设备的设备号,可通过设备号来获取次设备号 */
    	int fbidx = iminor(inode);
    	struct fb_info *info;
    	int res = 0;
    
        /* 获取该设备对应的fb_info结构体 设备驱动注册时会根据次设备号注册fb_info结构体 */
    	info = get_fb_info(fbidx);
    	if (!info) {
    		request_module("fb%d", fbidx);
    		info = get_fb_info(fbidx);
    		if (!info)
    			return -ENODEV;
    	}
    	if (IS_ERR(info))
    		return PTR_ERR(info);
    
    	lock_fb_info(info);
    	if (!try_module_get(info->fbops->owner)) {
    		res = -ENODEV;
    		goto out;
    	}
    	file->private_data = info;
    	if (info->fbops->fb_open) {
    		res = info->fbops->fb_open(info,1);/* 调用fb_info结构体中fbops下的fb_open函数 */
    		if (res)
    			module_put(info->fbops->owner);
    	}
    #ifdef CONFIG_FB_DEFERRED_IO
    	if (info->fbdefio)
    		fb_deferred_io_open(info, inode, file);
    #endif
    out:
    	unlock_fb_info(info);
    	if (res)
    		put_fb_info(info);
    	return res;
    }
    

    在fb_open()函数中iminor(inode)根据设备文件的inode节点中的设备号来获取次设备号,get_fb_info()函数再根据次设备号获取一个fb_info结构体info,最终调用info->fbops->fb_open()函数。

    同理分析fb_release()函数,最终调用info->fbops->fb_release()函数,所以内核为我们提供了一个framebuffer框架,我们只需要实现一个fb_info结构体,这个结构体可通过此设备号查找得到,并且对该结构体中的fbops初始化。经过简单分析我们基本上可以得出LCD FrameBuffer框架流程如下:

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-07-25 11:50:39  更:2021-07-25 11:52:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:58:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码