你們好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給你們分享的是i.MXRT1170上LCD花屏顯示問題的分析解決經驗。python
痞子衡最近這段時間在參與一個基於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。app
首先咱們須要在Flash中存入圖片數據,1280x480-24bpp (rgb888)圖片一張的裸數據大小是1800KB,32MB的Flash最大能夠存18張圖片,爲了給程序存儲留點空間,咱們就存17張,從Flash偏移0x100000處開始存圖片。ide
痞子衡本地有一個NXP十週年宣傳視頻(MP4格式),原始分辨率是1920x1080,能夠先用ffmpeg或者格式工廠將其轉換成1280x480,而後能夠直接用Windows自帶的圖片軟件裏的Trim功能截取其中一段,30fps幀率的視頻截取1秒就夠了。函數
這時候能夠用很是好用的GIF製做軟件ScreenToGif打開這個1秒的MP4,能夠看到一共有31張圖片,能夠刪掉其中一些留下17張,而後將其保存爲圖片(當前版本僅能保存爲png格式),能夠再用格式工廠軟件將圖片格式轉爲jpg,存在D:/nxp_logo文件夾下。性能
有了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()
如今能夠藉助MCUBootUtility的通用編程器功能將startup_video_white_rgb888_17f.bin文件燒錄進Flash裏0x100000處偏移的地方。至此,準備工做已經就緒。動畫
如今讓咱們開始設計開機動畫程序,能夠基於 \SDK_2.x.x_MIMXRT1170-EVK\boards\evkmimxrt1170\jpeg_examples\sd_jpeg 例程,將其中的LCD配置,Pinmux配置稍微改一下,適配這個項目的板子,而後主函數能夠精簡以下(sd卡讀,libjpeg解碼函數所有去掉):ui
#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刷新率以前,痞子衡額外作了一些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主頁、微信公衆號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就能夠在手機上第一時間看了哦。