大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是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. CentOS6.5x64采用静默模式安装64位oracle11g

    1.下载oracle11g64位版本的源文件,并上传到Linux服务器,下载地址自行百度,若实在找不到请留言. 2.Package安装检查安装: 通过yum工具直接安装: yum -y install ...

  2. (Redis基础教程之六)如何使用Redis中的List

    如何在ubuntu18.04上安装和保护redis 如何连接到Redis数据库 如何管理Redis数据库和Keys 如何在Redis中管理副本和客户端 如何在Redis中管理字符串 如何在Redis中 ...

  3. 学习ASP.NET Core(06)-Restful与WebAPI

    上一篇我们使用Swagger添加了接口文档,使用Jwt完成了授权,本章我们简答介绍一下RESTful风格的WebAPI开发过程中涉及到的一些知识点,并完善一下尚未完成的功能 .NET下的WebAPI是 ...

  4. Visual Studio 2019 Professional 激活

    Visual Studio 2019 Professional下载地址>https://visualstudio.microsoft.com/zh-hant/thank-you-download ...

  5. 【python爬虫】scrapy入门4--添加cookies

    (1) settings.py 取消注释:COOKIES_ENABLED = True (2)爬虫xx.py def parse(self, response): c_dic = {自己抓包} # 获 ...

  6. SPL常用函数

    使用SPL_AUTOLOAD_REGISTER装载类 <?php /** * libs/Test.class.php */ class Test { function __construct() ...

  7. 自动网络搜索(NAS)在语义分割上的应用(二)

    前言: 本文将介绍如何基于ProxylessNAS搜索semantic segmentation模型,最终搜索得到的模型结构可在CPU上达到36 fps的测试结果,展示自动网络搜索(NAS)在语义分割 ...

  8. [工具推荐]005.Axure RP Pro 7.0模拟C#TAB控件

    有一次,主管安排我写一个项目的原型,但是项目中涉及到了Tab控件,在Axure中的控件中找了一番,没有找着Tab控件.那么我们只能换种法子来实现它了,我们用到了Dynamic Panel来模拟. 1. ...

  9. 值得注意的Java基础知识

    1)Java语言中默认(即缺省没写出)的访问权限,不同包中的子类不能访问. 中有4中访问修饰符:friendly(默认).private.public和protected. public :能被所有的 ...

  10. BFC与优雅降级 渐进增强——学习笔记

    BFC(块级格式化上下文) BFC(Block formatting context) 直译为"块级格式化上下文". 元素的显示模式 我们前面讲过 元素的显示模式 display. ...