十七、(正点原子)Linux LCD驱动

一、Framebuffer设备

        在 Linux 中应用程序通过操作 RGB LCD 的显存来实现在 LCD 上显示字符、图片等信息。

        先来看一下裸机 LCD 驱动如下:
        ①、初始化 I.MX6U 的 eLCDIF 控制器,重点是 LCD 屏幕宽(width)、高(height)、 hspw、
hbp、 hfp、 vspw、 vbp 和 vfp 等信息。
        ②、初始化 LCD 像素时钟。
        ③、设置 RGBLCD 显存。
        ④、应用程序直接通过操作显存来操作 LCD,实现在 LCD 上显示字符、图片等信息。

         在裸机中我们可以随意的分配显存,但是在 Linux 系统中内存的管理很严格,显存是需要申请的,不是你想用就能用的。而且因为虚拟内存的存在,驱动程序设置的显存和应用程序访问的显存要是同一片物理内存。

        为了解决上述问题, Framebuffer 诞生了, Framebuffer 翻译过来就是帧缓冲,简称 fb,因此大家在以后的 Linux 学习中见到“Framebuffer”或者“fb”的话第一反应应该想到 RGBLCD或者显示设备。 fb 是一种机制,将系统中所有跟显示有关的硬件以及软件集合起来,虚拟出一个 fb 设备,当我们编写好 LCD 驱动以后会生成一个名为/dev/fbX(X=0~n)的设备,应用程序通过访问/dev/fbX 这个设备就可以访问 LCD。
        NXP 官方的 Linux 内核默认已经开启了 LCD 驱动,因此我们是可以看到/dev/fb0 这样一个设备,如图所示:

        图中的/dev/fb0 就是 LCD 对应的设备文件, /dev/fb0 是个字符设备,因此肯定有file_operations 操作集, fb 的 file_operations 操作集,如下所示:

定义在 drivers/video/fbdev/core/fbmem.c 文件中

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,

#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
	.get_unmapped_area = get_fb_unmapped_area,
#endif

#ifdef CONFIG_FB_DEFERRED_IO
	.fsync =	fb_deferred_io_fsync,
#endif

	.llseek =	default_llseek,
};

         Linux 内核将所有的 Framebuffer 抽象为一个叫做 fb_info 的结构体, fb_info 结构体包含了 Framebuffer 设备的完整属性和操作集合,因此每一个 Framebuffer 设备都必须有一个 fb_info。换言之就是, LCD 的驱动就是构建 fb_info,并且向系统注册 fb_info的过程。

定义在 include/linux/fb.h 文件里
struct fb_info {
	atomic_t count;
	int node;
	int flags;
	struct mutex lock;		        /* 互斥锁 */
	struct mutex mm_lock;		    /* 互斥锁,用于 fb_mmap 和 smem_*域*/
	struct fb_var_screeninfo var;	/* 当前可变参数 */
	struct fb_fix_screeninfo fix;	/* 当前固定参数 */
	struct fb_monspecs monspecs;	/* 当前显示器特性 */
	struct work_struct queue;	    /* 帧缓冲事件队列 */
	struct fb_pixmap pixmap;	    /* 图像硬件映射 */
	struct fb_pixmap sprite;	    /* 光标硬件映射 */
	struct fb_cmap cmap;		    /* 当前调色板 */
	struct list_head modelist;     /* 当前模式列表 */
	struct fb_videomode *mode;	    /* 当前视频模式 */

#ifdef CONFIG_FB_BACKLIGHT        /* 如果 LCD 支持背光的话 */
	/* assigned backlight device */
	/* set before framebuffer registration, 
	   remove after unregister */
	struct backlight_device *bl_dev;    /* 背光设备 */

	/* Backlight level curve */
	struct mutex bl_curve_mutex;	
	u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
	struct delayed_work deferred_work;
	struct fb_deferred_io *fbdefio;
#endif

	struct fb_ops *fbops;       /* 帧缓冲操作函数集 */
	struct device *device;		/* 父设备 */
	struct device *dev;		    /* 当前 fb 设备 */
	int class_flag;             * 私有 sysfs 标志 */
	struct fb_tile_ops *tileops;    /* Tile Blitting */
#endif
	char __iomem *screen_base;	/* 虚拟内存基地址(屏幕显存) */
	unsigned long screen_size;	/* 虚拟内存大小(屏幕显存大小) */ 
	void *pseudo_palette;		/* 伪 16 位调色板 */ 
#define FBINFO_STATE_RUNNING	0
#define FBINFO_STATE_SUSPENDED	1
	u32 state;			/* Hardware state i.e suspend */
	void *fbcon_par;                /* fbcon use-only private area */
	/* From here on everything is device dependent */
	void *par;
	/* we need the PCI or similar aperture base/size not
	   smem_start/size as smem_start may just be an object
	   allocated inside the aperture so may not actually overlap */
	struct apertures_struct {
		unsigned int count;
		struct aperture {
			resource_size_t base;
			resource_size_t size;
		} ranges[0];
	} *apertures;

	bool skip_vt_switch; /* no VT switch on suspend/resume required */
};

        fb_info 结构体的成员变量很多,我们重点关注 var、 fix、 fbops、 screen_base、screen_size和 pseudo_palette。

        fb_info结构体创建好初始化完成之后,使用register_framebuffer 函数向 Linux 内核注册初始化好的 fb_info。函数原型:

定义在 drivers/video/fbdev/mxsfb.c 种

int register_framebuffer(struct fb_info *fb_info)

        fb_info:需要注册的 fb_info。
        返回值: 0,成功;负值,失败。
       

        卸载 f

### 正点原子 Linux LCD 驱动移植教程及相关示例 在嵌入式开发中,LCD驱动的移植是一个常见的需求。对于正点原子系列开发板,在Linux环境下的LCD驱动移植可以参考官方文档或其他类似的开源项目实现。 #### 1. 使用 RGB LCD 屏幕的驱动文件 针对使用RGB LCD屏幕的情况,通常会涉及`drivers/gpu/drm/panel/panel-simple.c`这个驱动文件[^1]。该文件定义了一个简单的面板控制器接口,适用于多种类型的显示屏。以下是部分代码片段: ```c static const struct drm_display_mode default_640x480 = { .hdisplay = 640, .hsync_start = 640 + 16, .hsync_end = 640 + 16 + 96, .htotal = 640 + 16 + 96 + 32, .vdisplay = 480, .vsync_start = 480 + 10, .vsync_end = 480 + 10 + 2, .vtotal = 480 + 10 + 2 + 33, .clock = 25175, }; static int panel_simple_probe(struct device *dev, struct panel_desc *desc) { ... } ``` 上述代码展示了如何通过DRM框架配置显示模式,并初始化相应的硬件资源。 #### 2. 设备树支持与早期 ARM 架构差异 在较新的Linux内核版本中,ARM架构普遍采用了设备树(Device Tree)来描述硬件信息。而在3.x之前的版本,则依赖于`arch/arm/mach-xxx`和`arch/arm/plat-xxx`目录中的硬编码方式完成板级信息的描述[^2]。如果目标平台不支持设备树或者需要兼容旧版内核,可能还需要手动修改对应的`.c`文件以适配具体的硬件特性。 例如,SMDK2440 的板级初始化代码位于 `mach-smdk2440.c` 中,其中包含了 GPIO 设置、时钟管理等内容。这部分内容可以根据实际使用的芯片手册调整参数值。 #### 3. 跨平台工具链准备 为了顺利完成 FreeType 字体库以及其他图形处理组件 (如 libpng 和 libjpeg) 的构建工作,建议先准备好适合目标处理器架构的交叉编译器环境[^3]。假设已经安装好 Ubuntu 系统并具备必要的软件包,则可以通过以下命令克隆源码并执行编译操作: ```bash tar -zxvf freetype-2.8.tar.gz cd freetype-2.8/ ./configure --host=arm-linux-gnueabihf CC=/path/to/cross_compiler_prefix-arm-linux-gcc CXX=/path/to/cross_compiler_prefix-arm-linux-g++ make && make install ``` 这里需要注意替换掉 `/path/to/cross_compiler_prefix-*` 成真实的路径名。 #### 4. 参考作者及其贡献领域 最后值得一提的是,某些知名技术博主分享了许多有关嵌入式的实战经验和技术文章,像鱼弦先生就活跃于多个开发者社区之中,其作品覆盖范围广泛,从零基础入门指导直至高级优化技巧均有涉猎[^4]。读者可关注他的个人主页获取更多实用资讯。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tofu_Cabbage

你的打赏是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值