1. 程式人生 > >痞子衡嵌入式:記錄i.MXRT1060驅動LCD屏顯示橫向漸變色有亮點問題解決全過程(解答篇)

痞子衡嵌入式:記錄i.MXRT1060驅動LCD屏顯示橫向漸變色有亮點問題解決全過程(解答篇)

----   大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是**i.MXRT1060上LCD橫向漸變色顯示出亮點問題的分析解決經驗**。   接上篇[《一個關於LCD屏顯示出異常亮點的故事(上)》](https://www.cnblogs.com/henjay724/p/12602979.html)咱們繼續聊,上一篇發出之後,大家在我的微信公號文章下面留言很熱烈,大部分朋友都把懷疑點放在了HyperRAM時序配置上,覺得很大概率是HyperRAM的資料訪問出了問題導致了LCD顯示異常,這個懷疑是非常合情合理的,那麼從高效定位問題的角度,我們接下來應該怎麼做? ### 一、問題分析   讓我們回到上一篇的最後,痞子衡列出了所有可能出問題的地方,我們現在需要將這些疑點逐一排除: > 1. 客戶LCD顯示測試程式碼邏輯是否有問題? > 2. 客戶LCD屏與i.MXRT1060連線(線序)是否有問題? > 3. 客戶LCD屏的ST7701S驅動移植(從STM32到i.MXRT1060)是否有問題? > 4. 客戶選用的HyperRAM本身質量是否有問題? > 5. i.MXRT1060配置的客戶HyperRAM時序引數是否有問題? > 6. i.MXRT1060的LCD顯示模組eLCDIF驅動是否有問題? > 7. i.MXRT1060系統的匯流排處理(如Cache、匯流排競爭)是否有問題?   這些懷疑點總結下來就是兩類,一類是硬體問題(如2、4),另一類是軟體問題(如1、3、5、6、7)。痞子衡覺得應該從軟體疑點先下手。因為從現象上看,硬體上基本沒啥大問題,LCD是能夠按程式碼設計那樣去顯示的,而且硬體問題檢查起來(可能涉及改板子或者焊接,萬一整壞了板子...)不如驗證軟體問題來得快,等軟體疑點初步排除了,再找硬體問題也不遲。   確定了從軟體疑點下手,那麼從哪一個開始呢?當然是大家都認為最可疑的點 - HyperRAM時序配置問題這點先入手,不過直接去檢查HyperRAM時序配置較為繁瑣,我們有更好的選擇,uint32_t s_frameBuffer\[480\]\[480\]總大小為900KB,這小於i.MXRT1060內部RAM總空間(1MB),所以我們完全可以將這個frameBuffer連結到內部RAM裡來規避HyperRAM時序配置問題(疑點5)以及系統匯流排處理問題(疑點7),另外我們還可以直接用J-Link修改內部RAM裡的frameBuffer資料來規避客戶測試程式碼邏輯問題(疑點1)。為了方便地生成frameBuffer資料,我們還需要寫個簡單的Python指令碼,那麼我們先嚐試用這一套方法在LCD上顯示一個真實風景照吧。 >
Note: 這套驗證方法的最大好處是高效且省時,不需要在App程式碼工程裡改frameBuffer相關程式碼以及一次次地重新編譯下載。 ### 二、開始測試 #### 2.1 將frameBuffer連結到內部RAM裡 ##### 2.1.1 重配FlexRAM   首先是需要在App工程的startup_MIMXRT1062.s檔案裡修改Reset_Handler程式碼,增加FlexRAM重配程式碼,因為預設RAM配置是128KB ITCM, 128KB DTCM, 768KB OCRAM,我們要將其調整為1MB OCRAM。 ```C __iomux_gpr16_adr EQU 0x400AC040 __iomux_gpr17_adr EQU 0x400AC044 __flexram_bank_cfg EQU 0x55555555 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Default interrupt handlers. ;; THUMB PUBWEAK Reset_Handler SECTION .text:CODE:REORDER:NOROOT(2) Reset_Handler CPSID I ; Mask interrupts ;新增程式碼(開始) LDR R0,=__iomux_gpr17_adr MOV32 R1,__flexram_bank_cfg STR R1,[R0] LDR R0,=__iomux_gpr16_adr LDR R1,[R0] ORR R1,R1,#4 STR R1,[R0] ;新增程式碼(結束) LDR R0, =0xE000ED08 LDR R1, =__vector_table ; ... ``` ##### 2.1.2 調整MPU設定   然後我們要在App工程的board.c檔案裡修改BOARD_ConfigMPU()函式,增加如下程式碼,確保全部1MB OCRAM地址空間(0x20200000開始)都是non-cacheable屬性。 ```C /* Region 6 setting: Memory with Normal type, not shareable, non-cacheable */ MPU->
RBAR = ARM_MPU_RBAR(6, 0x20200000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1MB); ``` ##### 2.1.3 修改連結檔案   最後我們要在App工程的main函式原始檔裡將s_frameBuffer放在一個自定義的.frameBuffer段裡,以便在App連結檔案裡將其放到OCRAM地址空間裡(0x20200000 - 0x202FFFFF)。   main函式原始檔中的修改: ```C __no_init uint32_t s_frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH] @ ".frameBuffer"; ```   App工程連結檔案中的修改: ```text define symbol m_data2_start = 0x20200000; define symbol m_data2_end = 0x202FFFFF; define region DATA2_region = mem:[from m_data2_start to m_data2_end]; place in DATA2_region { section .frameBuffer }; ``` #### 2.2 編寫Python指令碼生成frameBuffer資料 ##### 2.2.1 風景圖片資料   我們可以從網上找一張.jpg格式圖片,將其尺寸裁剪到480x480,然後藉助Pillow裡的Image庫將其轉成XRGB8888格式的binary檔案,對應Python指令碼(指令碼名為convert_jpeg_to_xrgb8888.py)用法和原始碼如下:
```Python import sys, os import argparse from PIL import Image class ConvertJpegToXrgb8888(object): def __init__(self): pass def _read_options(self): parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-o", "--output", required=True, metavar="PATH", type=argparse.FileType('wb'), help="Specify the output file.") parser.add_argument("input", help="JPEG Image file."), return parser.parse_args() def run(self): args = self._read_options() imgObj = Image.open(args.input) pixelBuf = imgObj.getdata() 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.write(chr(0)) args.output.close() if __name__ == "__main__": exit(ConvertJpegToXrgb8888().run()) ``` ##### 2.2.2 RGB測試資料   此外我們還需要一個指令碼,能夠很容易地修改生成指定的RGB測試資料,用於定位亮點問題,對應Python指令碼(指令碼名為generate_xrgb8888.py)用法和原始碼如下: ```Python import sys, os import argparse class GenerateXrgb8888(object): def __init__(self): pass def _read_options(self): parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("-o", "--output", required=True, metavar="PATH", type=argparse.FileType('wb'), help="Specify the output file.") return parser.parse_args() def _make_xrgb8888(self, r, g, b): return chr(b) + chr(g) + chr(r) + chr(0) def run(self): args = self._read_options() for i in range(160): for j in range(480): args.output.write(self._make_xrgb8888(j%256, 0, 0)) for i in range(160): for j in range(480): args.output.write(self._make_xrgb8888(0, j%256, 0)) for i in range(160): for j in range(480): args.output.write(self._make_xrgb8888(0, 0, j%256)) args.output.close() if __name__ == "__main__": exit(GenerateXrgb8888().run()) ``` #### 2.3 使用J-Link將frameBuffer資料更新進OCRAM ##### 2.3.1 顯示風景圖片   我們從網上隨便找一張風景圖片scenery.jpg,使用convert_jpeg_to_xrgb8888.py指令碼將其轉換為scenery.bin,然後將J-Link模擬器掛上晶片,成功連線之後,使用loadbin scenery.bin 0x20200000命令將圖片資料下載進內部RAM。   這時候你可以看到LCD的顯示變成了圖片: ##### 2.3.2 顯示RGB測試資料   從上一節測試的真實圖片顯示效果上看,似乎看不出明顯的亮點問題,這說明亮點在特定RGB資料內容顯示的時候才會顯現出來,那麼我們現在的任務就是要找到這個顯現條件,這時候需要修改generate_xrgb8888.py指令碼來反覆做實驗。   所以痞子衡就不斷地修改指令碼、生成資料、下載資料,功夫不負有心人,痞子衡找到了亮點復現規律。 ### 三、原因分析   痞子衡發現的亮點規律是當橫向某兩個連續漸變畫素點RGB任一分量出現多bit由1向0跳變時(比如前一個畫素點B分量是8'b01111111,後一個畫素點B分量是8'b10000000),則後一個畫素點必是亮點,這個亮點畫素點最終顯示的B分量極可能變成了8'b11111111。   所以分析下來應該是DCLK訊號的極性設定在屏的驅動IC和i.MXRT1060的eLCDIF模組裡不匹配,RGB資料線取樣時機錯了,導致實際顯示的RGB資料發生了錯誤。   在SDK的elcdif_rgb example裡關於eLCDIF模組訊號輸出的極性設定如下,這裡需要注意的是kELCDIF_DriveDataOnRisingClkEdge是置1(即上沿資料輸出,下沿資料保持的意思)。 ```C #define APP_POL_FLAGS (kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DriveDataOnRisingClkEdge) ```   這是i.MXRT1060 eLCDIF極性配置相關:   這是OTA5180A晶片的預設極性配置時序圖:   SDK裡的極性設定與i.MXRT1060-EVK標配的LCD屏(RK043FN02H-CT)裡的驅動晶片OTA5180A預設配置是相吻合的。   我們現在再來看看SDK裡的極性設定與客戶LCD屏的驅動晶片ST7701S的極性配置是否匹配,客戶設定了ST7701S的IM[3:0]狀態為4'b1010,即RGB模式輸出,且PCLK是下沿資料輸入,上沿資料保持(Latch),因此跟SDK裡的極性設定是反相的。   所以最終的解決方法就是要麼將ST7701S的IM[3:0]狀態設為4'b0010,要麼在App程式碼裡將APP_POL_FLAGS定義改用kELCDIF_DriveDataOnFallingClkEdge。 ### 歡迎訂閱 文章會同時釋出到我的 [部落格園主頁](https://www.cnblogs.com/henjay724/)、[CSDN主頁](https://blog.csdn.net/Henjay724)、[微信公眾號](http://weixin.sogou.com/weixin?type=1&query=痞子衡嵌入式) 平臺上。 微信搜尋"__痞子衡嵌入式__"或者掃描下面二維碼,就可以在手機上第一時間看了哦。 ![](http://henjay724.com/image/github/pzhMcu_qrcode_258x2