Framebuffer_LCD驱动介绍

本文深入探讨了Framebuffer子系统的工作原理及其与LCD控制器的关系。详细介绍了LCD控制器如何简化硬件交互,Framebuffer如何提供统一的接口供应用程序操作LCD。通过具体代码分析,展示了Framebuffer驱动的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

学习Framebuffer过程中,最大的困惑不是fb层的各个数据结构的交互,而是stm32驱动LCD时的画点,画线,画圈这样的函数上哪去了。。。直到了解了LCD控制器的原理,总算知道了为什么没了。原来给LCD控制器承包了!

一、LCD控制器介绍

在说Framebuffer之前,得先提一下LCD控制器。如下图:
在这里插入图片描述

  • LCD控制器的主要作用是承担GPIO与LCD显示器的数据交互,集成复杂硬件控制(像单片机驱动LCD需要复杂的寄存器设置等操作)
  • 反映到内核中,则是分配一个空间作为显存(一般为对应显示屏的一帧数据的大小),将首尾地址给到LCD控制器对应的寄存器,这时候它就会自动地从这块内存中读取数据,控制LCD显示出来,呈现到用户面前。

二、Framebuffer介绍:

  • 首先,上面说的LCD控制器完成了处理器与LCD之间的交互,只需要对一块内存空间写数据就能让lcd显示我们想要的东西

那么我们要怎么在应用编程中控制LCD呢?
这就是Framebuffer的作用了。

  • Framebuffer就是将上面的那块空间封装上read、write、open、mmap等函数,虚拟出一个fb设备,当我们编写好 LCD驱动以后会生成一个名为 /dev/fbX(X=0~n)的设备,应用程序通过访问 /dev/fbx这个设备就可以访问 LCD。

Framebuffer子系统的层次结构如下:
Framebuffer子系统的层次结构
在应用层中反映为/dev/fbx,保存着一帧图像,可以操作试试:

# dd if=/dev/zero of=/dev/fbx		// 清屏
# cat /dev/fbx > text				// 截屏(未编码)
# cat text > /dev/fbx 				// 显示text到屏幕上

从结构图中可以看到Framebuffer重要代码在fbmem.c和xxxfb.c;

  • fbmem.c 中的代码是与硬件无关中间层部分。
  • xxxfb.c 是真正的跟LCD控制器相关的驱动部分(driver),在s3c2440是用了s3c2440fb.c中的驱动,210系列是用了s5pv210fb.c的驱动,s5p6818使用的是nxp-fb.c(一般来说)。
  • device一般在arch/arm中相关代码中。
    相关结构体:
struct fb_info   *fb_info    描述了一个framebuffer device相关一系列信息
struct fb_ops   *fb_ops      描述了一个framebuffer device的操作函数集合,具体到对硬件的操作,比如清屏,画圆等
static const struct file_operations fb_fops   文件操作函数集合,当应用程序打开设备时,用户可以read,write,ioctl等
struct fb_var_screeninfo var      描述LCD硬件可变参数
struct fb_fix_screeninfo fix        描述LCD硬件不可变参数,如显存的首尾地址

1.fbmem.c

主要作用是

  1. 注册占用主设备号29,
  2. 获得info结构体,以调用info->fb_ops的lcd硬件操作函数。
  3. mmap将fb=>vma虚拟地址空间–进程空间。

首先看init函数中:

static int __init fbmem_init(void){
	...
	if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
	...
	fb_class = class_create(THIS_MODULE, "graphics");
	...
	return 0;
}

可以看到init中用了字符设备驱动模型:register_chrdev( 29 , ”fb” , &fb_fops ),创建并占用主设备号29。以fb_fops作为操作函数,主要作用是获取info结构体,它才保存了具体的lcd驱动函数。

static const struct file_operations fb_fops = {
	.read =		fb_read,
	.write =	fb_write,
	.unlocked_ioctl = fb_ioctl,
	.mmap =		fb_mmap,
	.open =		fb_open,
	.release =	fb_release,
};

很典型的一个字符设备驱动模型。应用层对设备文件打开读写调用对应函数。首先看看fb_open函数主要内容:

fb_open(struct inode *inode, struct file *file){
	int fbidx = iminor(inode); // 获取次设备号
	info = get_fb_info(fbidx);
// ----fb_info = registered_fb[idx];从队列中获取info
	file->private_data = info;//将info保存到file中,方便read等获取info  
	if (info->fbops->fb_open) {// 调用fbops的open函数
		res = info->fbops->fb_open(info,1);}

fb_mman主要内容:

fb_mmap(struct file *file, struct vm_area_struct * vma){
	struct fb_info *info = file_fb_info(file);	
		// open已经将info存到file中,所以现在从file中获取info
	...
    if (fb->fb_mmap) { // 调用fbops的mmap
res = fb->fb_mmap(info, vma);}
	/* 将获得的info结构体中的framebuffer空间赋给vma虚拟地址空间  */
	...
}

2.2.选择nxp-fb.c介绍 info定义处

同样首先看到init函数:

static int __init nxp_fb_init(void){
	return platform_driver_register(&fb_plat_driver);
}

这是一个典型的platform总线-设备-驱动模型,注册了一个platform驱动,驱动结构如下:

static struct platform_driver fb_plat_driver = {
	.probe		= nxp_fb_probe,
	...
	.driver		= { .name	= DEV_NAME_FB,},
};

platform总线特点是当有设备注册并且与驱动的“DEV_NAME_FB”相同时完成匹配,调用nxp_fb_probe函数,所以接下来看到这个函数:

static int nxp_fb_probe(struct platform_device *pdev)
{
	struct nxp_fb_plat_data *plat = pdev->dev.platform_data;
			/* 从设备结构体中获取硬件相关信息 */
	...
	/* 填充info结构体,操作函数fb_ops、以及各种硬件相关信息var-fix */ 
	...
	ret = register_framebuffer(info);
		// 最重要的工作 -- 申请framebuffer
}

这里申请framebuffer的函数中执行了:

device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);

在类中创建一个设备dev(29,i),并且在/dev/下创建了一个fbx供应用层操作。

以上,就是对于framebuffer子系统的解释;
后面再做一篇LCD驱动开发

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值