大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRT上使能NOR Flash的Continuous read模式在軟復位後無法正常啟動問題的解決經驗。
先回顧上篇 《序列NOR Flash的Continuous read模式下軟復位後i.MXRT無法啟動問題解決方案之RESET#》,利用RESET#引腳復位功能是痞子衡找到的第一種解決方案,今天痞子衡繼續給大家介紹第二種解決方案。
- 本系列會有多篇文章,每篇文章均從一個核心切入點出發,給出一系列具體實現方案。
- 本系列均以MIMXRT1170-EVK板為示例目標物件,板載Flash型號為芯成IS25WP128(其他i.MXRT晶片和Flash型號下實現流程也差不多,需檢視對應資料手冊)。
一、解決思路
我們知道無法啟動問題是由於主晶片發生軟復位但Flash仍處於Continuous read模式造成的,要解決這個問題無非如下三個角度,痞子衡會在後面具體實現方案裡按這些角度全部搞一次(如果適用的話)。
- 一、ROM方面不做任何相關處理,但App在呼叫NVIC_SystemReset()做復位前將Flash先切回到Normal模式;
- 二、App方面不做任何相關處理,對BootROM相關配置做一些調整,讓BootROM也能正常處理處於Continuous read模式的Flash;
- 三、ROM和App聯合對Flash模式切換做一些特殊處理。
二、核心切入點(藉助Flash的軟復位命令功能)
本文找的核心切入點是利用Flash的軟體復位命令。Flash的軟體復位時序有兩種:一種是JEDEC標準規定的(嚴格來說其實算硬體復位,但因為其需CS#,SCK,IO0三根訊號線配合完成,因此痞子衡將其歸為軟體復位時序類);另一種是廠商定義的軟體復位命令(因為SOIC-8封裝的Flash沒有獨立RESET#引腳,因此廠商增加這個軟復位命令來代替缺失的獨立RESET#引腳功能)。
2.1 JEDEC標準復位時序
JEDEC協會規定了一種Flash復位時序,需要CS#,SCK,IO0三根訊號線配合完成,時序如下,保持SCK電平不變(高/低均可),拉四次CS#訊號,通過SI訊號線輸出4'b0101(在CS#上升沿取樣),則Flash會進入復位狀態。
JEDEC標準復位功能並不是所有Flash都整合的,華邦、芯成主流Flash型號均不支援JEDEC標準復位,痞子衡知道的Adesto ATXP032系列Flash裡有JEDEC標準復位。
ATXP032資料手冊裡關於JEDEC標準復位相關時序要求如下,進入JEDEC復位後需要 tXUDPD 時間來恢復。
2.2 軟體復位命令時序
Flash資料手冊命令集裡通常都可以找到reset相關命令。在IS25WP128資料手冊裡我們可以找到如下軟復位時序,它由0x66(RSTEN)和0x99(RST)命令組合完成,主晶片發完該命令組合後,Flash即進入復位狀態。
IS25WP128軟體復位最大需要100us的恢復時間,在恢復期間內對Flash進行讀寫擦操作並不會生效。
三、具體實現
本章節描述的方法,如果是在App裡(這裡均指XIP App)完成,那麼App裡增加的相關處理程式碼(注意是執行到的全部程式碼)需要是 ramfunc 屬性(即執行在內部RAM裡),這樣操作Flash時可以不受限制。此外程式碼執行前需要把全域性中斷關掉,防止執行過程中有中斷觸發,導致Flash裡的相關IRQHandler函式被執行。
#if (defined(__ICCARM__))
__ramfunc
#endif
void reset_flash_to_normal(void)
{
__disable_irq();
// 處理程式碼,使Flash返回到Normal模式
NVIC_SystemReset();
}
3.1 僅ROM方面做相關處理
我們先僅從ROM單方面角度來解決問題,可以先看下痞子衡之前的舊文 《瞭解i.MXRT1060系列ROM中序列NOR Flash啟動初始化流程優化點》 裡的2.3節。部分i.MXRT型號ROM裡在序列NOR Flash啟動流程裡整合了JEDEC標準復位。
如果要利用ROM裡整合的JEDEC標準復位功能,則Flash本身必須支援JEDEC標準復位。本系列示例主晶片i.MXRT1170的fusemap表裡關於JEDEC_RESET的相關定義如下,所以我們需要將fuse 0xC80[6]位燒寫為1。
3.2 僅App方面做相關處理
上一小節裡的方法先決條件是Flash要支援JEDEC標準復位,但實際客戶專案中選型的Flash往往沒有整合JEDEC標準復位。所以我們更多應該在廠商定義的軟復位命令上做文章,這就要從App方面的角度來解決問題了。
IS25WP128資料手冊裡找到如下兩個關於reset的命令,reset_flash_to_normal() 函式裡只需要按序傳送這兩個命令,並且延時等夠軟復位恢復時間即可。
程式碼可以基於 \SDK_2.9.1_MIMXRT1170-EVK\boards\evkmimxrt1170\driver_examples\flexspi\nor\polling_transfer\cm7下面的 flexspi_nor_polling_transfer.c 和 flexspi_nor_flash_ops.c,並新增如下程式碼:
#define NOR_CMD_LUT_SEQ_IDX_RESETENABLE 14
#define NOR_CMD_LUT_SEQ_IDX_RESET 15
#define CUSTOM_LUT_LENGTH 64
const uint32_t customLUT[CUSTOM_LUT_LENGTH] = {
// ...
/* 新增 Reset Enable */
[4 * NOR_CMD_LUT_SEQ_IDX_RESETENABLE] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x66, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
/* 新增 Reset */
[4 * NOR_CMD_LUT_SEQ_IDX_RESET] =
FLEXSPI_LUT_SEQ(kFLEXSPI_Command_SDR, kFLEXSPI_1PAD, 0x99, kFLEXSPI_Command_STOP, kFLEXSPI_1PAD, 0),
};
status_t flexspi_nor_software_reset(FLEXSPI_Type *base)
{
flexspi_transfer_t flashXfer;
status_t status;
/* Write enable */
flashXfer.deviceAddress = 0;
flashXfer.port = kFLEXSPI_PortA1;
flashXfer.cmdType = kFLEXSPI_Command;
flashXfer.SeqNumber = 1;
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_RESETENABLE;
status = FLEXSPI_TransferBlocking(base, &flashXfer);
if (status != kStatus_Success)
{
return status;
}
flashXfer.seqIndex = NOR_CMD_LUT_SEQ_IDX_RESET;
status = FLEXSPI_TransferBlocking(base, &flashXfer);
return status;
}
void reset_flash_to_normal(void)
{
__disable_irq();
flexspi_nor_flash_init(EXAMPLE_FLEXSPI);
flexspi_nor_software_reset(EXAMPLE_FLEXSPI);
// 這裡需要插入足夠的延時
SDK_DelayAtLeastUs(100, SystemCoreClock);
NVIC_SystemReset();
}
為了保證上述程式碼均執行在RAM裡,工程連結檔案裡(以IAR示例)需做如下改動:
initialize by copy { readwrite,
section .textrw,
object fsl_common.o,
object I64DivZer.o,
object I64DivMod.o,
object fsl_flexspi.o,
object flexspi_nor_flash_ops.o,
object flexspi_nor_polling_transfer.o,
section CodeQuickAccess };
3.3 ROM和App聯合處理
關於ROM和App聯合處理角度,在復位命令這個切入點上並沒有什麼優勢,此處略去。
至此,i.MXRT上使能NOR Flash的Continuous read模式在軟復位後無法正常啟動問題的解決經驗痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時釋出到我的 部落格園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜尋"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。