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


  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是i.MXRT1060上LCD橫向漸變色顯示出亮點問題的分析解決經驗

  接上篇《一個關於LCD屏顯示出異常亮點的故事(上)》咱們繼續聊,上一篇發出之後,大家在我的微信公號文章下面留言很熱烈,大部分朋友都把懷疑點放在了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。

__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屬性。

/* 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函數源文件中的修改:

__no_init   uint32_t s_frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH] @ ".frameBuffer";

  App工程鏈接文件中的修改:

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)用法和源代碼如下:

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)用法和源代碼如下:

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(即上沿數據輸出,下沿數據保持的意思)。

#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。

歡迎訂閱

文章會同時發佈到我的 博客園主頁CSDN主頁微信公衆號 平臺上。

微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章