痞子衡嵌入式:揭秘i.MXRT1170上串列NOR Flash雙程式可交替啟動設計
- 2022 年 2 月 27 日
- 筆記
- D2.單片機i.MXRT-CM7
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRT1170上串列NOR Flash雙程式可交替啟動設計。
在上一篇文章 《i.MXRT1060/1010上串列NOR Flash冗餘程式啟動設計》 里,痞子衡詳細介紹了 i.MXRT10xx 上的冗餘程式啟動設計,本質上這就是個雙備份程式啟動, NOR Flash 里存兩份一樣的 image,物理地址靠前的 image 0 啟動失效就繼續啟動後面的 image 1,多一層保障。
i.MXRT1170 是區別於 i.MXRT10xx 的第二代架構,性能/功能更加強大,其在繼承 i.MXRT10xx 冗餘程式啟動的基礎上,新增了雙程式可交替啟動設計,今天我們就來聊聊這個話題:
一、初識雙程式可交替啟動
與 i.MXRT10xx 一樣,這裡要聊的還是在一片掛載在 FlexSPI 上的串列 NOR Flash 里做冗餘/雙程式設計,就是下圖中的 image L 和 image H,不涉及 LPSPI 介面 Flash B 里的 image 2。
先說跟 i.MXRT10xx 上一樣的冗餘程式啟動流程,i.MXRT1170 上電先啟動物理地址靠前的 image L,如果 image L 被破壞了,則繼續啟動 image H。
什麼是雙程式可交替啟動呢?簡單說就是物理地址靠前的 image L 並不總是上電首先啟動的 image,在 i.MXRT1170 上新增了如下原型的 image version 啟動頭(在固定偏移 0x600 處),晶片上電 BootROM 會嘗試判斷兩個 image L/H 里的 version 頭版本,高版本的 image 優先被啟動。這種設計方便了 OTA 升級。
- Note: 當 image L/H 中不含有效 version 啟動頭時,雙程式可交替啟動特性就不生效,此時等效於冗餘程式啟動,image L 永遠被優先啟動。
typedef struct
{
uint16_t version;
uint16_t inversion;
} img_ver_t;
二、回顧冗餘程式啟動
在測試雙程式可交替啟動新特性之前,還是先過一下冗餘程式啟動。按照文章 《i.MXRT1060/1010上串列NOR Flash冗餘程式啟動設計》 第 2 節里一模一樣的方法,在恩智浦官方 MIMXRT1170-EVK 開發板上做測試,這個板子 FlexSPI1 上掛了兩片 Flash,默認連接的 16MB QuadSPI Flash,還有一片 64MB OctalFlash(需要做板子改動才能使能)。
在 i.MXRT1170 fuse 里關於冗餘程式啟動的使能位定義與 i.MXRT10xx 上差不多,只不過 fuse 地址從 0x6E0 換到了 0xC80。還是跟之前測試一樣藉助 MCUBootUtility 工具將 FLEXSPI_NOR_SEC_IMAGE_OFFSET 燒錄為 0x10,xSPI_FLASH_IMAGE_SIZE 保持默認 0,即第二份 image 偏移地址在 Flash 0x400000(4MB)處,最大 image 長度也是 4MB。
繼續用 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\led_blinky\cm7\iar\flexspi_nor_debug 常式生成兩個稍微不一樣的 image,閃燈間隔時間一個是 200ms(image L – iled_blinky_cm7_delay200ms.bin),另一個是 2s(image H – iled_blinky_cm7_delay2s.bin)。在 MCUBootUtility 工具主介面下使用 All-In-One 操作將 image L 下載進 Flash(base address 設為 0x30000400),使用通用編程器介面 Write 操作將 image H 也下載進 Flash(Start 設為 0x400400)。
現在 Flash 里有了兩份 image,當第一份 image 啟動失敗後,i.MXRT1170 BootROM 不是立刻去執行下一份 image ,還是那個取巧的方法,在一個軟複位不置位的暫存器里(SRC_GPR10)標記當前狀態,然後調用 NVIC_SystemReset() 重新進入 BootROM 執行。不過此時標記位從 GPR10[30] 換到了 GPR10[27:26],雖然是 2bit 狀態,但設值 1/2/3 等效於設值 1,因為對於串列 NOR Flash 最多就是兩份 image。這時候如果你想掛 J-Link 改寫 SRC_GPR10 去做快速驗證恐怕無法如願,因為 《i.MXRT1170上用J-Link連接複位後PC總是停在0x223104》。
所以在 i.MXRT1170 上只能老老實實做破壞 image 完整性的動作來驗證冗餘程式啟動,經實測其效果與 i.MXRT10xx 是完全一致的。
三、實測雙程式可交替啟動
現在我們開始實測雙程式可交替啟動,主要的工作量就是為 image L 和 image H 添加 version 啟動頭,並且將它們分別下載進 Flash。因為我們想驗證物理地址靠後的 image H 比 image L 優先啟動(冗餘程式啟動做不到這點),所以需要將 image H 的 version 頭版本設高一點。
3.1 為 image 添加 version 啟動頭
還是在 \SDK_2.11.0_MIMXRT1170-EVK\boards\evkmimxrt1170\demo_apps\led_blinky\cm7\iar\flexspi_nor_debug 常式基礎上,首先在工程鏈接文件 MIMXRT1176xxxxx_cm7_flexspi_nor.icf 添加如下語句,指定 .img_ver 段的位置。
define symbol m_boot_img_ver_start = 0x30000600;
place at address mem: m_boot_img_ver_start { section .img_ver };
然後在工程隨便一個源文件里添加如下常量 s_bt_img_l_ver 定義,這個 image 閃燈間隔時間是 200ms(image L – iled_blinky_cm7_delay200ms_ver0.bin),版本是 0x0000(注意編譯鏈接工程時為防止 s_bt_img_l_ver 被優化,可以在工程選項 Linker / Input / Keep symbols 里將其添加進去)。
const img_ver_t s_bt_img_l_ver @ ".img_ver" = {
.version = 0x0000,
.inversion = ~0x0000,
};
同樣的工程,再生成另一個閃燈間隔時間為 2s(image H – iled_blinky_cm7_delay2s_ver1.bin) 的 image 時使用如下常量 s_bt_img_h_ver 定義,版本是 0x0001。
const img_ver_t s_bt_img_h_ver @ ".img_ver" = {
.version = 0x0001,
.inversion = ~0x0001,
};
當然如果你嫌上述方法繁瑣,也可以直接在最終 image binary 文件上做修改(注意 offset 位置一定要找對):
3.2 下載含 version 頭的 image 進 Flash
現在需要藉助 MCUBootUtility 工具的通用編程器功能分別將兩個含 version 頭的 image L/H 下載進 Flash。這裡需要注意的是此時 image L 無法再通過主介面 All-In-One 操作來下載了,因為工具 v3.4 版本及以下沒有對 version 啟動頭做識別處理,因此會丟掉 version 頭數據(這個考慮會在 v4.0 之後加入支援)。
兩個 image 下載完成,一切工作就結束了,這時候你調整晶片啟動模式到 2’b10 – Flash boot,給板卡重新上電,應該可以看到 image H 正在執行。
3.3 BootROM中判斷version的邏輯
BootROM 中關於 version 啟動頭是否有效以及版本高低判斷邏輯其實是有一點複雜的,這裡把具體程式碼分享給大家,方便大家為 image 設置有效的 version 頭以及正確使能這個雙程式可交替啟動特性。
uint32_t image_l_base = 0x30000000
uint32_t image_h_base = 0x30400000
uint32_t get_image_index(void)
{
uint32_t redundant_boot = ((SRC->GPR[9] & 0x0C000000) >> 26);
static uint32_t image_index[] = { 0, 0 };
img_ver_t image_l_version = *(img_ver_t *)(image_l_base + 0x600);
img_ver_t image_h_version = *(img_ver_t *)(image_h_base + 0x600);
if ((image_l_version.version != 0xFFFFu || image_l_version.inversion != 0xFFFFu) &&
((0xFFFFu & image_h_version.version) == (0xFFFFu ^ image_h_version.inversion)) &&
((0xFFFFu & image_l_version.version) != (0xFFFFu ^ image_l_version.inversion) || (image_l_version.version < image_h_version.version)))
{
image_index[0] = 1;
}
else
{
image_index[1] = 1;
}
return image_index[redundant_boot];
}
四、一些關於 image 的注意事項
- Note1: 雖然文中所有的測試均是針對 XIP image,但這個冗餘程式/雙程式可交替啟動特性對於 Non-XIP image 也同樣適用。
- Note2: 如果是 XIP image,其鏈接地址不一定要固定在偏移 0x2000 處,因為 IVT 的存在,其是可以鏈接在偏移 0x2000 之後的任意位置的。
- Note3: 如果是 Non-XIP image,在 SDK 包里無法直接生成含啟動頭的 Non-XIP image binary,這時候可以先使用 MCUBootUtility 主介面的 All-In-One 操作下載一次 image,再通過通用編程器介面 Read 操作讀回來便是含啟動頭的 Non-XIP image binary。
至此,i.MXRT1170上串列NOR Flash雙程式可交替啟動設計痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時發布到我的 部落格園主頁、CSDN主頁、知乎主頁、微信公眾號 平台上。
微信搜索”痞子衡嵌入式“或者掃描下面二維碼,就可以在手機上第一時間看了哦。