大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是在FDCB裡配置序列NOR Flash多個暫存器的注意事項。
關於使用 i.MXRT 啟動頭 FDCB 來設定 Flash 內部暫存器,痞子衡寫過如下兩篇文章,在進入本文之前,建議大家先閱讀下這兩篇文章,有個初步瞭解。
- 《在FDCB裡設定Flash的Dummy Cycle》
- 《在FDCB裡切換Flash模式至QPI/OPI》
我們知道 Flash 內部常常有多個狀態/配置暫存器,這些暫存器有些是易失性的,有些是非易失性的。當晶片被指定從 Flash 啟動的時候,我們如果希望 BootROM 能夠根據不同應用需求來提前設定好這些 Flash 暫存器,那麼在應用程式裡就不用再額外配置了(涉及 Flash 工作狀態變化的配置,如果是 XIP 程式去操作,需要考慮程式碼重定向問題)。
對於使用 FDCB 來配置 Flash 一個暫存器的操作,相信大家都很瞭解,在恩智浦 SDK 包裡預設 FDCB 啟動頭裡都有成功示例。最近痞子衡同事嘗試使用 FDCB 去配置鎂光 MT35X 的兩個暫存器(地址為 0x000000 的暫存器切至 OPI DDR、地址為 0x000003 的暫存器設 Drive Strength)發現有一個暫存器設定沒生效,這是怎麼回事?今天我們來聊一聊:
- Note: 本文適用於 i.MXRT500/600/1010/1020/1040/1050/1060/1160/1170
一、FDCB提供的Flash暫存器配置能力
我們先來看一下 FDCB 結構裡跟 Flash 配置相關的成員,痞子衡整理如下,簡單來說,就是有一條 deviceModeSeq 和三條 configCmdSeqs,所以最多能配置 Flash 裡 4 個不同命令下對應的暫存器(有些 Flash 裡一條配置命令能連續寫入多個暫存器,這種情況下就能配置不止 4 個暫存器),這對於大部分應用場景都完全夠用了。
- Note 1: BootROM 執行這四個配置的順序分別是 deviceModeSeq、configCmdSeqs[0]、configCmdSeqs[1]、configCmdSeqs[2],記住這個順序。
- Note 2: deviceModeSeq 與 configCmdSeq 實現的配置功能幾乎沒有區別,兩者能做的事情是一樣的,可以互換。
//!@brief FlexSPI Memory Configuration Block
typedef struct _FlexSPIConfig
{
// ...
//!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable
uint8_t deviceModeCfgEnable;
//!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, Generic configuration, etc.
uint8_t deviceModeType;
//!< [0x012-0x013] Wait time for all configuration commands, unit: 100us
uint16_t waitTimeCfgCommands;
//!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt sequence number, [31:16] Reserved
flexspi_lut_seq_t deviceModeSeq;
//!< [0x018-0x01b] Argument/Parameter for device configuration
uint32_t deviceModeArg;
//!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable
uint8_t configCmdEnable;
//!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe
uint8_t configModeType[3];
//!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq
flexspi_lut_seq_t configCmdSeqs[3];
//!< [0x030-0x03b] Arguments/Parameters for device Configuration commands
uint32_t configCmdArgs[3];
// ...
//!< [0x07c-0x07d] Busy offset, valid value: 0-31
uint16_t busyOffset;
//!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - busy flag is 0 when flash device is busy
uint16_t busyBitPolarity;
//!< [0x080-0x17f] Lookup table holds Flash command sequences
uint32_t lookupTable[64];
// ...
} flexspi_mem_config_t;
在 《在FDCB裡設定Flash的Dummy Cycle》 一文最後,痞子衡已經分享了 BootROM 解析執行 configCmdSeq 的程式碼流程,在這個流程裡我們能看到和 deviceModeType/configModeType[]、waitTimeCfgCommands 成員相關的邏輯程式碼,這裡有必要進一步解釋一下。
//!@brief Flash Configuration Command Type
enum
{
kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc
kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command
kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode
kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode
kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode
kDeviceConfigCmdType_Reset, //!< Reset device command
};
當 deviceModeType/configModeType 成員被設定為 kDeviceConfigCmdType_Spi2Xpi 時;如果 FDCB 本身被獲取時 BootROM 用得是 DPI/QPI/OPI 命令(根據 efuse 配置決定),那麼此條 Flash 暫存器配置會被直接忽略;如果 BootROM 用得是普通一線 SPI 模式讀取的 FDCB,那麼這個 Flash 暫存器配置仍然生效。
kDeviceConfigCmdType_Spi2Xpi 等三個跟 Flash 命令模式切換相關的配置型別,顧名思義就是告訴 BootROM 這三種配置會導致 Flash 工作模式變化,而一旦 Flash 工作模式發生變化,用於判斷配置是否完成的 READ_STATUS 命令也隨之變得不可用(因為 SPI 模式下與 DPI/QPI/OPI 模式下的命令序列不同),這種情況下就需要藉助 waitTimeCfgCommands 成員來實現軟體延時以等待對 Flash 的配置真正生效(如果不等生效就直接進入後續流程,可能會導致啟動問題)。
kDeviceConfigCmdType_Generic 配置型別,則是用於跟工作模式切換無關的 Flash 暫存器配置,這種情況下 BootROM 可以使用 READ_STATUS 命令來判斷對 Flash 暫存器配置是否已經生效,那麼就不需要 waitTimeCfgCommands 實現的延時等待(需要查 Flash 資料手冊作相應設定,比較麻煩,而且手冊裡是給了典型值和最大值,取最大值會導致啟動時間變長,典型值不能保證適用所有情況)。
二、配置Flash多個暫存器注意點
Flash 配置暫存器的寫入流程通常分三步:一、WRITE_ENABLE 使能寫操作;二、具體的 CONFIG_REG 操作;三、READ_STATUS 或者軟體延時確保配置已完成。這些命令序列全部儲存在 FDCB 裡的 lookupTable[64] 成員裡。
關於 Flash 暫存器的配置操作,從暫存器屬性上來看,分為易失性和非易失性兩種,前者的操作一般是立即生效的,後者的操作不是立即生效(Flash 狀態暫存器 WIP 位會反映進度)。從命令模式角度來看,分為非模式切換操作(比如設定 Dummy Cycle、Drive Strength)以及切換 SPI 與 DPI/QPI/OPI 模式操作兩種,同樣前者操作是立即生效,後者操作不是立即生效。
現在回到文章開頭痞子衡同事遇到的問題,如果 deviceModeSeq 用於切換至 OPI DDR 模式,configCmdSeqs[0] 用於設 Drive Strength,請問哪一個操作沒有生效?這裡就不賣關子了,設 Drive Strength 沒有生效,因為第一個配置是切換至 OPI DDR 模式,當 Flash 切換到該模式時,用於第二/三/四個配置的 WRITE_ENABLE 命令變得不可用了(還是因為 SPI 模式下與 DPI/QPI/OPI 模式下的命令序列不同),當然對應 Flash 暫存器設定就無效了。
那麼如何避免這個問題?有一個一勞永逸的方法,那就是永遠用 configCmdSeqs[2] 去做 SPI 與 DPI/QPI/OPI 模式切換操作,這樣就不會影響前面三個配置。前面講了,此時判斷命令模式是否切換完成不能用 READ_STATUS 命令,那麼就一定需要 waitTimeCfgCommands 來做軟延時,如果延時時間不夠,並且後續 BootROM 執行到驗證 IVT 頭時模式切換仍未完成,這會導致 IVT 啟動頭無法正確獲取從而導致啟動失敗。
假設 waitTimeCfgCommands 延時設定對於命令模式切換已足夠,這樣問題就一定解決了嗎?其實還不一定,如果此時已將 deviceModeSeq 用於設 Drive Strength,但是選擇得是寫入 Flash 非易失性儲存器,這需要確保 waitTimeCfgCommands 延時對於寫入非易失性暫存器也足夠。翻看 MT35X 的資料手冊可以發現,寫入非易失性暫存器 cycle time 典型值是 0.2s,最大值是 1s。
再對比看看旺宏以及華邦家的 OctalFlash 非易失性暫存器寫入時間,發現旺宏最短(<=60us),華邦其次(<=15ms),鎂光有點略長了(<=1s)。越短的寫入時間,啟動時間也越短。
如果此時 waitTimeCfgCommands 設定對寫入非易失性暫存器來說不夠,即沒等到 Drive Strength 配置完成就去做切換 OPI 模式操作,這會導致模式切換失敗(Flash 在 Busy 期間不能接受任何寫入命令),當然也就無法正常啟動了。
以上介紹得都是比較複雜的 Flash 暫存器配置場景,如果是單純的易失性暫存器配置操作且不涉及模式切換,那麼 FDCB 裡這四個配置順序也就不重要了,而且也不需要啟用 waitTimeCfgCommands,這樣也不需要過多考慮了。
至此,在FDCB裡配置序列NOR Flash多個暫存器的注意事項痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時釋出到我的 部落格園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。