大家好,我是痞子衡,是正經搞技術的痞子,今天痞子衡給大家分享的是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主頁、微信公眾號 平臺上,
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦,

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/1785.html
標籤:嵌入式
上一篇:低電壓SRAM的重要性
下一篇:SRAM資料存盤原理
