痞子衡嵌入式:FlexSPI複位方式不當會導致i.MXRT系列下OTFAD加密啟動失敗


  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是FlexSPI複位方式不當會導致i.MXRT系列下OTFAD加密啟動失敗問題

  本篇是《系統時鐘配置不當會導致i.MXRT1xxx系列下OTFAD加密啟動失敗》 的後續篇,我們為i.MXRT1010解決了OTFAD時鐘配置限制問題後,加密的App就一定能正常跑了嗎?其實並不一定,如果你的App跟IAP有關(即會調用FlexSPI驅動去擦寫Flash),免不了會在FlexSPI驅動里操作FlexSPI外設暫存器的軟複位位,軟複位操作方式使用不當可能會導致App無法正常運行,今天痞子衡就來好好聊一聊這個FlexSPI複位小限制:

  • Note1: 雖然i.MXRT1170也包含OTFAD,但是本文中的FlexSPI複位限制問題在i.MXRT1170上並不存在。
  • Note2: 三位數系列i.MXRT600同樣包含OTFAD,且也受本文中的FlexSPI複位限制影響。

一、問題描述

  從恩智浦官網下載一個SDK包(痞子衡下的是v2.9.1),選擇其中 flexspi 常式 \SDK\boards\evkmimxrt1010\driver_examples\flexspi\nor\polling_transfer\ 。編譯這個 flexspi_nor_polling_transfer 工程(選擇 flexspi_nor_debug build,即XIP工程),得到可執行文件,將其下載到 MIMXRT1010-EVK 板載Flash中離線啟動(正常模式,不加密),打開串口調試助手看到如下結果:

  這個結果是常式預期結果,你可能會對這個XIP build也能擦寫Flash感到奇怪,按說板載Flash沒有RWW功能,擦寫Flash操作不能在Flash里原地執行,但是常式的鏈接文件里已經將涉及Flash擦寫程式碼的源文件直接放在RAM里了,因此常式是可以正常執行的。

  現在讓我們根據《系統時鐘配置不當會導致i.MXRT1xxx系列下OTFAD加密啟動失敗》 文中操作使能OTFAD加密,將整個App空間都加密,記得要修復系統時鐘配置限制問題,這時候再離線啟動,看到串口調試助手沒有任何輸出,說明常式執行失敗了。查看工程源程式碼,main()函數里第一句列印前調用了 flexspi_nor_flash_init(EXAMPLE_FLEXSPI);, 看起來OTFAD加密後這個Flash初始化函數執行不太正常。

  為了定位問題方便,我們回到不加密模式,給 flexspi_nor_polling_transfer 工程加上一些輔助調試的列印資訊,主要是FlexSPI相關API函數調用前加上列印資訊。注意:需要將如下三個源文件也放到RAM中才能看到控制台完整輸出。

initialize by copy {
  object fsl_debug_console.o,
  object fsl_adapter_lpuart.o,
  object fsl_lpuart.o,
};

  有了輔助列印資訊,我們現在再回到OTFAD加密模式,可以看到程式碼停在 FLEXSPI_UpdateLUT() 函數就沒有繼續執行下去了。本文不是為了講述如何一步步找到問題的方法,痞子衡其實知道就是 FLEXSPI_SoftwareReset() 函數惹的禍(沒有停在這個函數,是由於系統buffer的緣故),至於是什麼原因,詳見下節。

static inline void FLEXSPI_SoftwareReset(FLEXSPI_Type *base)
{
    base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
    while (0U != (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK))
    {
    }
}

二、原因分析

  老規矩,痞子衡直接給答案,這是OTFAD對FlexSPI外設複位的小限制,當OTFAD被使能時,如果被加密的app程式碼是XIP執行,app里利用FlexSPI->MCR0[SWRESET]位做複位時,這個swreset複位功能會同時清掉FlexSPI->INTR[KEYDONE]位,而FlexSPI的運行依賴OTFAD解析KeyBlob的結果,當FlexSPI->INTR[KEYDONE]位是0時,對Flash的AHB訪問會被禁掉,故而發生CPU lockup,程式碼無法繼續執行。

KEYDONE位為1 - 表明OTFAD解析KeyBlob已正常完成;
KEYDONE位為0 - 表明OTFAD正在解析KeyBlob過程中;

  FlexSPI->MCR0[SWRESET]位存在於任何一款i.MXRT晶片型號中,其功能是複位FlexSPI外設,在下面幾個場景都可以去做一次FlexSPI外設複位,不用擔心,這個外設複位並不影響FlexSPI配置暫存器里的值。不過比較遺憾的是在此時的OTFAD加密啟動使能情形下,不能再用MCR0[SWRESET]位去做複位了

場景一:初始化FlexSPI,打開MCR0[MDIS]位使能模組時
場景二:更新了FlexSPI的LUT表後
場景三:切換了FlexSPI的工作模式後(比如使能Flash四線)
場景四:完成了FlexSPI的擦、寫命令後

三、解決方案

  很多時候FlexSPI->MCR0[SWRESET]位更多是被用來清除AHB TX/RX Buffer(尤其是在Flash擦寫之後),在i.MXRT1010 FlexSPI外設的AHBCR暫存器里其實新增了單獨的CLRAHBTXBUF和CLRAHBRXBUF控制位,用以實現AHB TX/RX Buffer的清除。因此我們為了避免影響OTFAD加密啟動,可以使用AHBCR[CLRAHBTXBUF/CLRAHBRXBUF]位來代替MCR0[SWRESET]位去做複位。

  因此在 flexspi_nor_polling_transfer 工程里,將FLEXSPI_SoftwareReset()函數調用全部改成如下的FLEXSPI_ClearAhbBuffer()函數調用就可以保證工程正常運行了。

static inline void FLEXSPI_ClearAhbBuffer(FLEXSPI_Type *base)
{
#if defined(FSL_FEATURE_SOC_OTFAD_COUNT) && defined(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK)
    base->AHBCR |= FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK;
    base->AHBCR &= ~(FLEXSPI_AHBCR_CLRAHBRXBUF_MASK | FLEXSPI_AHBCR_CLRAHBTXBUF_MASK);
#endif
}

  至此,FlexSPI複位方式不當會導致i.MXRT系列下OTFAD加密啟動失敗問題痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

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

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