痞子衡嵌入式:快速定位i.MXRT600板級設計ISP[2:0]啟動模式引腳上電時序問題的方法

痞子衡發表於2021-05-28

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是一種快速定位i.MXRT600板級設計ISP[2-0]啟動模式引腳上電時序問題的方法

  我們知道恩智浦i.MXRT600是主打音訊市場的MCU產品,其也是i.MXRT三位數平臺的第一款型號。這顆MCU已被眾多知名國際大廠客戶選用,在專案中作為協處理器負責音訊相關子功能。不少客戶都已經到了量產階段,最近痞子衡在支援其中一個量產客戶,客戶遇到了同一批次某幾個板卡無法正常啟動的問題。痞子衡和同事一起排查,最終發現是ISP[2:0]啟動引腳電平上電時序問題。這其實是個典型問題,痞子衡今天教你一招快速定位此類問題的方法:

一、引出上電時序問題

  我們先來看看客戶的問題,下面是客戶板卡簡圖,i.MXRT600是負責音訊功能的協處理器,它的啟動引腳ISP[2:0]與主應用處理器(AP)連線了起來(客戶專案設計裡,AP並不負責控制i.MXRT600的啟動模式),為了防止對i.MXRT600上電ISP引腳取樣有影響,客戶還特地在中間加了一層反向隔離電路。

  • 注:其實i.MXRT600支援Serial Boot模式,這種模式下i.MXRT600作為協處理器,其應用程式資料可直接由AP通過指定的UART/I2C/SPI/USB下載進i.MXRT600的內部RAM執行,能省去一顆外部Flash。

  客戶量產過程中,同一批次幾百塊板卡,有一兩塊板卡上i.MXRT600無法啟動。客戶做了少量ABA實驗:將無法啟動板卡上的i.MXRT600晶片吹下來,換到能正常啟動板卡上,依然無法啟動。反過來,能正常啟動板卡上的i.MXRT600晶片換到無法正常啟動的板卡上,這塊板卡就能正常啟動了。

  從上面ABA實驗來看,似乎不是板級設計問題,像是出問題的板卡上i.MXRT600晶片自身問題。痞子衡拿到一塊出問題的板子,上電後測量了ISP[2:0]引腳電平,其值是3'b011 - FlexSPI Boot from Port A,上電穩定後ISP設定是沒問題的,但剛上電時i.MXRT600 BootROM到底取樣到的是什麼ISP電平值沒人知道。

  下面是客戶板卡上ISP部分反向隔離設計,為了驗證是ISP取樣時機問題,我們特意對電路進行改造將RT600_BOOT0和RT600_BOOT2分別強行拉高和拉低,然後給板卡重新上電,終於板卡能正常啟動了。

  所以我們可以得出初步結論,對於i.MXRT600從上電到BootROM進行ISP取樣,這段時間不是一個嚴格固定值,因晶片製造差異,這個時間應該是在一定範圍內,板級供電設計時上電時間應留有足夠餘量。客戶這個專案裡上電時間餘量留得不足,導致無法滿足個別i.MXRT600晶片ISP取樣時間要求。

二、BootROM中對於啟動模式的處理

  在介紹快速定位ISP取樣時機問題方法前,痞子衡先帶大家瞭解下i.MXRT600 BootROM中關於啟動模式的處理流程。

  我們們先回顧下痞子衡的舊文 《Boot配置(ISP_Pin/OTP)》,每次i.MXRT600晶片硬復位,OTP中的部分關於系統配置的值會被自動載入到OCOTP模組相應Shadow Register裡(關於OCOTP外設基礎知識可參考 《OTP及其燒寫方法》),BootROM中主要用如下 get_runtime_boot_device_info() 函式來獲取最終啟動模式,並將其存在全域性變數 s_bootDeviceInfo 中。

  • 注:程式碼中 OCOTP->OTP_SHADOW[0x60] 暫存器低四位即晶片參考手冊裡提及的 PRIMARY_BOOT_SRC[3:0]
static boot_device_info_t s_bootDeviceInfo;

void get_runtime_boot_device_info(void)
{
    // 從OTP Shadow Register獲取啟動模式
    uint32_t bootSrc = OCOTP->OTP_SHADOW[0x60] & 0x0f;
    boot_device_info_t bootDeviceInfo = { 0 };

    if (bootSrc == 0) // Isp Pin
    {
        // 從ISP[2:0]引腳獲取啟動模式 
        bootSrc = get_bootpin_mode();
        // 對 bootDeviceInfo 成員進一步賦值
    }
    else
    {
        // 對 bootDeviceInfo 成員進一步賦值
    }
    s_bootDeviceInfo = bootDeviceInfo;
}

  每一次i.MXRT600系統軟復位去重新執行BootROM時,ISP[2:0]引腳狀態都會被重新取樣,這完全是軟體取樣。ROM中ISP取樣功能函式如下面 get_bootpin_mode() 所示,程式碼中做了IO電平去抖處理:

#define BOOT_PIN_DEBOUNCE_READ_COUNT 500

uint32_t get_bootpin_mode(void)
{
    uint32_t bootSrc = 0;

    // 使能GPIO外設
    CLOCK_EnableClock(kCLOCK_HsGpio1);
    RESET_PeripheralReset(kHSGPIO1_RST_SHIFT_RSTn);

    // 設定ISP引腳為GPIO模式,並使能上拉.
    IOPCTL->PIO[1][15] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_IBENA(1);
    IOPCTL->PIO[1][16] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_IBENA(1);
    IOPCTL->PIO[1][17] = IOPCTL_PIO_FSEL(0) | IOPCTL_PIO_PUPDENA(1) | IOPCTL_PIO_PUPDSEL(1) | IOPCTL_PIO_IBENA(1);

    // 配置ISP引腳GPIO屬性為數字輸入模式.
    GPIO->DIR[1] &= ~((1U << 15) | (1U << 16) | (1U << 17));

    // Note1: 管腳預設上拉是disable的,ROM需要使能管腳上拉.
    // Note2: 從使能管腳上拉到讀取管腳值之間應間隔10us以上.
    sw_delay_us(10);

    // 取樣ISP引腳值
    for (uint32_t pin = 17; pin >= 15; pin--)
    {
        uint32_t readCount = 0;
        for (uint32_t i = 0; i < BOOT_PIN_DEBOUNCE_READ_COUNT; i++)
        {
            readCount += GPIO->B[1][pin] & 0x1;
        }
        if (readCount >= BOOT_PIN_DEBOUNCE_READ_COUNT / 2)
        {
            bootSrc |= 0x1;
        }
        if (pin != 15)
        {
            bootSrc <<= 1;
        }
    }

    return bootSrc;
}

  上面就是BootROM中關於啟動模式的處理程式碼。那麼有沒有方法掛上偵錯程式通過查後門方式直接讀取到 s_bootDeviceInfo 變數值呢?很抱歉,不可以!即使痞子衡也做不到,雖然痞子衡能通過查BootROM map檔案得知這個變數放在 0x10012d38 地址處。但是i.MXRT600 BootROM中整合了 《Debug Mailbox機制》,我們無法通過偵錯程式讀取正常執行後的ROM狀態,這條路行不通。

三、快速定位ISP[2:0]電平取樣問題

  第一小節介紹的客戶專案啟動問題,其實還算比較好定位,因為有ABA實驗在先,基本可以明確問題就出在ISP取樣時機上。但更多時候,在客戶專案研發階段,沒有ABA實驗的條件,可能僅有一塊板卡,並且Flash配置以及App裡啟動頭是否正確都尚待驗證。這種情況下,我們就需要一種快速甄別是否是ISP取樣時機因素導致的啟動問題。

  當晶片無法啟動時,我們第一想法肯定是要得知第二小節介紹裡 s_bootDeviceInfo 到底是什麼值,這樣我們就能反推ISP引腳到底在ROM裡是什麼取樣值,但這條路行不通。換個角度想,我們能不能不讓BootROM去取樣ISP引腳,換一種替代方式來決定啟動模式,如果這種情況下能按替代設定去啟動,就也可以反證ISP引腳取樣時機有問題。

  這種啟動模式替代設定方法就是痞子衡今天要教大家的方法,利用偵錯程式臨時改寫OCOTP->OTP_SHADOW[0x60]值(對的,我們可以不燒寫OTP),改寫完成後對晶片做一次軟復位即可。OCOTP->OTP_SHADOW暫存器組僅晶片硬體復位或者執行OCOTP更新命令其值才會被重新載入,軟復位不會影響其值。

四、在MIMXRT685-EVK上做一次實驗

  讓我們在MIMXRT685-EVK上做一次實驗,這塊板卡上Flash連到了FlexSPI0 Port B上,我們隨意下載一個SDK XIP工程,並將ISP引腳撥碼設為3'b010 - FlexSPI Boot from Port B,復位後晶片能正常啟動,工程執行正常。

  現在我們將ISP引腳撥碼設為3'b110 - Serial ISP,軟復位後晶片進入了ISP下載模式,不會從Flash啟動。查晶片標頭檔案得知 OCOTP->OTP_SHADOW[0x60] 暫存器地址是 0x50130180,我們現在嘗試改寫這個暫存器。

/** OCOTP - Register Layout Typedef */
typedef struct {
  __IO uint32_t OTP_SHADOW[496];                   /**< OTP shadow register N, array offset: 0x0, array step: 0x4 */
       uint8_t RESERVED_0[64];
  __IO uint32_t OTP_CTRL;                          /**< Control/address register, offset: 0x800 */
  // 省略...
} OCOTP_Type;

/** Peripheral OCOTP base address */
#define OCOTP_BASE                               (0x50130000u)
/** Peripheral OCOTP base address */
#define OCOTP_BASE_NS                            (0x40130000u)
/** Peripheral OCOTP base pointer */
#define OCOTP                                    ((OCOTP_Type *)OCOTP_BASE)
/** Peripheral OCOTP base pointer */
#define OCOTP_NS                                 ((OCOTP_Type *)OCOTP_BASE_NS)

  掛上J-Link偵錯程式,開啟J-Link Commander,連線晶片,注意選擇"MIMXRT685_M33",然後使用w4命令在0x50130180地址處寫入0x00000005(在PRIMARY_BOOT_SRC[3:0]定義裡,4'b0101是QSPI_B_BOOT)。

  繼續執行reset和go命令(或者按一下板載軟復位按鈕RESET BUTTON SW3),這時候你可以看到晶片從Flash正常啟動了,SDK XIP工程又執行起來了,顯然這時候ISP引腳電平設定被忽略了,因此我們找到了有效的啟動模式替代設定方法。

  最後有一點要注意,在使用J-Link軟復位時,如果看到如下log,得檢查下配套JLinkScript裡的ResetTarget()函式具體功能,要確保核心真的被複位了。

  至此,快速定位i.MXRT600板級設計ISP[2-0]啟動模式引腳上電時序問題的方法痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

文章會同時釋出到我的 部落格園主頁CSDN主頁知乎主頁微信公眾號 平臺上。

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

相關文章