查看: 5089|回复: 1

[分享] i.MXRT1170上LCD花屏显示问题的分析解决经验

[复制链接]
  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3900

    主题

    7513

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39627
    最后登录
    2025-8-1
    发表于 2020-6-8 10:36:59 | 显示全部楼层 |阅读模式
    i.MXRT1170上LCD花屏显示问题的分析解决经验


    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是i.MXRT1170上LCD花屏显示问题的分析解决经验。


    痞子衡最近这段时间在参与一个基于i.MXRT1170的大项目(先保个密),需要做一个开机动画功能,板子连接的LCD屏分辨率是1280x480,因为开机动画要求达到30fps,并且要画质清晰,如果是从SD卡里读mp4或者jpeg去解码,这么高分辨率的图像(暂不考虑低分辨率的图片再用PXP模块去拉伸的方案)解码耗时比较长,恐怕难以达成30fps,所以痞子衡打算直接把图片的裸rgb数据事先存在Flash里,然后LCD模块直接去刷Flash里的数据去显示。


    板子上的SPI NOR Flash有两种,默认是八线DDR高性能Flash,还有一个可选的四线SDR普通Flash,痞子衡做好的代码在默认高性能Flash上跑得没问题,换到另一块rework为普通四线Flash上就出问题了,显示完全是花屏,没有一点图片的影子,到底是怎么回事?跟着痞子衡一起去发现答案吧。


    一、项目板卡简图
    先来看一下这个项目板卡简图,简图里只示意了痞子衡今天要分享的LCD问题相关的器件,显示屏是TM103XDKP13控制器驱动的LVDS接口屏,跟i.MXRT连接的话需要有一个RGB2LVDS转接。Flash都是选的旺宏的,一个是MX25UW51345(200MHz,8bit,DDR),还有一个是MX25U25645(133MHz,4bit,SDR)。此外还有两个16bit的W9825G6KH组成的32bit SDRAM做显存,总容量是64MB。
    1.png
    二、在Flash中准备好图片裸数据
    首先我们需要在Flash中存入图片数据,1280x480-24bpp (rgb888)图片一张的裸数据大小是1800KB,32MB的Flash最大可以存18张图片,为了给程序存储留点空间,我们就存17张,从Flash偏移0x100000处开始存图片。


    2.1 截取一段mp4视频

    痞子衡本地有一个NXP十周年宣传视频(MP4格式),原始分辨率是1920x1080,可以先用ffmpeg或者格式工厂将其转换成1280x480,然后可以直接用Windows自带的图片软件里的Trim功能截取其中一段,30fps帧率的视频截取1秒就够了。
    2.png
    2.2 使用ScreenToGif软件分离出图片

    这时候可以用非常好用的GIF制作软件ScreenToGif打开这个1秒的MP4,可以看到一共有31张图片,可以删掉其中一些留下17张,然后将其保存为图片(当前版本仅能保存为png格式),可以再用格式工厂软件将图片格式转为jpg,存在D:/nxp_logo文件夹下。


    2.3 Python脚本转成rgb888裸数据

    有了17张jpg图片,这时候写一个Python脚本(jpg2rgb.py),借助Image库将17张jpg图片中的rgb数据全部抽取出来保存在一个bin文件中,下面脚本使用命令为 python jpg2rgb.py D:/nxp_logo/ -o startup_video_white_rgb888_17f.bin 。


    1. import sys, os
    2. import argparse
    3. import Image

    4. parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
    5. parser.add_argument("-o", "--output", required=True, metavar="PATH", type=argparse.FileType('wb'))
    6. parser.add_argument("input", help="JPEG Image folder.")
    7. args = parser.parse_args()

    8. imgFiles = []

    9. # 获取指定文件夹中所有jpg图片路径
    10. imgFolder = os.path.abspath(args.input)
    11. inputFiles = os.listdir(imgFolder)
    12. for idx in range(len(inputFiles)):
    13.     imgFiles.append(os.path.join(imgFolder, inputFiles[idx]))

    14. for idx in range(len(imgFiles)):
    15.     # 使用Image库打开jpg图片
    16.     imgObj = Image.open(imgFiles[idx])
    17.     pixelBuf = imgObj.getdata()
    18.     # 抽取rgb裸数据写入bin文件
    19.     for i in range(len(pixelBuf)):
    20.         for j in range(len(pixelBuf[i])):
    21.             args.output.write(chr(pixelBuf[i][len(pixelBuf[i]) - j - 1]))
    22. args.output.close()
    复制代码
    2.4 将图片裸数据bin文件下载进Flash
    现在可以借助MCUBootUtility的通用编程器功能将startup_video_white_rgb888_17f.bin文件烧录进Flash里0x100000处偏移的地方。至此,准备工作已经就绪。
    4.png
    三、引出LCD花屏显示问题

    现在让我们开始设计开机动画程序,可以基于 \SDK_2.x.x_MIMXRT1170-EVK\boards\evkmimxrt1170\jpeg_examples\sd_jpeg 例程,将其中的LCD配置,Pinmux配置稍微改一下,适配这个项目的板子,然后主函数可以精简如下(sd卡读,libjpeg解码函数全部去掉):
    1. #define APP_FB_HEIGHT 480
    2. #define APP_FB_WIDTH  1280
    3. /* LCD frame buffer byte per pixel, RGB888 format, 24-bit. */
    4. #define APP_FB_BPP 3

    5. const uint32_t s_imagePics = 17;
    6. const uint32_t s_imageStartAddr = 0x30100000;

    7. int main(void)
    8. {
    9.     uint8_t *imageAddr = (uint8_t *)s_imageStartAddr;
    10.     uint32_t imageBytes = APP_FB_HEIGHT * APP_FB_WIDTH * APP_FB_BPP;

    11.     BOARD_ConfigMPU();
    12.     BOARD_InitBootPins();
    13.     BOARD_BootClockRUN();
    14.     BOARD_ResetDisplayMix();
    15.     APP_InitDisplay();

    16.     while (1)
    17.     {
    18.         /* Wait for the previous set frame buffer active. */
    19.         while (s_newFrameShown == false);

    20.         /* Now new frame is ready, pass it to LCDIF. */
    21.         s_newFrameShown = false;
    22.         g_dc.ops->setFrameBuffer(&g_dc, 0, imageAddr);

    23.         imageAddr += imageBytes;
    24.         if ((uint32_t)imageAddr >= (s_imageStartAddr + imageBytes * s_imagePics))
    25.         {
    26.             break;
    27.         }
    28.     }
    29. }

    30. static void APP_BufferSwitchOffCallback(void *param, void *switchOffBuffer)
    31. {
    32.     s_newFrameShown = true;
    33. }
    复制代码
    这时候把代码下载进高性能DDR Flash的那块板子,我们的代码可以链接到TCM里执行,这样不占用运行时Flash访问带宽,不与LCD抢带宽。断电重启可以看到在60Hz的LCD刷新率下,开机动画效果显示杠杠的。
    11.gif
    现在把代码下载进普通SDR Flash的板子试试,可以看到LCD显示花屏了,完全没有图像的影子,这时候该怎么定位问题?
    12.gif
    四、尝试降低LCD刷新率
    在尝试降低LCD刷新率之前,痞子衡额外做了一些debug工作来确认是不是Flash焊接的问题,首先是调试器挂上去查看PC指针停在哪里,经调试发现,PC指针是在TCM里,根据工程map文件可以查到其地址对应的是程序的结尾,说明代码正常跑完了,这至少证明芯片能够正常从Flash启动。



    然后痞子衡又对程序作了一些改动,将Flash中的图片数据拷贝到SDRAM中,让LCD模块去刷SDRAM,这时候图像显示是正常的,这几乎就可以定位问题了,是普通SDR Flash带宽不够,Flash访问速度撑不起60Hz刷新率。
    1. #define DEMO_HSW        (1U)
    2. #define DEMO_HBP        (48U)
    3. #define DEMO_HFP        (16U)
    4. #define DEMO_VSW        (1U)
    5. #define DEMO_VBP        (3U)
    6. #define DEMO_VFP        (5U)

    7. static void BOARD_InitLcdifClock(void)
    8. {
    9.     /*
    10.      * The pixel clock is (height + VSW + VFP + VBP) * (width + HSW + HFP + HBP) * frame rate.
    11.      *
    12.      * For 60Hz frame rate, the TM103XDKP13 pixel clock should be 40MHz.
    13.      *
    14.      */
    15.     const clock_root_config_t lcdifv2ClockConfig = {
    16.         .clockOff = false,
    17.         .mfn      = 0,
    18.         .mfd      = 0,
    19.         .mux      = 4, /*!< PLL_528. */
    20.         .div      = 12,
    21.     };

    22.     CLOCK_SetRootClock(kCLOCK_Root_Lcdifv2, &lcdifv2ClockConfig);
    23. }
    复制代码
    让我们尝试降低LCD刷新率来验证是不是Flash带宽的问题,在BOARD_InitLcdifClock()函数中修改lcdifv2ClockConfig.div的值,慢慢增大该值,经痞子衡测试,当div设为22时(即对应LCD刷新率为33.9Hz),终于能够正常显示开机动画了。


    五、关于带宽的分析
    现在给出痞子衡的观点,对于一个新项目,如果首次测试LCD显示,建议先从低刷新率开始,只有低刷新率调试通过,再逐渐增大刷新率,否则会因为带宽问题浪费不少时间。


    最后再让我们通过理论公式来推算这款普通SDR Flash能支持最大的刷新率,计算公式其实很简单:
    1. LCD最大刷新率 = (Flash时钟频率 * Flash数据位) / 图片大小 = 133MHz * 4bit / (1280 * 480 * 24bit) = 36.08Hz
    复制代码
    理论计算值36.08Hz跟我们实测值33.9Hz很接近,那点差值应该是FLEXSPI和eLCDIF模块的开销。


    至此,i.MXRT1170上LCD花屏显示问题的分析解决经验痞子衡便介绍完毕了,掌声在哪里~~~



    文章出处:痞子衡嵌入式

    3.png
    qiandao qiandao
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2024-7-18 23:09
  • 签到天数: 1 天

    连续签到: 1 天

    [LV.1]初来乍到

    0

    主题

    2

    帖子

    0

    新手上路

    Rank: 1

    积分
    4
    最后登录
    2024-7-18
    发表于 2024-7-18 23:11:52 | 显示全部楼层
    学习了,单片机的花屏原来这么定位,以前做过海思的VDP模块的开发,基本都是通过linux的proc文件系统去查看帧率,帧的格式,配置的是否是对应屏幕的vtotal,htotal等,和单片机定位方法完全不一样。
    刚注册,进来看看
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-1 10:50 , Processed in 0.081516 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表