關鍵字:STM32H5, data flash, high-cycle data, NMI
問題描述
客戶反饋,使用 STM32H563 的 data flash(high-cycle data flash),在還沒有寫入任何數據之前去讀取 data flash, 會觸發 hardfault 異常。
1. 問題分析
我們嘗試在 NUCLEO-H563ZI 板上重現問題,直接使用 CubeH5 包內的示例工程 :
STM32Cube_FW_H5_V1.4.0\Projects\NUCLEO-H563ZI\Examples\FLASH\FLASH_EDATA_EraseProgram
此示例代碼的大體流程如下 :
1> 系統啟動后,初始化系統時鐘。
2> 配置 OB, 將 FLASH bank1 的最末尾的 8 個 sector 配置為 high-cycle flash.如下紅框所示 :
圖1. 配置末尾 8 個 sector 為 data flash
3> 擦除所有 8 個 high-cycle data flash 扇區
4> 往 8 個 data flash 扇區寫入數據 0xAA55(半字).
5> 最后讀出 8 個 data flash 扇區的數據進行檢查
這里有一個細節,每次編程只寫半字數據,為什么是半字呢?那是因為 data flash 區域每16bit 對應一個 6 位的 ECC 校驗。當然你要是寫一個 32bit 的字也是可以的。
為了模擬客戶的問題,我們將第 4>步驟跳過,即在擦除扇區后,直接讀取扇區內數據。最終重現了問題 :
圖2. 觸發了 NMI 異常
此時查看 FLASH 的 FLASH_ECCDETR 寄存器 :
圖3. FLASH_ECCDETR 寄存器
從寄存器內容可看出,此時觸發了 EDATA_ECC double error 錯誤。剛擦除了 data flash不能立即讀取嗎?于是在參考手冊上找到如下對應內容:
如上圖參考手冊內容所描述,當 data flash 為 virgin word 時(比如剛擦除完,還未寫入任何數據), 此時若去訪問它,當觸發 ECC 錯誤,只有編程后(no more virgin), ECC 錯誤才會消失。
至于讀取 data flash 時,觸發 ECC 錯誤時,寄存器中顯示的內容為什么是 0xf000? 這個在參考手冊中也能找到對應內容:
可見,FLASH_ECCDETR 寄存器的 ADDR_ECC 中顯示的地址并不是簡單地將 flash 地址直接顯示,而是有一定的規則。代碼中訪問的是 0x09000000U 位置就觸發了 data flash ECCD 錯誤,它對應的是 Data area sector 7 的起始位置,如上表所示,對應 0xF000, 此扇區對 ECC?錯誤記錄范圍為 0xF000~0xF1FF.
2. 解決方法
知道了原因,再去解決就比較容易了。解決方法有兩個:
1> 確保代碼中每次讀取 data flash 之前必須先寫入數據。
2> 屏蔽 ECC 錯誤
在讀取 data flash 之前,執行如下代碼:
__HAL_RCC_SBS_CLK_ENABLE();
? ? ? ? HAL_SBS_FLASH_DisableECCNMI();
如此一來,雖 ECC 錯誤仍然存在(已忽略),但不再觸發 NMI 中斷。
3. 其它
與 data flash 具體類似特性的還有 OTP, 它也是若寫任何數據前就去讀取其內容也會觸發 ECCD 錯誤,從而導致 NMI 異常。
另外,對于 data flash,訪問它要關閉其對應的緩存屬性。這個在示例中也有相關代碼,比如:
若不如此做,則當訪問 data flash 時,將觸發 hardfault 中斷。
圖4. 若不關閉緩存屬性,訪問 data flash 將觸發 hardfault
與這個類似的還有 OTP, 和 readonly data(比如芯片 UID). 若對應地址沒關閉緩存直接讀取也會觸發 hardfault.