大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是i.MXRT500/600上串行NOR Flash雙程序可交替啟動(dòng)設(shè)計(jì)。
在上一篇文章 《i.MXRT1170上串行NOR Flash雙程序可交替啟動(dòng)設(shè)計(jì)》 里,痞子衡詳細(xì)介紹了 i.MXRT11xx 系列上的雙程序啟動(dòng)設(shè)計(jì),本質(zhì)上其就是在雙備份程序啟動(dòng)基礎(chǔ)上增加了 image 版本控制,所以兩份 image 可以按版本優(yōu)先級(jí)來靈活選擇啟動(dòng),而不是死板地靠物理地址高低來定啟動(dòng)順序。
i.MXRTxxx 系列上(RT500/600)也有雙程序可交替啟動(dòng)特性,其主體設(shè)計(jì)邏輯基本上跟 i.MXRT1170 是差不多的,只是一些細(xì)節(jié)處略有差異(比如可啟動(dòng) image 結(jié)構(gòu)不同、otp 配置地址不同、簽名實(shí)現(xiàn)不同、非易失性寄存器暫存狀態(tài)設(shè)計(jì)不同、image 版本判斷邏輯略有不同等),除此之外 i.MXRTxxx 上在驗(yàn)證 image 完整性方面除了簽名外,還有一種相對(duì)平民化的 CRC32 校驗(yàn)可供選擇,這也是今天本文要介紹的重點(diǎn):
一、與 i.MXRT11xx 系列雙程序啟動(dòng)細(xì)節(jié)差異
本文不打算從頭開始完整介紹 i.MXRTxxx 上雙程序可交替啟動(dòng)特性,這里只講和 i.MXRT11xx 上的差異點(diǎn),其余流程直接參考 《i.MXRT1170上串行NOR Flash雙程序可交替啟動(dòng)設(shè)計(jì)》 一文。
1.1 恢復(fù)啟動(dòng)的接口外設(shè)不同
第一點(diǎn)不同其實(shí)與本文要討論的 FlexSPI 雙程序啟動(dòng)特性無關(guān),因?yàn)槲覀円牡倪€是在一片掛載在 FlexSPI 上的串行 NOR Flash 里做雙程序設(shè)計(jì),就是下圖中的 image 0 和 image 1,不涉及 Flexcomm SPI 接口 Flash B 里的 image 2(在 i.MXRT1170 上這個(gè)外設(shè)是 LPSPI)。
在介紹 i.MXRT1170 雙程序啟動(dòng)一文里我們用了 image L/H 來表示 image 0/1,這里還是恢復(fù)使用 image 0/1 來表示,因?yàn)楹竺嫖覀円吹?i.MXRT500/600 參考手冊(cè)啟動(dòng)流程圖里就是用 image 0/1 來表達(dá)的,避免表達(dá)混亂。
1.2 可啟動(dòng) image 結(jié)構(gòu)不同
i.MXRT1170 上最簡(jiǎn)易可啟動(dòng) image 結(jié)構(gòu)比較復(fù)雜(包含 FDCB、img_ver、IVT、BD、App),而 i.MXRTxxx 上就比較簡(jiǎn)單了(僅需 FDCB、img_ver、App),但是好在兩者關(guān)于 image version 頭結(jié)構(gòu)定義以及偏移位置是完全一致的(0x600)。
typedefstruct
{
uint16_tversion;//版本值
uint16_tinversion;//version值的取反(~version)
}img_ver_t;
此外 i.MXRT1170 上第一個(gè) FlexSPI 的 AHB 映射地址是 0x3000_0000,而 i.MXRTxxx 上第一個(gè) FlexSPI 的 AHB 映射地址是 0x0800_0000,這是系統(tǒng)設(shè)計(jì)差異,需要注意。
- Note:下圖中示意地址均是 Flash 偏移地址,沒有包含 AHB 映射地址,另外這里假設(shè)第二份 image 偏移地址在 0x400000(具體是由 otp 配置值來決定的)。
1.3 使能雙程序啟動(dòng)的otp配置地址不同
i.MXRTxxx 上關(guān)于使能雙程序啟動(dòng)的 otp 配置定義與 i.MXRT1170 上是一致的,只是因?yàn)閮烧?otp 空間設(shè)計(jì)不同,所以具體配置地址不同。i.MXRTxxx 上具體配置在 otp BOOT_CFG2/3 上面:
Remap功能的ADDR_START寄存器固定設(shè)為 Flash 起始映射地址。
otp 0x188[31:28] - FlexSPI remap size, App的最大長(zhǎng)度,標(biāo)識(shí)了第一份App的結(jié)束地址,該值加上ADDR_START后被填入Remap功能的ADDR_END寄存器。
otp 0x18C[31:22] - Second image offset,標(biāo)識(shí)了第二份App的起始地址(在Flash中偏移位置),即填入Remap功能的ADDR_OFFSET寄存器的值。
這次我們要在 MIMXRT595-EVK 板卡上實(shí)測(cè),這個(gè)板子 FlexSPI0 上掛了兩片 Flash,默認(rèn)連接的 64MB OctalFlash,還有一片 8MB QuadSPI Flash(需要做板子改動(dòng)才能使能)。為了跟之前測(cè)試保持一致,還是借助 MCUBootUtility 工具將 Second image offset 燒錄為 0x10,F(xiàn)lexSPI remap size 保持默認(rèn) 0,即第二份 image 偏移地址在 Flash 0x400000(4MB)處,最大 image 長(zhǎng)度也是 4MB。
1.4 暫存狀態(tài)的非易失寄存器有差異
i.MXRT1170 是用非易失寄存器 SRC_GPR10 其中 2bit 來記錄當(dāng)前啟動(dòng)狀態(tài)的,而 i.MXRTxxx 上則復(fù)雜得多,它采用了 SYSCTL0 外設(shè)里的一個(gè)非易失寄存器的全部 32bit 來暫存啟動(dòng)狀態(tài)。
//Loadredundantbootoptionsstoredinspecificregister
#defineLOAD_REDUNDANT_BOOT_OPTIONS()(*(volatileuint32_t*)(SYSCTL0_BASE+0x384))
//Storeredundantbootoptionsinspecificregisterbeforesystemreset
#defineSET_REDUNDANT_BOOT_OPTIONS(val)((*(volatileuint32_t*)(SYSCTL0_BASE+0x384))=val)
這個(gè) 32bit 寄存器功能原型如下,它不單純是用做雙程序啟動(dòng)的狀態(tài)記錄了,還糅合了 ROM API 功能。具體用法可以在芯片參考手冊(cè) ROM API 小節(jié)找到,這里不具體展開了,不是本文重點(diǎn)。
typedefstruct_user_app_boot_invoke_option
{
union
{
struct
{
uint32_treserved:8;
uint32_tboot_image_index:4;
uint32_tinstance:4;
uint32_tboot_interface:4;
uint32_tmode:4;
uint32_ttag:8;
}B;
uint32_tU;
}option;
}user_app_boot_invoke_option_t;
1.5 image 版本判斷邏輯不同
在 i.MXRT1170 上 image version 頭有效的條件一定是其高低16bit符合取反關(guān)系,而 i.MXRTxxx 上除了這個(gè)條件外,其認(rèn)定 0xFFFFFFFF 也是一個(gè)有效版本(被定為最低版本)。
芯片參考手冊(cè)里有比較詳細(xì)的 version 判斷邏輯如下,這個(gè)邏輯跟 i.MXRT1170 上差異還是比較大的,i.MXRTxxx 上 BootROM 只會(huì)啟動(dòng)包含有效版本號(hào)的 image,版本有效性是 image 能被啟動(dòng)的一個(gè)必要條件,不像 i.MXRT1170 上版本信息只是單純用來判斷啟動(dòng)順序,不作為 image 是否有效的標(biāo)準(zhǔn)。
痞子衡在 MIMXRT595-EVK 開發(fā)板上對(duì) image 版本設(shè)置情況也做了比較全面的實(shí)測(cè),測(cè)試結(jié)果如下:
image 0 版本值 | image 1 版本值 | 啟動(dòng)結(jié)果 |
---|---|---|
0xFFFFAA55 (或其他無效版本值) |
0xFFFFAA55 (或其他無效版本值) |
不啟動(dòng)任何 image |
0xFFFFAA55 (或其他無效版本值) |
0xFFFE0001 (或其他任意有效版本值包含全0xFFs) |
僅啟動(dòng) image 1 |
0xFFFFAA55 (或其他無效版本值) |
0xFFFF0000 |
會(huì)誤先啟動(dòng) image 0 失敗再啟動(dòng) image 1 |
0xFFFFFFFF | 0xFFFFFFFF |
先啟動(dòng) image 0 失敗再啟動(dòng) image 1 |
0xFFFFFFFF |
0xFFFF0000 (或其他高于0x0的有效版本值) |
先啟動(dòng) image 1 失敗再啟動(dòng) image 0 |
0xFFFE0001 | 0xFFFE0001或0xFFFF0000或者全0xFFs |
先啟動(dòng) image 0 失敗再啟動(dòng) image 1 |
二、測(cè)試CRC32校驗(yàn)雙程序啟動(dòng)
現(xiàn)在來到本文的重頭戲了,如何使能 image 的 CRC32 檢驗(yàn)啟動(dòng)?這個(gè)設(shè)計(jì)其實(shí)最早可追溯到 Kinetis 系列,痞子衡有一篇舊文 《Kinetis BOOT特性(完整性檢測(cè))》,文章很詳細(xì)地介紹了 Kinetis 系列 BootROM 里是如何支持 CRC32 校驗(yàn)的。
2.1 啟動(dòng)頭CRC32參數(shù)存儲(chǔ)位置
i.MXRTxxx BootROM 關(guān)于 CRC32 校驗(yàn)的設(shè)計(jì)與 Kinetis 非常類似,最大的區(qū)別就在于存儲(chǔ) CRC32 三大參數(shù)(起始地址,校驗(yàn)長(zhǎng)度,校驗(yàn)值)的位置。i.MXRTxxx 上也是放在了 App 默認(rèn)中斷向量表里的保留空間里(offset 0x20, 0x28, 0x34),共 12 個(gè)字節(jié)。
offset 0x34 - imageLoadAddress: App加載后中斷向量表首地址,也決定CRC校驗(yàn)起始地址
- 對(duì)于 XIP image,一般固定為 0x08001000(App無需加載)
- 對(duì)于 Non-XIP image,App加載前存儲(chǔ)起始地址是 0x08001000,加載后到指定鏈接的 RAM 地址,CRC計(jì)算和校驗(yàn)是發(fā)生在App加載后。
offset 0x20 - imageLength: 決定CRC校驗(yàn)總長(zhǎng)度,一般是 App 的長(zhǎng)度(從中斷向量表首地址開始到代碼體結(jié)束)
offset 0x28 - crcChecksum: CRC校驗(yàn)值,[imageLoadAddress : imageLoadAddress + imageLength] 范圍內(nèi)數(shù)據(jù)的正確 CRC32 結(jié)果
2.2 使能CRC32校驗(yàn)的條件
當(dāng) App 默認(rèn)中斷向量表里 offset 0x24 處的 imageType[7:0] 類型為 0x02 或者 0x05,且 offset 0x20 處的 imageLength 不為 0 時(shí),CRC32 校驗(yàn)的功能就會(huì)被使能。BootROM 在做 CRC32 計(jì)算時(shí)主要有如下兩個(gè)注意事項(xiàng):
- Note 1: 指定的CRC計(jì)算范圍如果包含crcChecksum這4bytes的話,在計(jì)算CRC時(shí)會(huì)自動(dòng)跳過這4bytes。
- Note 2: 指定的CRC計(jì)算長(zhǎng)度如果不是4字節(jié)對(duì)齊,CRC數(shù)據(jù)計(jì)算到最后會(huì)自動(dòng)補(bǔ)0對(duì)齊。
2.3 具體CRC32算法選項(xiàng)
關(guān)于 CRC32 算法的具體實(shí)現(xiàn)有很多分支,BootROM 中使用的比較主流的 MPEG2 分支,其在計(jì)算 image 具體 CRC 時(shí)主要借助了芯片內(nèi)部的 CRC 模塊(這個(gè)模塊也常見于恩智浦 LPC 系列芯片上),這個(gè) CRC 模塊支持三種固定的 CRC 算法多項(xiàng)式(多項(xiàng)式系數(shù)不是可自由配置的),BootROM 用得就是最后一個(gè)模式選項(xiàng) CRC-32:
BootROM 中對(duì) CRC 模塊的配置代碼如下:
#include"fsl_crc.h"
voidcrc32_init(void)
{
crc_config_tcrcUserConfigPtr;
CRC_GetDefaultConfig(&crcUserConfigPtr);
crcUserConfigPtr.seed=0xffffffffU;
crcUserConfigPtr.polynomial=kCRC_Polynomial_CRC_32;
crcUserConfigPtr.reverseIn=false;
crcUserConfigPtr.reverseOut=false;
crcUserConfigPtr.complementIn=false;
crcUserConfigPtr.complementOut=false;
}
2.4 利用工具自動(dòng)添加CRC校驗(yàn)參數(shù)
對(duì) CRC32 校驗(yàn)啟動(dòng)的原理了解差不多了,我們現(xiàn)在在 MIMXRT595-EVK 開發(fā)板上實(shí)測(cè)一下,跟前面測(cè)試一樣,先使用 SDK_2.10.1_EVK-MIMXRT595oardsevkmimxrt595driver_examplesgpioled_outputiarflash_debug 例程生成兩個(gè)閃燈間隔時(shí)間不同的程序鏡像文件:image 0 - gpio_led_output_delay200ms.bin 和 image 1 - gpio_led_output_delay2s.bin。
然后借助 MCUBootUtility 工具(需要 v3.5.0 版本及以上),在 Secure Boot Type 里選擇 Plain CRC Image Boot,點(diǎn)擊 All-In-One 下載按鈕(兩個(gè)文件分別做兩次同樣的下載流程),工具會(huì)自動(dòng)在 image 相應(yīng)地方填充進(jìn)所需的 CRC32 參數(shù)并下載進(jìn) Flash。
這時(shí)候在工具通用編程器模式(Boot Device Memory)里我們?cè)僮x回 image 保存就可以得到兩個(gè)含 CRC32 校驗(yàn)的程序鏡像文件 image 0 - gpio_led_output_delay200ms_crc.bin 和 image 1 - gpio_led_output_delay2s_crc.bin。
以 image 0 為例,根據(jù) 0x08001020 處的 imageLength 信息顯示,image 0 App 本身長(zhǎng)度為 0x36e8 字節(jié),而 App 起始偏移是 0x1000,所以我們直接是從偏移 0 地址處開始讀回 0x46e8 字節(jié)作為 gpio_led_output_delay200ms_crc.bin 文件數(shù)據(jù)。此外 image 0 的 CRC32 校驗(yàn)值已經(jīng)填好了,是 0x4d8957d8。
2.5 手動(dòng)驗(yàn)證CRC32校驗(yàn)值的方法
在使用 image 0 - gpio_led_output_delay200ms_crc.bin 和 image 1 - gpio_led_output_delay2s_crc.bin 做雙程序啟動(dòng)前,我們可以先手動(dòng)地驗(yàn)證下其中的 CRC32 校驗(yàn)值是否正確,痞子衡找到一個(gè)在線計(jì)算 CRC 的網(wǎng)站:
- CRC在線校驗(yàn)網(wǎng)站:http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
在這個(gè)網(wǎng)站里把模式選好,然后從 gpio_led_output_delay200ms_crc.bin 文件里僅拷貝出 App 部分的數(shù)據(jù)放到網(wǎng)站 CRC Input Data 框(注意要手動(dòng)刪除 crcChecksum 四個(gè)字節(jié),另外還要檢查總數(shù)據(jù)字節(jié)長(zhǎng)度是否按 4 對(duì)齊,如果不對(duì)齊,要在數(shù)據(jù)末尾按格式補(bǔ)上相應(yīng)的 00),最后點(diǎn)擊網(wǎng)站上的 Calculate CRC! 按鈕可以得到結(jié)果,這里我們看到兩個(gè)結(jié)果是一致的:
2.6 含CRC32校驗(yàn)的雙程序啟動(dòng)測(cè)試
現(xiàn)在可以利用 image 0 - gpio_led_output_delay200ms_crc.bin 和 image 1 - gpio_led_output_delay2s_crc.bin 測(cè)試雙程序啟動(dòng)了,繼續(xù)借助 MCUBootUtility 工具的通用編程器模式將其分別下載進(jìn) 0x0 和 0x400000 地址處,必要時(shí)還可以手動(dòng)調(diào)整兩個(gè) image 里的版本號(hào),測(cè)試過程中也可以稍微修改一下 image 數(shù)據(jù)再下載或者下載后再擦除一些 image 區(qū)域(故意讓CRC32校驗(yàn)失?。?,最終測(cè)試結(jié)果如下:
image 0 | image 1 | 啟動(dòng)結(jié)果 | ||
---|---|---|---|---|
CRC情況 | 版本值 | CRC情況 | 版本值 | |
校驗(yàn)通過 | 0xFFFFFFFF | 校驗(yàn)通過/失敗 | 0xFFFFFFFF | 直接啟動(dòng) image 0 |
校驗(yàn)失敗 | 0xFFFFFFFF | 校驗(yàn)通過 | 0xFFFFFFFF | 啟動(dòng) image 0 失敗后啟動(dòng)了 image 1 |
校驗(yàn)通過 | 0xFFFE0001 | 校驗(yàn)通過/失敗 | 0xFFFF0000 | 直接啟動(dòng) image 0 |
校驗(yàn)失敗 | 0xFFFE0001 | 校驗(yàn)通過 | 0xFFFF0000 | 啟動(dòng) image 0 失敗后啟動(dòng)了 image 1 |
校驗(yàn)通過/失敗 | 0xFFFF0000 | 校驗(yàn)通過 | 0xFFFE0001 | 直接啟動(dòng) image 1 |
校驗(yàn)通過 | 0xFFFF0000 | 校驗(yàn)失敗 | 0xFFFE0001 | 啟動(dòng) image 1 失敗后啟動(dòng)了 image 0 |
三、一些關(guān)于 image 的注意事項(xiàng)
- Note1: 雖然文中所有的測(cè)試均是針對(duì) XIP image,但這個(gè)雙程序可交替啟動(dòng)特性對(duì)于 Non-XIP image 也同樣適用。
- Note2: 如果是 XIP image,其鏈接地址要求固定在 Flash 偏移 0x1000 處(如果 Flash 掛在第一個(gè) FlexSPI 上,其 AHB 地址就是 0x08001000)。
- Note3: 如果是 Non-XIP image,在 SDK 包里無法直接生成含啟動(dòng)頭的 Non-XIP image binary,這時(shí)候可以先使用 MCUBootUtility 主界面的 All-In-One 操作下載一次 image,再通過通用編程器界面 Read 操作讀回來便是含啟動(dòng)頭的 Non-XIP image binary。
- Note4: 使能 CRC32 校驗(yàn)的雙程序可交替啟動(dòng),也是同時(shí)支持 XIP image 和 Non-XIP image 的。
至此,i.MXRT500/600上串行NOR Flash雙程序可交替啟動(dòng)設(shè)計(jì)痞子衡便介紹完畢了,掌聲在哪里~~~
原文標(biāo)題:i.MXRTxxx上串行NOR Flash雙程序可交替啟動(dòng)設(shè)計(jì)有何不同?
文章出處:【微信公眾號(hào):痞子衡嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
-
接口
+關(guān)注
關(guān)注
33文章
8575瀏覽量
151021 -
Image
+關(guān)注
關(guān)注
0文章
32瀏覽量
11896 -
NOR flash
+關(guān)注
關(guān)注
2文章
90瀏覽量
23003
原文標(biāo)題:i.MXRTxxx上串行NOR Flash雙程序可交替啟動(dòng)設(shè)計(jì)有何不同?
文章出處:【微信號(hào):pzh_mcu,微信公眾號(hào):痞子衡嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論