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

欢迎订阅

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

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

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

  1. 痞子衡嵌入式:记录i.MXRT1060驱动LCD屏显示横向渐变色有亮点问题解决全过程(提问篇)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT1060上LCD横向渐变色显示出亮点问题的分析解决经验. 痞子衡前段时间在支持一个i.MXRT1060客户项目时遇到了LCD ...

  2. 痞子衡嵌入式:链接函数到8字节对齐地址或可进一步提升i.MXRT内核执行性能

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT上进一步提升代码执行性能的经验. 今天跟大家聊的这个话题还是跟痞子衡最近这段时间参与的一个基于i.MXRT1170的大项目有 ...

  3. 痞子衡嵌入式:第一本Git命令教程(4)- 转移(add/rm/mv)

    今天是Git系列课程第四课,上一课我们在Git空间里做了一些文件改动并且知道了如何利用Git查看这些变动,今天痞子衡要讲的是将这些变动提交到Git本地仓库前的准备工作. Git仓库目录下的文件改动操作 ...

  4. 痞子衡嵌入式:快速定位i.MXRT600板级设计ISP[2:0]启动模式引脚上电时序问题的方法

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是一种快速定位i.MXRT600板级设计ISP[2-0]启动模式引脚上电时序问题的方法. 我们知道恩智浦i.MXRT600是主打音频市场的 ...

  5. 痞子衡嵌入式:16MB以上NOR Flash使用不当可能会造成软复位后i.MXRT无法正常启动

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是i.MXRT上使用16MB以上NOR Flash软复位无法正常启动问题的分析解决经验. 痞子衡这几天在支持一个i.MXRT1050客户项 ...

  6. 痞子衡嵌入式:恩智浦MCU安全加密启动一站式工具NXP-MCUBootUtility用户指南

    NXP MCU Boot Utility English | 中文 1 软件概览 1.1 介绍 NXP-MCUBootUtility是一个专为NXP MCU安全加密启动而设计的工具,其特性与NXP M ...

  7. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU特性介绍(2)- RT1052DVL6性能实测

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的性能. 在前面的文章 i.MXRT微控制器概览 里,痞子衡给大家简介过恩智浦半导体在2017年推出的新 ...

  8. 痞子衡嵌入式:飞思卡尔i.MX RT系列MCU启动那些事(4)- Flashloader初体验(blhost)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RT系列MCU的Flashloader. 在上一篇文章 Serial Downloader模式(sdphost, mf ...

  9. 痞子衡嵌入式:并行接口NAND标准(ONFI)及SLC Raw NAND简介

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是ONFI标准及SLC Raw NAND. NAND Flash是嵌入式世界里常见的存储器,对于嵌入式开发而言,NAND主要分为两大类:S ...

随机推荐

  1. android 百度地图v3.2.0获取实际地址

    百度地图升级到v3.2.0后,api发生挺大的变化的,但是下载的Demo却不是最新版本的. 在v3.2.0之前获取详细地址只要:option.setIsNeedAddress(true); 但是升级后 ...

  2. Linux shell 正则表达式用法

    1.“ \  ” 用法 用于关闭其后续字符的特殊含义,恢复字符的本身含义,如:\\ 表示字符 \ 2. “ . " 用法 匹配任意单个字符 3. " * " 用法 匹配任 ...

  3. iOS中的系统目录(Documents、tmp、Library)、RunLoop的一些知识点

    学习内容 欢迎关注我的iOS学习总结--每天学一点iOS:https://github.com/practiceqian/one-day-one-iOS-summary 实现轮播图需要注意的地方 需要 ...

  4. 神奇的'license': 'AGPL 3.0'标签报错

    在__minifest__.py中,放了license标签,然后整个模块就报错了. 注释掉这个标签就好了.

  5. POJ1321棋盘问题(DFS)

    Description 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子 ...

  6. linux文档目录

  7. 万字长文!一次性弄懂 Nginx 处理 HTTP 请求的 11 个阶段

    Nginx 处理一个 HTTP 请求的全过程 前面给大家讲了 Nginx 是如何处理 HTTP请求头部的,接下来就到了真正处理 HTTP 请求的阶段了.先看下面这张图,这张图是 Nginx 处理 HT ...

  8. Kubernetes fabric8 JavaAPI

    Kubernetes fabric8 JavaAPI 一.依赖准备 <dependency> <groupId>io.fabric8</groupId> <a ...

  9. MVC4.0 上传文件

    Views/Import/ImportExcel.cshtml @{ Layout = null;} <!DOCTYPE html> <html><head> &l ...

  10. 你真的了解负载均衡中间件nginx吗?

    前言 nginx可所谓是如今最好用的软件级别的负载均衡了.通过nginx的高性能,并发能力强,占用内存下的特点,可以搭建高性能的代理服务.同时nginx还能作为web服务器,反向代理,动静分离服务器. ...