LCD触控屏移植之硬件篇

1 前言

  最近终于打通了从应用层到驱动再到硬件得整个流程,把触摸屏点亮了。回头看发现拖了好久得时间,之所以拖这么久也是强迫症犯了,想精益求精导致地。
  分析官方例程可以看出,项目的优点是触摸模块和lcd模块共用同一个简单的spi驱动程序,除此之外整个就很普通。想要优化项目首先把lcd的驱动替换成framebuffer驱动,增加屏幕的刷新率;其次原来的项目手绘几个界面太低端了,移植一个lvgl,这样跑自己的程序更简单高效;最后触摸模块也要替换成input子系统的驱动,更好的对接lvgl。
  虽然最终花费了点时间,但上述目标都已经实现了!下面是各个模块在实际项目中的接线情况以及遇到的硬件问题及解法。

2 硬件参数信息及接线

  如下是屏幕的尺寸参数信息:

工作电压    5V  分辨率 480 × 320 Pixels
通信接口    SPI 显示尺寸    73.44 × 48.96 mm
显示面板    IPS 像素大小    0.153 × 0.153 mm
控制芯片    ILI9488 产品尺寸    86.00 × 57.20 mm

  开发板引脚功能图(具体引脚编号的计算作用查看我这个文章):



  屏幕引脚与开发板引脚接线图:



  屏幕引脚功能图:



  如上就是屏幕对应开发板的接线情况,清楚的标注了每个引脚的具体功能。在后面适配触摸驱动时,发现了屏幕的一个缺点,因为lcd屏幕和触摸屏都共用一组spi引脚传输数据,这会影响传输效率;并且驱动也需要改动代码以适应此情况。除此之外屏幕整体性能还是不错的,适合练手。

3 lcd屏幕

  点亮整个屏幕花费了很多工夫,回头兜兜转转发现很多问题的答案全在数据手册里,所以一定要读数据手册!大略的抄别人的代码,只要没啥问题,基本上都会把屏幕点亮,但到了细节处,总会遇到各种各样的bug,这些bug的原因往往是因为照本宣科没进行充足的适配导致的。
  还有屏幕原理啥的就不讲了,没啥用!且网上资料也一大堆,想看百度就行了;这里直接分析点亮屏幕的关键部分内容。

3.1 大小端数据传输问题

  这个问题关系着屏幕能否正确显示颜色,在产品手册44页可以看出,spi传输数据时,先传输的是高位;而系统是小端存储。若不进行处理,则屏幕接收的数据就是完全错误的,无法点亮屏幕,因此要读数据手册,根据手册要求更改适配驱动代码。

3.1.1 分析数据手册

  如下图所示是数据手册中对spi传输时数据的要求:



  在图中MSB是数据的最高位,即字节或字中最左边的位。它是数值最大的位。LSB是数据的最低位,即字节或字中最右边的位。它是数值最小的位。
  传输顺序:当配置为 MSB 优先传输时,SPI 总线会先传输数据的最高位,然后依次传输次高位,直到最低位(LSB)。当配置为 LSB 优先传输时,SPI 总线会先传输数据的最低位,然后依次传输次低位,直到最高位(MSB)。
  用途:MSB 通常用于需要保证数据的最重要部分优先传输的场合。在许多标准 SPI 设备中,MSB 优先是默认配置。LSB 优先传输有时用于特定设备或协议需求,但在许多情况下不如 MSB 常用。
  由上文可知,屏幕默认的是MSB模式,spi子系统在接收数据时,是大端序;因此需要在lcd驱动中做数据处理,将系统存储的数据由小端序转换成大端序再有存放到spi子系统的传输队列中发送。

3.1.2 分析驱动代码

  如下是对数据大小端存储的示意:

原始数据
  高位-->低位
0x12345678
 低位------->高位
 12  34  56 78    大端
 78  56  34 12    小端

  数据存储传输方式不一致就导致一个问题,我数据传过来先进入的是78,是数据的低位;而spi要的是高位,冲突了,导致屏幕接收错误数据无法点亮屏幕。所以要在驱动代码中对数据进行大小端的转换。
  这是驱动代码对于这块处理的逻辑:

for (i = 0; i < to_copy; i++)
        {
            txbuf16[i] = cpu_to_be16(vmem16[i]);
        }

  这里的cpu_to_be16函数就是内核自带的将16位数据转换为大端序的接口函数。因此在使用spi子系统传输数据前调用该接口进行数据转换即可解决此问题。

3.2 屏幕颜色选择

3.2.1 点亮屏幕的基本原理

  下面是驱动代码中点亮屏幕的代码逻辑。
  lcd的屏幕是由一个一个的lcd灯构成,点亮每个灯赋予其颜色,直到所有lcd灯都点亮,就可以点亮整个屏幕显示彩色图片了。而其内部实现核心代码是往framebuffer中的一维数组指针里写数据:

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
fb[y * width + x] = color;

  由上可知我们需要计算每个点的坐标并填充颜色。在计算(x,y)的坐标时,width表示每行有width个像素;y*width表示第y行的起始坐标,+x表示第x个像素点。最终获取每个lcd的坐标(xk,yk),例如:(2,2)。获取坐标后再赋予其颜色得数据即可点亮对应颜色得lcd灯。

3.2.2 屏幕颜色的选择

  颜色的选择对于屏幕的显示效果以及后续适配lvgl都至关重要,其本质就是屏幕的每个lcd灯显示什么颜色,这里我选择的是rgb565;一共16位的颜色数据。可以直接适配lvgl,不用做大的改动。

红色(R):高 5 位(15-11)
绿色(G):中 6 位(10-5)
蓝色(B):低 5 位(4-0)

  而颜色的选择又关联着传输数据的选择。根据上文的硬件接线可知屏幕是4线spi,通过数据手册可知四线spi传输数据的内容在4.7.2章节内;又因为我们选择的rgb565是16位的数据格式,所以最终的模式是如下所示的4.7.5.1章节传输格式。



  从图中可以看出,在模式确定后要进行设置需要输入3ah命令,然后设置具体的模式。



  如图所示,可以确定2个模式位都选择16bit后,最终输入的模式值是0x55。



3.3 红蓝反置问题

  在成功点亮屏幕后,发现图片颜色不对,才知道还有这个问题。就是单纯红蓝颜色错位了,正常是看不出来的,需要让屏幕显示一张三原色的图片,看颜色是否正确,不正确需要开启红蓝反置。
  流程如上一小节,找到0x36命令,开启红蓝反置位后,输入的值是0x28;
  而开启后,依旧会有问题,这是因为驱动源码中对红蓝反置的配置又做了设置。具体逻辑如下所示:

//从设备树中获取bgr属性值
pdata->bgr = device_property_read_bool(dev, "bgr");
    |
//再赋值
par->bgr = pdata->bgr;
    |
//将值运算后传给屏幕
write_reg(par, MIPI_DCS_SET_ADDRESS_MODE,
              0x80 | (par->bgr << 3));

  从这里看,bgr的值又重新赋了一次,导致我即使在初始化时设置了红蓝反置也没效果;狠狠的卡了我几个晚上!!!这里对这个问题的修改方法有如下两种:

//1.在lcd的设备树中添加bgr属性,将属性值置1。
bgr = 1;
或
//2.直接注掉上面的par->bgr = pdata->bgr;重新赋值。
par->bgr = 1;

  推荐第一种方法。
  如下是我结合官方demo和其他的例程综合给出的屏幕初始化参数:

 //设置spi传输数据的模式-----4线模式
 0xb0, 0x0,
MIPI_DCS_EXIT_SLEEP_MODE,  //退出睡眠模式
250(延时ns)
 //设置spi像素格式,3ah----rgb565-16位的
MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
//功率控制
    -1, 0xC2, 0x44,  //电源模式,正常模式
    -1, 0x21,  //反显
 //vcom控制
    -1, 0xC5, 0x00, 0x00, 0x00, 0x00,
    //,-1, 0xC5, 0x00, 0x1e, 0x80,
    -1, 0xb6, 0x02,0x42,//显示功能控制
    -1, 0x36, 0x28,//数据存储控制,重点用了红蓝反置的功能位
    /* PGAMCTRL(Positive Gamma Control) *///gamma值校准
    -1, 0xE0, 0x00, 0x13, 0x18, 0x04, 0x0F, 0x06, 0x3a, 0x56,
          0x4d, 0x03, 0x0a, 0x06, 0x30, 0x3e, 0x0f,
    /* NGAMCTRL(Negative Gamma Control) */
    -1, 0xE1, 0x00, 0x13, 0x18, 0x01, 0x11, 0x06, 0x38, 0x34,
          0x4d, 0x06, 0x0d, 0x0b, 0x31, 0x37, 0x0f,
MIPI_DCS_EXIT_SLEEP_MODE,
MIPI_DCS_SET_DISPLAY_ON,

  如果对显示效果有追求,则可以细读手册,额外添加一些命令参数来提升显示效果。

3.4 小结

  至此lcd屏幕硬件方面基本没啥问题了。
  从上文可看出这个luckfox官方出的屏幕性能还是很强大的,没有阉割屏幕成3线spi,而是配置的4线spi,这为后面移植lvgl省下了大量时间,驱动代码也不用大动了,甚至因为不用进行颜色格式转换,而节省了大量的数据转换时间,提升了屏幕的刷新率。如下所示,在lvgl的配置文件lv_conf.h显示了只支持下面几个数据格式。若使用其他颜色格式,需要专门适配。

/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
#define LV_COLOR_DEPTH 16

  后面和其他人交流发现,他们就是因为使用同款三线spi屏幕在移植lvgl时就因为屏幕不支持3线的rgb565,进而导致只能使用其他的颜色格式,还要在驱动层做一次数据转换,拉低了屏幕刷新速度。综合来看官方的这个屏幕还是不错的。

4 触摸屏

  本以为lcd点亮加lvgl移植显示成功后就没啥难题了,没想到后面移植触摸屏驱动又是一个大深坑。在移植触摸驱动时遇到了中断与spi子系统冲突的问题,在这个坑里兜兜转转了好长一段时间;索性皇天不负有心人,最终解决了这个问题。解决问题后回头看发现这些问题本身并没有多难,难点在于网上资料很少,全靠自己摸索解决。

4.1 读XPT2046数据手册

  整体手册读下来没啥要求和细节,要注意的是返回数据是16位的,但数据是高12位有效;且实际应用中一次返回8位数据,因此接收的数据需要自己拼接整理。其次就是传输命令,x轴就是0xd0,y轴就是0x90.其他没任何讲究。
  如下是官方手册里对传输命令每一位的解析;其实也可以不用看,综合计算后得到的值就是0x90和0xd0。



  综上所述可看出相较lcd显示屏初始化,触摸屏的初始化没啥难度;难点在于中断和spi传输数据的配合。

4.2 触摸屏与lcd屏调用spi子系统冲突问题

  这个触摸屏从上面屏幕的引脚信息可以看出,是和ili9488lcd屏幕共用一组spi引脚的,因此spi引脚在驱动和设备树上需要注意一下。它们存在传输时序的问题。这是重中之重!需要重点关注。
  展开来讲时序问题就是lcd模块调用spi子系统传输数据还未完成时,触发了中断调用触摸模块也调用spi接口读取坐标信息,这时不做处理就会导致spi传输时序混乱,出现未知错误。
  解决方式是利用lcd屏幕和触摸屏的cs片选引脚,利用他们的状态做个锁在二者调用spi子系统是进行限制,从而解决此问题(后续在驱动章节详述)。

5 总结

  至此,从应用层到驱动到硬件的整个逻辑链条打通,整体看没啥特别难得问题,只不过就是在这之前没人这么系统得把这个屏幕和luckfox开发板做适配,网上没有详细得资料,导致所有得工作都是从头干起,很多不必要得坑都踩下去了,所以才显得这一路很坎坷。不过有得有失,整个一套搞下来对驱动和设备树得理解更深了。最后,后面剩下的工作无外乎就是逻辑代码的堆叠了。也是最磨人的部分。
  注:sd卡文件系统模块;这个模块我没用到,就没移植。其实和lvgl类似,都是写好的模块;只需要修改几个参数,引脚初始化好就能使用。后面用到时会更新相关教程。

评论

  1. alex
    iPad Safari 14.1.1
    4 月前
    2024-7-21 18:23:19

    你好,这个屏幕我适配了,触摸功能没适配好,你会dts吗,看一下

    • 博主
      alex
      Windows Edge 126.0.0.0
      4 月前
      2024-7-31 14:44:41

      对不起才看到,请问是什么问题!!

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇