百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

什么是定位LCD花屏显示问题的第一大法?

csdh11 2024-12-23 09:26 16 浏览

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是 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-EVK\boards\evkmimxrt1170\jpeg_examples\sd_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 花屏显示问题的分析解决经验痞子衡便介绍完毕了,掌声在哪里~~~

相关推荐

用Python轻松修改Word文件的作者和时间,打造自己的专属效率工具

你是否曾经遇到过需要批量修改Word文件的作者、创建时间或修改时间的情况?手动操作不仅费时费力,还容易出错。可以用Python编写一个小工具,轻松解决这个问题!无论你是编程新手还是有一定经验的...

插件开发js代码划分(js插件编写)

在开发Chrome插件时,将JavaScript代码拆分成多个模块而非集中放置,主要基于性能优化、可维护性提升和浏览器插件特性适配等多方面的考量。以下是具体原因及区别分析:一、拆分的核心原因...

5分钟掌握Python中的标准输入、标准输出、标准错误

读取用户输入从标准输入获取输入:user_input=input("Impartyourwisdom:")print(f"Youshared:{user_input}")...

高大上的解答:在 &#39;packages.pyi&#39; 中找不到引用 &#39;urllib3&#39;

DeepSeek的一句代码:...

Flask 入门教程(flask快速入门)

目录什么是Flask?环境配置与安装第一个Flask应用:HelloWorld路由与视图函数模板与Jinja2表单处理与用户输入...

每日一库之 Go 语言开发者的神器—Gotx

点击上方蓝色“Go语言中文网”关注我们,领全套Go资料,每天学习Go语言简介Gotx是一个Go语言(Golang)的解释器和运行环境,只有单个可执行文件,绿色、跨平台,无需安装任何Go语言环境就可...

MySQL性能调优工具包制作(mysql性能调整)

一、最终工具包内容mysql_tuning_toolkit/├──scripts/#核心脚本│├──sysbench-pro.sh#...

掌握TensorFlow核心用法:从安装到实战的完整指南

一、为什么TensorFlow值得学习?作为全球使用最广泛的开源机器学习框架,TensorFlow已累计获得超过17万GitHub星标,支撑着Google搜索、Waymo自动驾驶、NASA卫星图像分析...

如何把PY 打包成EXE安装文件(pypy 打包exe)

将Python脚本打包成EXE文件通常使用第三方工具实现,以下是详细步骤和注意事项:...

Pygame Zero 详细使用教程(python zerorpc)

PygameZero是一个基于Pygame的简化游戏开发框架,特别适合初学者和快速原型开发。它隐藏了许多底层的复杂性,使得开发者可以更专注于游戏逻辑的实现。本文将通过分析提供的代码,详细介绍如...

Stable diffusion AI画图辅助脚本 Script 的使用(二)

本篇为脚本使用介绍的第二部分,主要介绍Promptmatrix提示词矩阵以及UltimateSDUpscale终极SD放大这两个脚本,同时也简单介绍一下如何编写自己的脚本。1、Promp...

一文明白Python 的import如何工作

Pythonimport系统的基础知识Python的import系统是该语言设计的关键部分,允许模块化编程和代码的轻松重用。了解这个系统对任何Python程序员都很重要,因为它决定了代码的结构...

Highlight.js - 前端的代码语法高亮库

千辛万苦写了篇技术分享,贴了一堆代码,兴高采烈地发到了自己的博客网站上。结果却发现代码全是白底黑字,字体还难看得很,你瞬间就没了兴致。能不能让网页也能像IDE那样,做带语法高亮的炫酷显示呢?来看一...

xbox xsx/s ps2模拟器 战神12,北欧女神2 配置教程

xsxxss下载PS2独立模拟器,Retroarch全能模拟器地址。...

RetroArch 着色器、金手指怎么用? 重返复古游戏萤幕滤镜效果

自从上次分享RetroArch模拟器的一些技巧后,许多模拟器新用户对老旧游戏机感到好奇,为什么游戏画面看起来会有很多马赛克。这主要是因为当年的游戏开发商是针对当时的屏幕进行设计的,所以在现在的高分辨率...