• 痞子衡嵌入式:降低刷新率是定位LCD花屏显示问题的第一大法(i.MXRT1170, 1280x480 LVDS)



      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是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。

    二、在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.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 。

    import sys, os
    import argparse
    import Image
    
    parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("-o", "--output", required=True, metavar="PATH", type=argparse.FileType('wb'))
    parser.add_argument("input", help="JPEG Image folder.")
    args = parser.parse_args()
    
    imgFiles = []
    
    # 获取指定文件夹中所有jpg图片路径
    imgFolder = os.path.abspath(args.input)
    inputFiles = os.listdir(imgFolder)
    for idx in range(len(inputFiles)):
        imgFiles.append(os.path.join(imgFolder, inputFiles[idx]))
    
    for idx in range(len(imgFiles)):
        # 使用Image库打开jpg图片
        imgObj = Image.open(imgFiles[idx])
        pixelBuf = imgObj.getdata()
        # 抽取rgb裸数据写入bin文件
        for i in range(len(pixelBuf)):
            for j in range(len(pixelBuf[i])):
                args.output.write(chr(pixelBuf[i][len(pixelBuf[i]) - j - 1]))
    args.output.close()
    
    

    2.4 将图片裸数据bin文件下载进Flash

      现在可以借助MCUBootUtility的通用编程器功能将startup_video_white_rgb888_17f.bin文件烧录进Flash里0x100000处偏移的地方。至此,准备工作已经就绪。

    三、引出LCD花屏显示问题

      现在让我们开始设计开机动画程序,可以基于 SDK_2.x.x_MIMXRT1170-EVKoardsevkmimxrt1170jpeg_examplessd_jpeg 例程,将其中的LCD配置,Pinmux配置稍微改一下,适配这个项目的板子,然后主函数可以精简如下(sd卡读,libjpeg解码函数全部去掉):

    #define APP_FB_HEIGHT 480
    #define APP_FB_WIDTH  1280
    /* LCD frame buffer byte per pixel, RGB888 format, 24-bit. */
    #define APP_FB_BPP 3
    
    const uint32_t s_imagePics = 17;
    const uint32_t s_imageStartAddr = 0x30100000;
    
    int main(void)
    {
        uint8_t *imageAddr = (uint8_t *)s_imageStartAddr;
        uint32_t imageBytes = APP_FB_HEIGHT * APP_FB_WIDTH * APP_FB_BPP;
    
        BOARD_ConfigMPU();
        BOARD_InitBootPins();
        BOARD_BootClockRUN();
        BOARD_ResetDisplayMix();
        APP_InitDisplay();
    
        while (1)
        {
            /* Wait for the previous set frame buffer active. */
            while (s_newFrameShown == false);
    
            /* Now new frame is ready, pass it to LCDIF. */
            s_newFrameShown = false;
            g_dc.ops->setFrameBuffer(&g_dc, 0, imageAddr);
    
            imageAddr += imageBytes;
            if ((uint32_t)imageAddr >= (s_imageStartAddr + imageBytes * s_imagePics))
            {
                break;
            }
        }
    }
    
    static void APP_BufferSwitchOffCallback(void *param, void *switchOffBuffer)
    {
        s_newFrameShown = true;
    }
    

      这时候把代码下载进高性能DDR Flash的那块板子,我们的代码可以链接到TCM里执行,这样不占用运行时Flash访问带宽,不与LCD抢带宽。断电重启可以看到在60Hz的LCD刷新率下,开机动画效果显示杠杠的。

      现在把代码下载进普通SDR Flash的板子试试,可以看到LCD显示花屏了,完全没有图像的影子,这时候该怎么定位问题?

    四、尝试降低LCD刷新率

      在尝试降低LCD刷新率之前,痞子衡额外做了一些debug工作来确认是不是Flash焊接的问题,首先是调试器挂上去查看PC指针停在哪里,经调试发现,PC指针是在TCM里,根据工程map文件可以查到其地址对应的是程序的结尾,说明代码正常跑完了,这至少证明芯片能够正常从Flash启动。

      然后痞子衡又对程序作了一些改动,将Flash中的图片数据拷贝到SDRAM中,让LCD模块去刷SDRAM,这时候图像显示是正常的,这几乎就可以定位问题了,是普通SDR Flash带宽不够,Flash访问速度撑不起60Hz刷新率。

    #define DEMO_HSW        (1U)
    #define DEMO_HBP        (48U)
    #define DEMO_HFP        (16U)
    #define DEMO_VSW        (1U)
    #define DEMO_VBP        (3U)
    #define DEMO_VFP        (5U)
    
    static void BOARD_InitLcdifClock(void)
    {
        /*
         * The pixel clock is (height + VSW + VFP + VBP) * (width + HSW + HFP + HBP) * frame rate.
         *
         * For 60Hz frame rate, the TM103XDKP13 pixel clock should be 40MHz.
         *
         */
        const clock_root_config_t lcdifv2ClockConfig = {
            .clockOff = false,
            .mfn      = 0,
            .mfd      = 0,
            .mux      = 4, /*!< PLL_528. */
            .div      = 12,
        };
    
        CLOCK_SetRootClock(kCLOCK_Root_Lcdifv2, &lcdifv2ClockConfig);
    }
    

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

    五、关于带宽的分析

      现在给出痞子衡的观点,对于一个新项目,如果首次测试LCD显示,建议先从低刷新率开始,只有低刷新率调试通过,再逐渐增大刷新率,否则会因为带宽问题浪费不少时间。
      最后再让我们通过理论公式来推算这款普通SDR Flash能支持最大的刷新率,计算公式其实很简单:

    LCD最大刷新率 = (Flash时钟频率 * Flash数据位) / 图片大小 = 133MHz * 4bit / (1280 * 480 * 24bit) = 36.08Hz

      理论计算值36.08Hz跟我们实测值33.9Hz很接近,那点差值应该是FLEXSPI和eLCDIF模块的开销。

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

    欢迎订阅

    文章会同时发布到我的 博客园主页CSDN主页微信公众号 平台上。

    微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

  • 相关阅读:
    Keras & Theano 输出中间层结果
    keras & tensorflow 列出可用GPU 和 切换CPU & GPU
    Visualizing CNN Layer in Keras
    [python]使用django快速生成自己的博客小站,含详细部署方法
    [JetBrains注册] 利用教育邮箱注册JetBrains产品(pycharm、idea等)的方法
    【python】pycharm常用配置快速入门。
    一道笔试题来理顺Java中的值传递和引用传递
    集群扩容的常规解决:一致性hash算法
    [面经]春季跳槽面筋总结 [2018年3月17]
    TestNG的简单使用
  • 原文地址:https://www.cnblogs.com/henjay724/p/13044745.html
Copyright © 2020-2023  润新知