17_LinuxLCD驱动

news2024/12/23 10:22:37

目录

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.coloradmin.cn/o/790895.html

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

相关文章

Gumbel Softmax Trick

Gumbel Softmax Trick 重参数化技巧(re-parameters trick)Gumbel softmax trick基于Softmax的采样基于Gumbel-max的采样基于Gumbel-softmax采样Softmax中的温度系数tau 算法学习之gumbel softmax 【Learning Notes】Gumbel 分布及应用浅析 gumbel-softma…

Failed to connect to 127.0.0.1 port 7890科学上网导致的问题

找了很多种解法: 首先这个.config配置文件有两个地方存在:先使用第一种方式,不管用再试第二种 第一个位置git安装路径:不需要重启 E:\git\Git\etc,这个需要看你自己的安装路径,找到http_proxy删除即可第二…

类型转换函数

再论类型转换 标准数据类型之间会进行隐式的类型安全转换 转换规则如下: 问题 普通类型与类类型之间能否进行类型转换? 类类型之间能否进行类型转换? 再论构造函数 构造函数可以定义不同类型的参数 参数满足下列条件时称为转换构造函数…

LocalDateTime的json格式化问题

目录 解决: 1、注册日期序列化器 2、自定义LocalDateTime的JSON格式 3、使用第三方库 总结: 实体类中定义了LocalDateTime类型的属性,获取数据会出现以下日期格式问题: 讲述: 对于LocalDateTime的JSON序列化和反序…

解析数据可视化工具:如何选择最合适的软件

在当今信息爆炸的时代,数据已成为各行各业的重要资源。为了更好地理解和分析数据,数据可视化成为一种必不可少的工具。市面上数据可视化工具不说上千也有上百,什么帆软、powerbi、把阿里datav,腾讯云图、山海鲸可视化等等等等&…

【VCS】(6)Code Coverage

Code Coverage VCS 中 Code Coverage 的类型Code Coverage Flow代码覆盖率选项Lab Code Coverage初步尝试其他格式的覆盖率报告屏蔽部分代码屏蔽整个模块 设计和验证到底要做到什么程度? 这里其中一个指标就是 Code Coverage。 代码覆盖率一般考虑以下几个方面&…

前置操作符和后置操作符

下面的代码有没有区别?为什么? 意想不到的事实 现代编译器产品会对代码进行优化 优化使得最终的二进制程序更加高效 优化后的二进制程序丢失了 C/C 的原生语义 不可能从编译后的二进制程序还原 C/C 程序 思考 操作符可以重载吗? 如何区分…

V1.4基站仓储三代标签操作指导

一、管理系统使用 1、启动v1.4基站 插上电源,用网线连接基站和电脑。基站默认ip为192.168.1.200,所以需要修改电脑的IP地址为192.168.1.x,例如:192.168.1.100 ​ 注:当基站第二个灯(绿色)闪烁…

DAY12_JSPEL表达式JSTL标签MVC模式和三层架构

目录 1 JSP 概述2 JSP 快速入门2.1 搭建环境2.2 导入 JSP 依赖2.3 创建 jsp 页面2.4 编写代码2.5 测试 3 JSP 原理4 JSP 脚本4.1 JSP 脚本分类4.2 案例4.2.1 需求4.2.2 实现4.2.3 成品代码4.2.4 测试 4.3 JSP 缺点 5 EL 表达式5.1 概述5.2 代码演示5.3 域对象 6 JSTL标签6.1 概…

leetcode数据结构题解(Java实现)(存在重复元素、最大子数组和、两数之和、合并两个有序数组)

文章目录 第一天217. 存在重复元素53.最大子数组和 第二天1. 两数之和88. 合并两个有序数组 第一天 217. 存在重复元素 题解思路:首先题目需要的是判断数组中是否存在相同的数字,存在返回true,不存在就返回false。 那么显然可以这样做,先进行…

全光谱护眼灯怎么选择?护眼灯全光谱和自然光谱的区别

一、全光谱护眼台灯的挑选技巧 全光谱:想要护眼台灯能有自然光的效果,选择台灯时建议选择全光谱台灯,并且显色指数大于Ra95以上的,显色指数越高越还原色彩,并且选择RGO豁免蓝光才是真的不会伤害眼睛的。 照射面积&…

Python(四十)for-in练习题——100到999之间的水仙花数

❤️ 专栏简介:本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中,我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 :本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

2023年发布的25个开源大型语言模型总结

大型语言模型(llm)是一种人工智能(AI),在大量文本和代码数据集上进行训练。它们可以用于各种任务,包括生成文本、翻译语言和编写不同类型的创意内容。 今年开始,人们对开源LLM越来越感兴趣。这些模型是在开源许可下发布的,这意味…

Redis Stream 流的深度解析与实现高级消息队列【一万字】

详细介绍了 Redis 5.0 版本新增加的数据结构Stream的使用方式以及原理,如何实现更加可靠的消息队列。 文章目录 Stream 概述2 Stream基本结构3 存储数据3.1 Entry ID3.2 数量限制 4 获取数据4.1 范围查询4.2 独立消费消息4.2.1 非阻塞使用4.2.2 阻塞的使用 4.3 消费…

【Spring定时器】SpringBoot整合Quartz

SpringBoot整合Quartz 简单介绍 简单操作 导入相关pom依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency>创建继承类MyQuartz package com.ustc.quartz; …

C语言假期作业 DAY 01

题目 1.选择题 1、执行下面程序&#xff0c;正确的输出是&#xff08; &#xff09; int x5,y7; void swap() { int z; zx; xy; yz; } int main() { int x3,y8; swap(); printf("%d,%d\n"&#xff0c;x, y)…

Docker 单机/集群 部署 Nacos2.2.0

单机部署 1- 拉取镜像 docker pull nacos/nacos-server:v2.2.02- 准备挂载的配置文件目录和日志目录 日志目录(空目录)&#xff1a;./nacos/logs配置文件&#xff1a;./nacos/conf/application.properties 从官网下载 nacos 压缩包&#xff1a;Release 2.2.0 (Dec 14, 2022…

基于SpringBoot+vue的医院信管系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

TypeScript -- 基础类型

文章目录 TypeScript -- 基础类型let 和 const基本类型写法布尔类型 -- boolean数字类型 -- number字符串类型 -- string数组类型元组类型枚举类型 -- enum任意类型 -- any空值 -- voidNull 和 Undefined不存在的类型 -- never对象 -- object类型断言 TypeScript – 基础类型 1…

关于 ivanti Access Client软件配置问题

最近需要使用ivanti工具连接校园网&#xff0c;但是经常出现ivanti连接后&#xff0c;WIFI或有线网络就显示无互联网连接的情况。 为此&#xff0c;我检查了一下网络的配置状态&#xff0c;发现ivanti连接的时候回临时创建一个网络adapter&#xff0c;该adapter有 一个身份验证…