大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是在FDCB里配置串行NOR Flash多個寄存器的注意事項。
我們知道 Flash 內(nèi)部常常有多個狀態(tài)/配置寄存器,這些寄存器有些是易失性的,有些是非易失性的。當(dāng)芯片被指定從 Flash 啟動的時候,我們?nèi)绻M?BootROM 能夠根據(jù)不同應(yīng)用需求來提前設(shè)置好這些 Flash 寄存器,那么在應(yīng)用程序里就不用再額外配置了(涉及 Flash 工作狀態(tài)變化的配置,如果是 XIP 程序去操作,需要考慮代碼重定向問題)。
對于使用 FDCB 來配置 Flash 一個寄存器的操作,相信大家都很了解,在恩智浦 SDK 包里默認(rèn) FDCB 啟動頭里都有成功示例。最近痞子衡同事嘗試使用 FDCB 去配置鎂光 MT35X 的兩個寄存器(地址為 0x000000 的寄存器切至 OPI DDR、地址為 0x000003 的寄存器設(shè) Drive Strength)發(fā)現(xiàn)有一個寄存器設(shè)置沒生效,這是怎么回事?今天我們來聊一聊:
- Note: 本文適用于 i.MXRT500/600/1010/1020/1040/1050/1060/1160/1170
一、FDCB提供的Flash寄存器配置能力
我們先來看一下 FDCB 結(jié)構(gòu)里跟 Flash 配置相關(guān)的成員,痞子衡整理如下,簡單來說,就是有一條 deviceModeSeq 和三條 configCmdSeqs,所以最多能配置 Flash 里 4 個不同命令下對應(yīng)的寄存器(有些 Flash 里一條配置命令能連續(xù)寫入多個寄存器,這種情況下就能配置不止 4 個寄存器),這對于大部分應(yīng)用場景都完全夠用了。
- Note 1: BootROM 執(zhí)行這四個配置的順序分別是 deviceModeSeq、configCmdSeqs[0]、configCmdSeqs[1]、configCmdSeqs[2],記住這個順序。Note 2: deviceModeSeq 與 configCmdSeq 實現(xiàn)的配置功能幾乎沒有區(qū)別,兩者能做的事情是一樣的,可以互換。
//!@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里設(shè)置Flash的Dummy Cycle》 一文最后,痞子衡已經(jīng)分享了 BootROM 解析執(zhí)行 configCmdSeq 的代碼流程,在這個流程里我們能看到和 deviceModeType/configModeType[]、waitTimeCfgCommands 成員相關(guān)的邏輯代碼,這里有必要進(jìn)一步解釋一下。
//!@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
};
當(dāng) deviceModeType/configModeType 成員被設(shè)置為 kDeviceConfigCmdType_Spi2Xpi 時;如果 FDCB 本身被獲取時 BootROM 用得是 DPI/QPI/OPI 命令(根據(jù) efuse 配置決定),那么此條 Flash 寄存器配置會被直接忽略;如果 BootROM 用得是普通一線 SPI 模式讀取的 FDCB,那么這個 Flash 寄存器配置仍然生效。
kDeviceConfigCmdType_Spi2Xpi 等三個跟 Flash 命令模式切換相關(guān)的配置類型,顧名思義就是告訴 BootROM 這三種配置會導(dǎo)致 Flash 工作模式變化,而一旦 Flash 工作模式發(fā)生變化,用于判斷配置是否完成的 READ_STATUS 命令也隨之變得不可用(因為 SPI 模式下與 DPI/QPI/OPI 模式下的命令序列不同),這種情況下就需要借助 waitTimeCfgCommands 成員來實現(xiàn)軟件延時以等待對 Flash 的配置真正生效(如果不等生效就直接進(jìn)入后續(xù)流程,可能會導(dǎo)致啟動問題)。
kDeviceConfigCmdType_Generic 配置類型,則是用于跟工作模式切換無關(guān)的 Flash 寄存器配置,這種情況下 BootROM 可以使用 READ_STATUS 命令來判斷對 Flash 寄存器配置是否已經(jīng)生效,那么就不需要 waitTimeCfgCommands 實現(xiàn)的延時等待(需要查 Flash 數(shù)據(jù)手冊作相應(yīng)設(shè)置,比較麻煩,而且手冊里是給了典型值和最大值,取最大值會導(dǎo)致啟動時間變長,典型值不能保證適用所有情況)。
二、配置Flash多個寄存器注意點
Flash 配置寄存器的寫入流程通常分三步:一、WRITE_ENABLE 使能寫操作;二、具體的 CONFIG_REG 操作;三、READ_STATUS 或者軟件延時確保配置已完成。這些命令序列全部存儲在 FDCB 里的 lookupTable[64] 成員里。
關(guān)于 Flash 寄存器的配置操作,從寄存器屬性上來看,分為易失性和非易失性兩種,前者的操作一般是立即生效的,后者的操作不是立即生效(Flash 狀態(tài)寄存器 WIP 位會反映進(jìn)度)。從命令模式角度來看,分為非模式切換操作(比如設(shè)置 Dummy Cycle、Drive Strength)以及切換 SPI 與 DPI/QPI/OPI 模式操作兩種,同樣前者操作是立即生效,后者操作不是立即生效。
現(xiàn)在回到文章開頭痞子衡同事遇到的問題,如果 deviceModeSeq 用于切換至 OPI DDR 模式,configCmdSeqs[0] 用于設(shè) Drive Strength,請問哪一個操作沒有生效?這里就不賣關(guān)子了,設(shè) Drive Strength 沒有生效,因為第一個配置是切換至 OPI DDR 模式,當(dāng) Flash 切換到該模式時,用于第二/三/四個配置的 WRITE_ENABLE 命令變得不可用了(還是因為 SPI 模式下與 DPI/QPI/OPI 模式下的命令序列不同),當(dāng)然對應(yīng) Flash 寄存器設(shè)置就無效了。
那么如何避免這個問題?有一個一勞永逸的方法,那就是永遠(yuǎn)用 configCmdSeqs[2] 去做 SPI 與 DPI/QPI/OPI 模式切換操作,這樣就不會影響前面三個配置。前面講了,此時判斷命令模式是否切換完成不能用 READ_STATUS 命令,那么就一定需要 waitTimeCfgCommands 來做軟延時,如果延時時間不夠,并且后續(xù) BootROM 執(zhí)行到驗證 IVT 頭時模式切換仍未完成,這會導(dǎo)致 IVT 啟動頭無法正確獲取從而導(dǎo)致啟動失敗。
假設(shè) waitTimeCfgCommands 延時設(shè)置對于命令模式切換已足夠,這樣問題就一定解決了嗎?其實還不一定,如果此時已將 deviceModeSeq 用于設(shè) Drive Strength,但是選擇得是寫入 Flash 非易失性存儲器,這需要確保 waitTimeCfgCommands 延時對于寫入非易失性寄存器也足夠。翻看 MT35X 的數(shù)據(jù)手冊可以發(fā)現(xiàn),寫入非易失性寄存器 cycle time 典型值是 0.2s,最大值是 1s。
再對比看看旺宏以及華邦家的 OctalFlash 非易失性寄存器寫入時間,發(fā)現(xiàn)旺宏最短(<=60us),華邦其次(<=15ms),鎂光有點略長了(<=1s)。越短的寫入時間,啟動時間也越短。
如果此時 waitTimeCfgCommands 設(shè)置對寫入非易失性寄存器來說不夠,即沒等到 Drive Strength 配置完成就去做切換 OPI 模式操作,這會導(dǎo)致模式切換失敗(Flash 在 Busy 期間不能接受任何寫入命令),當(dāng)然也就無法正常啟動了。
以上介紹得都是比較復(fù)雜的 Flash 寄存器配置場景,如果是單純的易失性寄存器配置操作且不涉及模式切換,那么 FDCB 里這四個配置順序也就不重要了,而且也不需要啟用 waitTimeCfgCommands,這樣也不需要過多考慮了。
至此,在FDCB里配置串行NOR Flash多個寄存器的注意事項痞子衡便介紹完畢了,掌聲在哪里~~~