16_LinuxLCD驱动

目录

Framebuffer设备

LCD驱动简析

LCD驱动程序编写

LCD屏幕参数节点信息修改

LCD 屏幕背光节点信息

使能Linux logo显示

设置LCD作为终端控制台


Framebuffer设备

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

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

2.初始化LCD像素时钟。

3.设置RGBLCD显存。

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

在Linux中应用程序最终也是通过操作RGB LCD的显存来实现在LCD上显示字符、图片等信息。在裸机中我们可以随意的分配显存,但是在Linux系统中内存的管理很严格,显存是需要申请的,不是你想用就能用的。而且因为虚拟内存的存在,驱动程序设置的显存和应用程序访问的显存要是同一片物理内存。

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

 图中的/dev/fb0就是LCD对应的设备文件,/dev/fb0是个字符设备,因此肯定有

file-operations操作集,fb的fileoperations操作集定义在drivers/video/fbdev/core/fbmem.c文件中,如下所示:

 

LCD驱动简析

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

1.获取LCD的屏幕参数。

2.根据屏幕参数信息来初始化eLCDIF接口控制器。不同分辨率的LCD屏幕其eLCDIF控制器驱动代码都是一样的,只需要修改好对应的屏幕参数即可。屏幕参数信息属于屏幕设备信息内容,这些肯定是要放到设备树中的,因此本实验的主要工作就是修改设备树,NXP官方的设备树已经添加了LCD设备节点,只是此节点的LCD屏幕信息是针对NXP官方EVK开发板所使用的4.3寸480*272编写的,需要将其改为我们所使用的屏幕参数。简单看一下NXP 官方编写的Linux下的LCD驱动,打开imx6ull.dtsi,然后找到Icdif节点内容,如下所示:

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

从示例代码可以看出,这是一个标准的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函数的主要工作内容为:

1.申请fb_info。

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

3.初始化eLCDIF控制器。

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

 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接口控制器的寄存器首地址,设备树中Icdif节点已经设置了eLCDIF寄存器首地址为0X021C8000,因此res=0X021C8000。

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

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

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

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

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

 继续回到示例代码中的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驱动程序编写

需要做的就是按照所使用的LCD来修改设备树。重点要注意三个地方:

1.LCD 所使用的 IO 配置。

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

3.LCD 背光节点信息修改,要根据实际所使用的背光IO来修改相应的设备节点信息。接下来依次来看一下上面这两个节点改如何去修改:

LCD屏幕IO配置

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

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

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

第37~40行,子节点pinctrl_pwml,LCD背光PWM引脚配置项。这个引脚要根据实际情况设置,这里建议大家在以后的学习或工作中,LCD的背光IO尽量和半导体厂商的官方开发板一致。注意示例代码中默认将LCD的电气属性都设置为 0X79,这里将其都改为0X49,也就是将LCD相关IO的驱动能力改为R0/1,也就是降低 LCD相关IO的驱动能力。因为前面已经说了,正点原子的ALPHA开发板上的LCD接口用了三个SGM3157模拟开关,为了防止模拟开关影响到网络,因此这里需要降低LCD数据线的驱动能力,如果你所使用的板子没有用到模拟开关那么就不需要将0X79改为0X49。

LCD屏幕参数节点信息修改

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

 第3行,pinctrl-0属性,LCD所使用的IO信息,这里用到了pinctrl_ledif_dat、pinctrl_ledif_ctrl和pinctrl_ledif_reset这三个IO相关的节点,前两个在示例代码中已经讲解了。pinctrl_lcdif_reset是LCD复位IO信息节点,正点原子的I.MX6U-ALPHA开发板的LCD 没有用到复位IO,因此pinctrl_ledif_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文件中的ledif节点改为如下内容:

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

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

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

LCD 屏幕背光节点信息

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

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

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

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

 imx6ull.dtsi文件中的pwml节点信息大家不要修改,如果要修改pwm1节点内容的话请在imx6ull-alientek-emmc.dts文件中修改。在整个Linux源码文件中搜索compatible属性的这两个值即可找到imx6ull的pwm 驱动文件,imx6ull的PWM驱动文件为

drivers/pwm/pwm-imx.c,这里我们就不详细的去分析这个文件了。

继续在imx6ull-alientek-emme.dts文件中找到向pwm1追加的内容,如下所示:

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

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

1.节点名称要为“backlight”。

2.节点的compatible属性值要为"pwm-backlight”,因此可以通过在Linux内核中搜索“pwm-backlight”来查找PWM背光控制驱动程序,这个驱动程序文件为

drivers/video/backlight/pwm_bl.c,感兴趣的可以去看一下这个驱动程序。

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

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

5.default-brightness-level 属性为默认亮度级别。

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

 第3行,设置背光使用pwml, 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%的亮度。

使能Linux logo显示

Linux内核启动的时候可以选择显示小企鹅 logo,只要这个小企鹅logo显示没问题那么我们的LCD驱动基本就工作正常了。这个logo显示是要配置的,不过Linux内核一般都会默认开启logo显示,但是奔着学习的目的,我们还是来看一下如何使能Linuxlogo显示。打开Linux内核图形化配置界面,按下路径找到对应的配置项:

图中这三个选项分别对应黑白、16位、24位色彩格式的logo,把这三个都选中,都编译进Linux内核里面。设置好以后保存退出,重新编译Linux内核,编译完成以后使用新编译出来的imx6ull-alientek-emmc.dtb和zImage镜像启动系统,如果LCD驱动工作正常的话就会在LCD屏幕左上角出现一个彩色的小企鹅logo,屏幕背景色为黑色,如图所示:

 

设置LCD作为终端控制台

一直使用SecureCRT作为Linux开发板终端,开发板通过串口和SecureCRT进行通信。现在已经驱动起来LCD了,所以可以设置LCD作为终端,也就是开发板使用自己的显示设备作为自己的终端,然后接上键盘就可以直接在开发板上敲命令了,将LCD设置为终端控制台的方法如下:

设置uboot中的bootargs

重启开发板,进入Linux命令行,重新设bootargs参数的console内容,命令如下所示:

注意红色字体部分设置console,这里我们设置了两遍console,第一次设置console-tty1,也就是设置LCD屏幕为控制台,第二遍又设置console=ttymxc0,115200,也就是设置串口也作为控制台。相当于我们打开了两个console,一个是 LCD,一个是串口,重启开发板就会发现LCD 和串口都会显示Linux启动log信息。但是此时我们还不能使用LCD作为终端进行交互,因为的设置还未完成。

修改/etc/inittab文件

打开开发板根文件系统中的/etc/inittab文件,在里面加入下面这一行:

 添加完成以后的/etc/inittab 文件内容如图所示:

 修改完成以后保存/etc/inittab并退出,然后重启开发板,重启以后开发板LCD屏幕最后一行会显示下面一行语句:

至此,拥有了两套终端,一个是基于串口的SecureCRT,一个就是我们开发板的LCD屏幕,但是为了方便调试

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jenkins发送的邮箱中没有带配置的压缩附件

【问题描述】:Jenkins中明明配置了邮箱发送时要带压缩附件,收到的邮箱中却没有附件内容 【问题定位】:压缩附件没有放在Jenkins工作空间下,所以发送的邮件并未发送附件 【解决办法】: 1)把压缩附件放到J…

kubernetes持久化存储卷

kubernetes持久化存储卷 kubernetes持久化存储卷一、存储卷介绍二、存储卷的分类三、存储卷的选择四、本地存储卷之emptyDir五、本地存储卷之 hostPath六、网络存储卷之nfs七、PV(持久存储卷)与PVC(持久存储卷声明)7.1 认识pv与pvc7.2 pv与pvc之间的关系7.3 实现nfs类型pv与pvc…

Spring MVC拦截器和跨域请求

一、拦截器简介 SpringMVC的拦截器(Interceptor)也是AOP思想的一种实现方式。它与Servlet的过滤器(Filter)功能类似,主要用于拦截用户的请求并做相应的处理,通常应用在权限验证、记录请求信息的日志、判断用…

EfficientNetV2: Smaller Models and Faster Training

EfficientNetV2: Smaller Models and Faster Training 1.Abstract 本文提出了一种训练速度快、参数量少、模型小的卷积神经网络EfficientNetV2。 训练采用了NAS感知技术与缩放技术对训练速度与参数数量进行联合优化。 NAS感知技术: 全名是神经架构搜索&#xff0…

quartus工具篇——ROM ip核

quartus工具篇——ROM ip核 1、ROM简介 FPGA中的ROM(Read-Only Memory)是一种只读存储器,主要用来存储固化的初始化配置数据。FPGA ROM的特性主要有: 预编程初始化 - ROM在FPGA编程时就已经写入了初始值,这些值在整个工作周期保持不变。初始化配置 - ROM通常用来存储FPGA的初…

Flutter的开发环境搭建-图解

前言:Flutter作为一个移动应用开发框架,具有许多优点和一些局限性。最大的优点就是-跨平台开发:Flutter可以在iOS和Android等多个平台上进行跨平台开发,使用一套代码编写应用程序,节省开发时间和成本。 Flutter可以编…

JVM运行时数据区——方法区、堆、栈的关系

方法区存储加载的字节码文件内的相关信息和运行时常量池,方法区可以看作是独立于Java堆的内存空间,方法区是在JVM启动时创建的,其内存的大小可以调整,是线程共享的,并且也会出现内存溢出的情况,也可存在垃圾…

2023JAVA 架构师面试 130 题含答案:JVM+spring+ 分布式 + 并发编程》...

此文包含 Java 面试的各个方面,史上最全,苦心整理最全 Java 面试题目整理包括基JVM算法数据库优化算法数据结构分布式并发编程缓存等,使用层面广,知识量大,涉及你的知识盲点。要想在面试者中出类拔萃就要比人付出更多的…

3.18 Bootstrap 列表组(List Group)

文章目录 Bootstrap 列表组(List Group)向列表组添加徽章向列表组添加链接向列表组添加自定义内容 Bootstrap 列表组(List Group) 本章我们将讲解列表组。列表组件用于以列表形式呈现复杂的和自定义的内容。创建一个基本的列表组的…

Debug Stable Diffusion webui

文章目录 SD前期预备一些惊喜TorchHijackForUnet Txt2Img 搭配 Lora 使用单独运行 txt2img.py获取所有资源代码地址参数sd model 主程序代码地址参数(同上)模型InferenceLORA应用重构并使用LORA模型用Lora重构后的网络 做 sampler后处理 以下内容是最近的学习笔记,如…

MySQL基础语法(DDL、DQL、DML、DCL)

目录 SQL通用语法以及分类 SQL通用语法 SQL语句的分类 数据库/表/列的命名规则 DDL语句 DDL设计的数据类型 数据库操作 表操作(必须先进入到数据库) DQL语句 DQL的执行顺序 基本查询 SELECT 条件查询 WHERE 分组查询 GROUP BY 排序查询 OR…

Python Flask构建微信小程序订餐系统 (十)

🔥 编辑会员信息 🔥 编辑会员信息可以通过点击会员列表操作,也可以点击会员信息详情点击进行操作 🔥 修改编程会员信息列表布局 🔥 修改 web/templates/member/index.html 文件,添加跳转到编辑会员信息的页面 web/templates/member/set.html 🔥 创建用于会员…

python机器学习(四)线性代数回顾、多元线性回归、多项式回归、标准方程法求解、线性回归案例

回顾线性代数 矩阵 矩阵可以理解为二维数组的另一种表现形式。A矩阵为三行两列的矩阵,B矩阵为两行三列的矩阵,可以通过下标来获取矩阵的元素,下标默认都是从0开始的。 A i j : A_{ij}: Aij​:表示第 i i i行,第 j j j列的元素。…

在虚拟机中安装anaconda和pytorch

首先我用的是VMware&#xff0c;ubuntu16.04. 首先建议安装anaconda,登录官网Free Download | Anaconda 下载完成后&#xff0c;来到安装文件目录处&#xff0c;打开终端&#xff0c; 然后在终端输入bash <anaconda文件名> 然后就一直enter和yes到底&#xff0c;直到安…

服务器中了Locked勒索病毒怎么解决,勒索病毒解密恢复方式与防护措施

服务器是企业重要数据存储和处理的关键设备&#xff0c;然而&#xff0c;众所周知&#xff0c;服务器系统并非完全免受网络攻击的。其中一种常见的威胁是勒索病毒&#xff0c;其中一种恶名昭彰的变种是Locked勒索病毒。Locked勒索病毒采用了对称AES与非对称RSA的加密形式&#…

曲线长度预测神经网络设计与实现

在本文中&#xff0c;我们使用深度神经网络 (DNN) 解决几何中的一个基本问题&#xff1a;曲线长度的计算。 我们从监督学习方法的示例中学习了几何属性。 由于最简单的几何对象是曲线&#xff0c;因此我们重点学习平面曲线的长度。 为此&#xff0c;重建了基本长度公理并建立了…

Microsoft发布用于 AutoML 算法和训练的 NNI v1.3

将传统的机器学习方法应用于现实世界的问题可能非常耗时。自动化机器学习 &#xff08;AutoML&#xff09; 旨在改变这种状况——通过对原始数据运行系统流程并选择从数据中提取最相关信息的模型&#xff0c;使构建和使用 ML 模型变得更加容易。 为了帮助用户以高效和自动的方…

【雕爷学编程】Arduino动手做(170)---LGT8F328P 开发板

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

【C++ 程序设计】第 1~9 章:常见知识点汇总

目录 一、C 语言简介 二、面向对象的基本概念 三、类和对象进阶 四、运算符重载 五、类的继承与派生 六、多态与虚函数 七、输入/输出流 八、文件操作 九、函数模板与类模板 一、C 语言简介 知识点名称内容C语言的发展简史★★1. C 语言是 C 语言的前身 &…

PyTorch深度学习实战(6)——神经网络性能优化技术

PyTorch深度学习实战&#xff08;6&#xff09;——神经网络性能优化技术 0. 前言1. 数据准备1.1 数据集分析1.2 数据集加载 2. 使用 PyTorch 训练神经网络2.1 神经网络训练流程2.2 PyTorch 神经网络训练 3. 缩放数据集4. 修改优化器5. 构建深层神经网络小结系列链接 0. 前言 …