痞子衡嵌入式:深扒i.MXRTxxx系列ROM中集成的串列NOR Flash啟動SW Reset功能及其應用場合


  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRTxxx系列ROM中集成的串列NOR Flash啟動SW Reset功能及其應用場合

  在串列 NOR Flash 熱啟動過程中(非首次上電複位,而是單純系統軟複位 NVIC_SystemReset),有很多場景下均需要先複位一下 Flash ,將其恢復到默認的 Normal 模式,然後 Flash 才能被i.MXRT BootROM 正常啟動。

  《了解i.MXRTxxx系列ROM中靈活的串列NOR Flash啟動硬複位引腳選擇》 一文里介紹的硬複位 Flash 的方法適用包含獨立 RESET# 引腳的 Flash,但很多 Flash 型號並不包含這個專用引腳(尤其是 SOIC-8 封裝),有沒有一種更通用的複位 Flash 方法呢?當然是有的,《串列NOR Flash的Continuous read模式下軟複位後i.MXRT無法啟動問題解決方案之SW Reset》 一文里介紹了一種利用 Flash 里普遍支援的 SW Reset 軟複位命令的方法,並在用戶應用程式里給出了示例程式碼。

  我們知道大部分早期 i.MXRT1xxx 型號 BootROM 里並沒有集成 Flash SW Reset 功能,需要用戶程式碼里去集成這個 Flash SW Reset 命令功能,這有點不方便,因此在更新的 i.MXRTxxx 系列型號 BootROM 里就集成了這個 Flash SW Reset 軟複位功能。今天痞子衡就介紹下這個功能在 BootROM 里實現細節:

  • 備註1:本文主角是i.MXRT500/600,但內容也基本適用i.MXRT1160/1170。
  • 備註2:本文主要適用普通四線 QSPI NOR 或者八線 Octal Flash

一、BootROM中Flash SW Reset功能介紹

1.1 FlexSPI Boot初始化流程

  關於 i.MXRT 系列的串列 NOR Flash 啟動初始化流程,痞子衡一共寫過三篇文章,這些文章雖針對早期 i.MXRT1xxx 系列型號寫的,但內容基本也適用 i.MXRTxxx 系列型號,後續更新的 i.MXRT 型號在這個方面特性只會微調和增強。

  1. 《深入i.MXRT1050系列ROM中串列NOR Flash啟動初始化流程》
  2. 《了解i.MXRT1060系列ROM中串列NOR Flash啟動初始化流程優化點》
  3. 《自識別特性(Auto Probe)可以讓i.MXRT1060無需FDCB也能從NOR Flash啟動》

  為了讓大家對 i.MXRTxxx 系列串列 NOR Flash 啟動初始化流程有明確概念,痞子衡重畫了相應啟動流程圖,從流程上來看,其和 i.MXRT1060 最主要的差異就是三處步驟Y,這是最核心的改進點,也是本文主題。除此以外,還有一些微小差異(步驟7的位置調整)。

1.2 Flash SW Reset相關程式碼設計

  BootROM 中 Flash SW Reset 功能是通過 flexspi_nor_restore_spi_protocol() 函數實現的(關於它的原型可以在 i.MXRT1170 SDK\middleware\mcu-boot\src\drivers\flexspi_nor\flexspi_nor_flash.c 文件里找到),這個函數一共被調用兩次,一次是在 Auto Probe 流程里(見 flexspi_nor_flash.c 文件里的 flexspi_nor_get_config() 函數實現,這個過程用戶無需參與);另一次是在主流程里(見如下程式碼),主流程里的調用才是用戶可以參與控制的:

// Flash 狀態模式
enum
{
    kFlashInstMode_ExtendedSpi = 0x00,
    kFlashInstMode_0_4_4_SDR   = 0x01,
    kFlashInstMode_0_4_4_DDR   = 0x02,
    kFlashInstMode_QPI_SDR     = 0x41,
    kFlashInstMode_QPI_DDR     = 0x42,
    kFlashInstMode_OPI_SDR     = 0x81,
    kFlashInstMode_OPI_DDR     = 0x82,
};

// 主要支援的三種軟複位命令序列
enum
{
    kRestoreSequence_Send_66_99     = 6, // 適用大部分 QSPI Flash(如 IS25WP064A,GD25Q64,W25Q64)以及 Micron 的 OctalFlash
    kRestoreSequence_Send_6699_9966 = 7, // 適用 MXIC 的 OctalFlash,如 MX25UM51345
    kRestoreSequence_Send_06_FF     = 8, // 專用 Adesto EcoXIP
};

typedef union {
    struct
    {
        uint8_t por_mode;             // 默認上電 Flash 狀態模式
        uint8_t current_mode;         // 當前 Flash 狀態模式
        uint8_t exit_no_cmd_sequence;
        uint8_t restore_sequence;     // 指定軟複位命令序列
    } B;
    uint32_t U;
} flash_run_context_t;

// 從指定的非易失性區域獲取用戶設置
flash_run_context_t flashRunCtx;
(void)flexspi_nor_read_persistent(&flashRunCtx.U);

// 根據用戶設置來做相應 Flash 軟複位操作
(void)flexspi_nor_restore_spi_protocol(flexspiInstance, &flexspiNorConfig, &flashRunCtx);

  其中 flashRunCtx.B.restore_sequence 取值跟 Flash 型號有關, kRestoreSequence_Send_66_99 適用 QSPI NOR,比如華邦的 W25Q64(下圖裡 SW Reset 命令有 SPI 模式和 QPI 模式兩種,但 BootROM 只用 QPI SDR 這種):

  kRestoreSequence_Send_66_99 也適用 Micron 的 OctalFlash,如 MT35X 系列(下圖裡 SW Reset 命令有 SPI 模式和 OPI 模式兩種,但 BootROM 只用 OPI SDR 這種):

  kRestoreSequence_Send_6699_9966 適用旺宏的 Octal Flash,比如 MX25UM51345(下圖裡 SW Reset 命令有 SPI 模式和 OPI 模式兩類,但 BootROM 只用 OPI 這類,不過 SDR/DTR 都支援):

1.3 存儲SW Reset指示的易失性通用暫存器

  上一節程式碼中的 flash_run_context_t 結構體變數 flashRunCtx 是用戶程式跟 BootROM 溝通的關鍵,這個變數需要存在一個晶片系統軟複位不清除的區域,BootROM 程式碼里選擇了如下非易失性通用暫存器:

// i.MXRT500/600 里實現
status_t flexspi_nor_read_persistent(uint32_t *data)
{
    *data = *(volatile uint32_t *)(SYSCTL0_BASE + 0x380);

    return kStatus_Success;
}

// i.MXRT1160/1170 里實現
status_t flexspi_nor_read_persistent(uint32_t *data)
{
    *data = SRC->GPR[2];

    return kStatus_Success;
}

1.4 將SW Reset請求傳遞給 BootROM 的兩種方式

  用戶有兩種方式將 flashRunCtx 值傳遞給 BootROM,一是在應用程式程式碼里加入如下程式碼,主動將值寫進指定的通用暫存器,這種方式比較靈活,flashRunCtx 設置可根據實際應用情況任意調整。

flash_run_context_t flashRunCtx = {.U = 0};
flashRunCtx.B.por_mode = kFlashInstMode_ExtendedSpi;
flashRunCtx.B.current_mode = kFlashInstMode_QPI_SDR;
flashRunCtx.B.restore_sequence = kRestoreSequence_Send_66_99;
// 針對 i.MXRT1160/1170
SRC->GPR[2] = flashRunCtx.U;
// 針對 i.MXRT500/600
*(volatile uint32_t *)(SYSCTL0_BASE + 0x380) = flashRunCtx.U;

  第二種方式是利用啟動頭 FDCB,在 flexspi_nor_config_t.flashStateCtx 里保存的就是 flashRunCtx,每一次 BootROM 啟動都會將 FDCB 里的 flashStateCtx 寫入指定的通用暫存器,這種方式相對來說不夠靈活,適用明確的場景。

#if defined(BOOT_HEADER_ENABLE) && (BOOT_HEADER_ENABLE == 1)
#if defined(__ARMCC_VERSION) || defined(__GNUC__)
__attribute__((section(".flash_conf"), used))
#elif defined(__ICCARM__)
#pragma location = ".flash_conf"
#endif

const flexspi_nor_config_t flash_config = {
    .memConfig =
        {
            .tag                 = FLEXSPI_CFG_BLK_TAG,
            // 其他省去不表
        },
    .pageSize      = 256u,
    .sectorSize    = 4u * 1024u,
    .blockSize     = 64u * 1024u,
    // 設置 flashRunCtx
    .flashStateCtx = 0x06004100u,  /*!< [0x1d4-0x1d7] */
};

#endif /* BOOT_HEADER_ENABLE */

二、BootROM中Flash SW Reset功能應用

2.1 Flash進入QPI/OPI模式後系統複位

  Flash 的 SPI 模式和 QPI/OPI 模式常常是互斥的,同一時間僅能一種模式工作。Flash 上電默認是 SPI 模式,需要發送特殊的 QPIEN 命令或者配置一些內部暫存器才能進入 QPI 或者 OPI模式,一旦進了 QPI/OPI 模式,需要被複位回 SPI 模式才能被 BootROM 正常啟動。

  比如在 MIMXRT595-EVK 板卡上,SDK 里 FDCB 啟動頭使能了默認板載 Octal Flash – MX25UM51435 的 OPI DDR 模式,所以我們需要在應用程式系統初始化里插入如下程式碼:

void SystemInit_flash(void)
{
    flash_run_context_t flashRunCtx = {.U = 0};
    flashRunCtx.B.por_mode = kFlashInstMode_ExtendedSpi;
    flashRunCtx.B.current_mode = kFlashInstMode_OPI_DDR;
    run_cflashRunCtxtx.B.restore_sequence = kRestoreSequence_Send_6699_9966;
    *(volatile uint32_t *)(SYSCTL0_BASE + 0x380) = flashRunCtx.U;
}

/*
// 或 FDCB 增加如下設置
const flexspi_nor_config_t flash_config = {
    .flashStateCtx = 0x07008200u,  //!< [0x1d4-0x1d7] //
};
*/

2.2 Flash進入Continuous read模式後系統複位

  《串列NOR Flash的Continuous read模式下軟複位後i.MXRT無法啟動問題解決方案之SW Reset》 一文里的問題,可通過如下新方案實現(基於 MIMXRT1170-EVK 板卡):

void reset_flash_to_normal(void)
{
    __disable_irq();

    flash_run_context_t flashRunCtx = {.U = 0};
    flashRunCtx.B.por_mode = kFlashInstMode_ExtendedSpi;
    flashRunCtx.B.current_mode = kFlashInstMode_0_4_4_SDR;
    flashRunCtx.B.restore_sequence = kRestoreSequence_Send_66_99;
    SRC->GPR[2] = flashRunCtx.U;
    
    NVIC_SystemReset();
}

/*
// 或 FDCB 增加如下設置
const flexspi_nor_config_t flash_config = {
    .flashStateCtx = 0x06000100u,  //!< [0x1d4-0x1d7] //
};
*/

2.3 Flash進入Deep Power Down模式後系統複位

  大部分 Flash 都支援進入 Deep Power Down 模式(通過 B9H 命令進入),這種模式適合一些對功耗要求敏感的設備,比如智慧手錶。在 Deep Power Down 模式下,Flash 不再響應讀寫擦命令,需要接受 Release Deep Power Down 命令(同時也是 Read Device ID命令)才能被再次喚醒正常工作,某些 QSPI NOR 以及 OctalFlash 下也支援 SW Reset 命令來喚醒退出低功耗模式,這時候也可以根據實際情況利用 BootROM 里集成的 SW Reset 功能。

  至此,i.MXRTxxx系列ROM中集成的串列NOR Flash啟動SW Reset功能及其應用場合痞子衡便介紹完畢了,掌聲在哪裡~~~

歡迎訂閱

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

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