Linux LCD 驱动实验

LCD 是很常用的一个外设,在裸机篇中我们讲解了如何编写 LCD 裸机驱动,在 Linux 下LCD 的使用更加广泛,再搭配 QT 这样的 GUI 库下可以制作出非常精美的 UI 界面。本章我们就来学习一下如何在 Linux 下驱动 LCD 屏幕。

Framebuffer 设备

先来回顾一下裸机的时候 LCD 驱动是怎么编写的,裸机 LCD 驱动编写流程如下:

①、初始化 I.MX6U 的 eLCDIF 控制器,重点是 LCD 屏幕宽(width)、高(height)、hspw、hbp、hfp、vspw、vbp 和 vfp 等信息。

②、初始化 LCD 像素时钟。

③、设置 RGBLCD 显存。

④、应用程序直接通过操作显存来操作 LCD,实现在 LCD 上显示字符、图片等信息。

在 Linux 中应用程序最终也是通过操作 RGB 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 这样一个设备,如图 59.1.1.1 所示:

图 59.1.1.1 中的/dev/fb0 就是 LCD 对应的设备文件,/dev/fb0 是个字符设备,因此肯定有file_operations 操作集,fb 的 file_operations 操作集定义在 drivers/video/fbdev/core/fbmem.c 文件中,如下所示:

关于 fb 的详细处理过程就不去深究了,本章我们的重点是驱动起来 ALPHA 开发板上的LCD。

LCD 驱动简析

LCD 裸机例程主要分两部分:

①、获取 LCD 的屏幕参数。

②、根据屏幕参数信息来初始化 eLCDIF 接口控制器。

不同分辨率的 LCD 屏幕其 eLCDIF 控制器驱动代码都是一样的,只需要修改好对应的屏幕参数即可。屏幕参数信息属于屏幕设备信息内容,这些肯定是要放到设备树中的,因此我们本章实验的主要工作就是修改设备树,NXP 官方的设备树已经添加了 LCD 设备节点,只是此节点的 LCD 屏幕信息是针对 NXP 官方 EVK 开发板所使用的 4.3 寸 480*272 编写的,我们需要将其改为我们所使用的屏幕参数。

我们简单看一下 NXP 官方编写的 Linux 下的 LCD 驱动,打开 imx6ull.dtsi,然后找到 lcdif节点内容,如下所示:

示例代码 59.1.2.1 中的 lcdif 节点信息是所有使用 I.MX6ULL 芯片的板子所共有的,并不是完整的 lcdif 节点信息。像屏幕参数这些需要根据不同的硬件平台去添加,比如向 imx6ull-alientek-emmc.dts 中的 lcdif 节点添加其他的属性信息。从示例代码 59.1.2.1 可以看出 lcdif 节点的 compatible 属性值为“fsl,imx6ul-lcdif”和“fsl,imx28-lcdif”,因此在 Linux 源码中搜索这两个字符串即可找到 I.MX6ULL 的 LCD 驱动文件,这个文件为drivers/video/fbdev/mxsfb.c,mxsfb.c就是 I.MX6ULL 的 LCD 驱动文件,在此文件中找到如下内容:

从示例代码 59.1.2.2 可以看出,这是一个标准的 platform 驱动,当驱动和设备匹配以后mxsfb_probe 函数就会执行。在看 mxsfb_probe 函数之前我们先简单了解一下 Linux 下Framebuffer 驱动的编写流程,Linux 内核将所有的 Framebuffer 抽象为一个叫做 fb_info 的结构体,fb_info 结构体包含了 Framebuffer 设备的完整属性和操作集合,因此每一个 Framebuffer 设备都必须有一个 fb_info。换言之就是,LCD 的驱动就是构建 fb_info,并且向系统注册 fb_info的过程。fb_info 结构体定义在 include/linux/fb.h 文件里面,内容如下(省略掉条件编译):

fb_info 结构体的成员变量很多,我们重点关注 var、fix、fbops、screen_base、screen_size和 pseudo_palette。mxsfb_probe 函数的主要工作内容为:

①、申请 fb_info。

②、初始化 fb_info 结构体中的各个成员变量。

③、初始化 eLCDIF 控制器。

④、使用 register_framebuffer 函数向 Linux 内核注册初始化好的 fb_info。register_framebuffer函数原型如下:

int register_framebuffer(struct fb_info *fb_info)

函数参数和返回值含义如下:

fb_info:需要上报的 fb_info。

返回值:0,成功;负值,失败。

接下来我们简单看一下 mxsfb_probe 函数,函数内容如下(有缩减):

第 1374 行,host 结构体指针变量,表示 I.MX6ULL 的 LCD 的主控接口,mxsfb_info 结构体是 NXP 定义的针对 I.MX 系列 SOC 的 Framebuffer 设备结构体。也就是我们前面一直说的设备结构体,此结构体包含了 I.MX 系列 SOC 的 Framebuffer 设备详细信息,比如时钟、eLCDIF控制器寄存器基地址、fb_info 等。

第 1395 行,从设备树中获取 eLCDIF 接口控制器的寄存器首地址,设备树中 lcdif 节点已经设置了 eLCDIF 寄存器首地址为 0X021C8000,因此 res=0X021C8000。

第 1401 行,给 host 申请内存,host 为 mxsfb_info 类型结构体指针。

第 1407 行,给 fb_info 申请内存,也就是申请 fb_info。

第 1413~1414 行,设置 host 的 fb_info 成员变量为 fb_info,设置 fb_info 的 par 成员变量为host。通过这一步就将前面申请的 host 和 fb_info 联系在了一起。

第 1416 行,申请中断,中断服务函数为 mxsfb_irq_handler。

第 1425 行,对从设备树中获取到的寄存器首地址(res)进行内存映射,得到虚拟地址,并保存到 host 的 base 成员变量。因此通过访问 host 的 base 成员即可访问 I.MX6ULL 的整个 eLCDIF寄存器。其实在 mxsfb.c 中已经定义了 eLCDIF 各个寄存器相比于基地址的偏移值,如下所示:

大家可以对比着《I.MX6ULL 参考手册》中的 eLCDIF 章节检查一下示例代码 59.1.2.4 中的这些寄存器有没有错误。

继续回到示例代码59.1.2.5 中的 mxsfb_probe 函数,第1462 行,给 fb_info中的 pseudo_palette申请内存。

第 1473 行,调用 mxsfb_init_fbinfo 函数初始化 fb_info,重点是 fb_info 的 var、fix、fbops,screen_base 和 screen_size。其中 fbops 是 Framebuffer 设备的操作集,NXP 提供的 fbops 为mxsfb_ops,内容如下:

关于 mxsfb_ops 里面的各个操作函数这里就不去详解的介绍了。mxsfb_init_fbinfo 函数通过调用 mxsfb_init_fbinfo_dt 函数从设备树中获取到 LCD 的各个参数信息。最后,mxsfb_init_fbinfo函数会调用 mxsfb_map_videomem 函数申请 LCD 的帧缓冲内存(也就是显存)。

第 1489~1490 行,设置 eLCDIF 控制器的相应寄存器。

第 1494 行,最后调用 register_framebuffer 函数向 Linux 内核注册 fb_info。

mxsfb.c 文件很大,还有一些其他的重要函数,比如 mxsfb_remove、mxsfb_shutdown 等,这里我们就简单的介绍了一下 mxsfb_probe 函数,至于其他的函数大家自行查阅。

LCD 驱动程序编写

前面已经说了,6ULL 的 eLCDIF 接口驱动程序 NXP 已经编写好了,因此 LCD 驱动部分我们不需要去修改。我们需要做的就是按照所使用的 LCD 来修改设备树。重点要注意三个地方:

①、LCD 所使用的 IO 配置。

②、LCD 屏幕节点修改,修改相应的属性值,换成我们所使用的 LCD 屏幕参数。

③、LCD 背光节点信息修改,要根据实际所使用的背光 IO 来修改相应的设备节点信息。

接下来我们依次来看一下上面这两个节点改如何去修改:

1、LCD 屏幕 IO 配置

首先要检查一下设备树中 LCD 所使用的 IO 配置,这个其实 NXP 都已经给我们写好了,不需要修改,不过我们还是要看一下。打开 imx6ull-alientek-emmc.dts 文件,在 iomuxc 节点中找到如下内容:

第 2~27 行,子节点 pinctrl_lcdif_dat,为 RGB LCD 的 24 根数据线配置项。

第 30~36 行,子节点 pinctrl_lcdif_ctrl,RGB LCD 的 4 根控制线配置项,包括 CLK、ENABLE、VSYNC 和 HSYNC。

第 37~40 行,子节点 pinctrl_pwm1,LCD 背光 PWM 引脚配置项。这个引脚要根据实际情况设置,这里我们建议大家在以后的学习或工作中,LCD 的背光 IO 尽量和半导体厂商的官方开发板一致。

注意示例代码 59.3.1 中默认将 LCD 的电气属性都设置为 0X79,这里将其都改为 0X49,也就是将 LCD 相关 IO 的驱动能力改为 R0/1,也就是降低 LCD 相关 IO 的驱动能力。因为前面已经说了,正点原子的 ALPHA 开发板上的 LCD 接口用了三个 SGM3157 模拟开关,为了防止模拟开关影响到网络,因此这里需要降低 LCD 数据线的驱动能力,如果你所使用的板子没有用到模拟开关那么就不需要将 0X79 改为 0X49。

2、LCD 屏幕参数节点信息修改

继续在 imx6ull-alientek-emmc.dts 文件中找到 lcdif 节点,节点内容如下所示:

示例代码 59.3.2 就是向 imx6ull.dtsi 文件中的 lcdif 节点追加的内容,我们依次来看一下示例代码 59.3.2 中的这些属性都是些什么含义。

第 3 行,pinctrl-0 属性,LCD 所使用的 IO 信息,这里用到了 pinctrl_lcdif_dat、pinctrl_lcdif_ctrl和 pinctrl_lcdif_reset 这三个 IO 相关的节点,前两个在示例代码 59.3.1 中已经讲解了。pinctrl_lcdif_reset 是 LCD 复位 IO 信息节点,正点原子的 I.MX6U-ALPHA 开发板的 LCD 没有用到复位 IO,因此 pinctrl_lcdif_reset 可以删除掉。

第 6 行,display 属性,指定 LCD 属性信息所在的子节点,这里为 display0,下面就是 display0子节点内容。

第 9~32 行,display0 子节点,描述 LCD 的参数信息,第 10 行的 bits-per-pixel 属性用于指明一个像素占用的 bit 数,默认为 16bit。本教程我们将 LCD 配置为 RGB888 模式,因此一个像素点占用 24bit,bits-per-pixel 属性要改为 24。第 11 行的 bus-width 属性用于设置数据线宽度,因为要配置为 RGB888 模式,因此 bus-width 也要设置为 24。

第 13~30 行,这几行非常重要!因为这几行设置了 LCD 的时序参数信息,NXP 官方的 EVK开发板使用了一个 4.3 寸的 480*272 屏幕,因此这里默认是按照 NXP 官方的那个屏幕参数设置的。每一个属性的含义后面的注释已经写的很详细了,大家自己去看就行了,这些时序参数就是我们重点要修改的,需要根据自己所使用的屏幕去修改。

这里以正点原子的 ATK7016(7 寸 1024*600)屏幕为例,将 imx6ull-alientek-emmc.dts 文件中的 lcdif 节点改为如下内容:

第 3 行,设置 LCD 屏幕所使用的 IO,删除掉原来的 pinctrl_lcdif_reset,因为没有用到屏幕复位 IO,其他的 IO 不变。

第 9 行,使用 RGB888 模式,所以一个像素点是 24bit。

第 15~23 行,ATK7016 屏幕时序参数,根据自己所使用的屏幕修改即可。

3、LCD 屏幕背光节点信息

正点原子的 LCD 接口背光控制 IO 连接到了 I.MX6U 的 GPIO1_IO08 引脚上,GPIO1_IO08复用为 PWM1_OUT,通过 PWM 信号来控制 LCD 屏幕背光的亮度,这个我们已经在第二十九章详细的讲解过了。正点原子 I.MX6U-ALPHA 开发板的 LCD 背光引脚和 NXP 官方 EVK 开发板的背光引脚一样,因此背光的设备树节点是不需要修改的,但是考虑到其他同学可能使用别的开发板或者屏幕,LCD 背光引脚和 NXP 官方 EVK 开发板可能不同,因此我们还是来看一下如何在设备树中添加背光节点信息。

首先是 GPIO1_IO08 这个 IO 的配置,在 imx6ull-alientek-emmc.dts 中找到如下内容:

pinctrl_pwm1 节点就是 GPIO1_IO08 的配置节点,从第 3 行可以看出,设置 GPIO1_IO08这个 IO 复用为 PWM1_OUT,并且设置电气属性值为 0x110b0。

LCD 背光要用到 PWM1,因此也要设置 PWM1 节点,在 imx6ull.dtsi 文件中找到如下内容:

imx6ull.dtsi 文件中的 pwm1 节点信息大家不要修改,如果要修改 pwm1 节点内容的话请在imx6ull-alientek-emmc.dts 文件中修改。在整个 Linux 源码文件中搜索 compatible 属性的这两个值即可找到 imx6ull 的 pwm 驱动文件,imx6ull 的 PWM 驱动文件为 drivers/pwm/pwm-imx.c,这里我们就不详细的去分析这个文件了。继续在 imx6ull-alientek-emmc.dts 文件中找到向 pwm1追加的内容,如下所示:

第 3 行,设置 pwm1 所使用的 IO 为 pinctrl_pwm1,也就是示例代码 59.3.4 所定义的GPIO1_IO08 这个 IO。

第 4 行,将 status 设置为 okay。

如果背光用的其他 pwm 通道,比如 pwm2,那么就需要仿照示例代码 59.3.6 的内容,向pwm2 节点追加相应的内容。pwm 和相关的 IO 已经准备好了,但是 Linux 系统怎么知道PWM1_OUT 就是控制 LCD背光的呢?因此我们还需要一个节点来将 LCD 背光和 PWM1_OUT连接起来。这个节点就是 backlight , backlight节点描述可以参考Documentation/devicetree/indings/video/backlight/pwm-backlight.txt 这个文档,此文档详细讲解了backlight 节点该如何去创建,这里大概总结一下:

①、节点名称要为“backlight”。

②、节点的 compatible 属性值要为“pwm-backlight”,因此可以通过在 Linux 内核中搜索“ pwm-backlight ” 来 查 找 PWM 背 光 控 制 驱 动 程 序 , 这 个 驱 动 程 序 文 件 为drivers/video/backlight/pwm_bl.c,感兴趣的可以去看一下这个驱动程序。

③、pwms属性用于描述背光所使用的PWM以及PWM频率,比如本章我们要使用的pwm1,pwm 频率设置为 200Hz(NXP 官方推荐设置)。

④、brightness-levels 属性描述亮度级别,范围为 0~255,0 表示 PWM 占空比为 0%,也就是亮度最低,255 表示 100%占空比,也就是亮度最高。至于设置几级亮度,大家可以自行填写此属性。

⑤、default-brightness-level 属性为默认亮度级别。

根据上述 5 点设置 backlight 节点,这个 NXP 已经给我们设置好了,大家在 imx6ull-alientek-emmc.dts 文件中找到如下内容:

第 3 行,设置背光使用 pwm1,PWM 频率为 200Hz。

第 4 行,设置背 8 级背光(0~7),分别为 0、4、8、16、32、64、128、255,对应占空比为0%、1.57%、3.13%、6.27%、12.55%、25.1%、50.19%、100%,如果嫌少的话可以自行添加一些其他的背光等级值。

第 5 行,设置默认背光等级为 6,也就是 50.19%的亮度。

关于背光的设备树节点信息就讲到这里,整个的 LCD 设备树节点内容我们就讲完了,按照这些节点内容配置自己的开发板即可。

更多待补充。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频的编解码格式

文章目录 视频的编解码格式概念术语视频处理流程视频封装格式视频编码格式视频编解码器,视频容器和视频文件格式之间的区别补充视频码率 参考资料 视频的编解码格式 概念术语 两大组织主导视频压缩的组织及其联合(joint)组织 ITU-T(VCEG) ITU-T的中文名称是国际电信…

论文翻译 | A Prompt Pattern Catalog to Enhance Prompt Engineering with ChatGPT (下)

I.事实核查表模式 1)意图和上下文:此模式的目的是确保LLM输出一个事实列表,这些事实存在于输出中,并构成输出中语句的重要组成部分。此事实列表有助于告知用户输出所基于的事实(或假设)。然后,用户可以对这…

python将照片集导出成视频

shigen坚持更新文章的博客写手,记录成长,分享认知,留住感动。个人IP:shigen 背景 一个安静的下午,看着电脑里乱七八糟的照片,有大有小,宽高不一,突然想找个方式把他们统一起来&…

求最大公约数(c语言)

先看题👇 我这里介绍的方法:辗转相除法: 最大公约数: 最大公约数是指同时能整除俩个或更多整数的最大正整数。 欧几里得算法就是求最大公约数的算法 求最大公约数涉及到一个数学原理的转换: 俩个数的最大公约数等于其中一个数和…

使用scss生成旋转圆圈

图片 html代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title>…

Windows电脑桌面如何弄个好用的提醒备忘录?

在这个充满挑战的时代&#xff0c;每个人都渴望成为更好的自己。然而&#xff0c;随着生活节奏的加快&#xff0c;我们时常发现自己陷入了各种琐事之中&#xff0c;难以脱身。为了不让重要的事情被遗漏&#xff0c;一款好的提醒备忘录工具就显得尤为关键。那么&#xff0c;Wind…

白嫖正版xshell和XFTP

在哪里可以下载正版免费的xshell和XFTP&#xff0c;并且还能够获得官网免费持久更新 白嫖步骤 首先直接在浏览器搜索xshell官网 点进官网之后直接点击下载 接着点击免费授权页面 进入之后就可以免费下载了 下载安装完成后填写用户名和邮箱并提交&#xff0c;这里就以xshell为…

第6篇:无线与移动网络

目录 引言 6.1 无线网络的基础概念 6.2 无线局域网&#xff08;WLAN&#xff09;与IEEE 802.11 6.3 蓝牙与无线个域网&#xff08;WPAN&#xff09; 6.4 无线城域网&#xff08;WMAN&#xff09;与WiMax 6.5 ZigBee与智能家居 6.6 移动蜂窝网络&#xff08;3G/4G/5G&…

【str_replace替换导致的绕过】

双写绕过 随便输入一个 usernameadmin&passwords 没有回显测试注入点 usernameadmin or 11%23&passwords 回显hello admin测试列数 usernameadmin order by 3%23&passwords测试回显位 usernameadmi union select 1,2,3%23&passwords 没有显示数据&#xff0c;推…

如何保证数据库和缓存双写一致性?

1. 如何保证数据库和缓存双写一致性&#xff1f; 在高并发情况下&#xff0c;如果有大量的请求直接访问到数据库&#xff0c;由于数据库是将数据存储到磁盘当中的&#xff0c;每次访问时需要将数据以页的形式读取到内存当中&#xff0c;并且建立数据库连接、查询数据库中的数据…

个人健康系统|个人健康数据管理系统|基于小程序+java的个人健康数据管理系统设计与实现(源码+数据库+文档)

个人健康数据管理系统 目录 基于小程序java的个人健康数据管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师…

Python基础08

目录 1.Object-Oriented Programming 2.类 2.1类的定义 2.2实例化对象(构造函数) 2.3self 2.4cls 2.5实例变量(也叫属性) 2.6类属性 2.5初始化方法 2.7类方法 2.8静态方法 3.继承 3.1单继承 3.2多继承 3.3覆盖(Override) 1.Object-Oriented Programming 一切皆…

RabbitMQ service is already present - only updating service parameters

Windows下卸载RabbitMQ之后,然后重新注册RabbitMQ服务的时候,报错以下信息: D:\software\rabbitmq-server-4.0.2\rabbitmq_server-4.0.2\sbin>D:\software\rabbitmq-server-4.0.2\rabbitmq_server-4.0.2\sbin\rabbitmq-service.bat install RabbitMQ service is already …

动态规划-子数组系列——乘积最大子数组

1.题目解析 题目来源&#xff1a;152.乘积最大子数组——力扣 测试用例 2.算法原理 1.状态表示 由于题目给的数组中可以包含负数&#xff0c;因此求最大乘积有两种情况&#xff1a; a.负数乘以最小数得出最大乘积 b.整数乘以最大数得出最大乘积 所以需要两个表分别求出最大最…

MySQL 数据库迁移至达梦 DM8 常见问题

目录 如何让迁移到 DM 的表名大小写和 MySQL 保持一致 MySQL 迁移到 DM 报错&#xff1a;列[NAMES]长度超出定义 MySQL 迁移到 DM 报错&#xff1a;记录超长 索引错误 DM大小写敏感配置 表空间 新建用户 用户与模式的关系 省略模式名的优势 实际操作 如何让迁移到 DM…

【网络原理】——拥塞控制,延时/捎带应答,面向字节流,异常情况

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 一&#xff1a;拥塞控制&#xff08;重点&#xff09; 1&#xff1a;情境引入 2&#xff1a;解决方案…

【Docker】安装部署项目流程(Pycharm版)

安装部署步骤 1.准备项目 第一步要准备好你所需要部署的项目&#xff0c;确保在工作目录下所以程序.py文件正常调用并能正确运行 如上&#xff0c;main要在工作目录中能跑通&#xff0c;这里有一点需要注意 在IDE src不要标记为源代码根目录&#xff0c;观察一下是否能跑通代…

【计算机网络 - 基础问题】每日 3 题(五十)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

Java最全面试题->Java基础面试题->JavaSE面试题->面向对象面试题

面向对象 下边是我自己整理的面试题&#xff0c;基本已经很全面了&#xff0c;想要的可以私信我&#xff0c;我会不定期去更新思维导图 哪里不会点哪里 1.面向对象和面向过程的区别 面向对象&#xff1a; 优点&#xff1a;易维护&#xff0c;复用&#xff0c;扩展。面向对象…

解决DOTA-v2.0数据集上传结果至官网BUG: No space left on device

时间&#xff1a;2024.10.20 一、DOTA-v2.0数据集上传结果至官网BUG&#xff1a; No space left on device IOError at /evaluation1/ [Errno 28] No space left on device二、解决方法&#xff0c;法一 上传的结果文件太大了&#xff0c;把服务器磁盘占满了。 将结果中精度…