大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是 i.MXRT 部分型號(hào)上新增的 FlexSPI Remap 功能。
OTA 升級(jí)設(shè)計(jì)幾乎是每個(gè)量產(chǎn)客戶都繞不開的話題,產(chǎn)品發(fā)布后免不了要做固件(App)升級(jí)以修復(fù) bug 或者增加新特性。升級(jí) App 是個(gè)麻煩事,因?yàn)樘幚聿缓?,App 被破壞了導(dǎo)致啟動(dòng)不了,產(chǎn)品就容易變磚,變了磚即使能救回來,也非常影響用戶體驗(yàn)。
如今基于 i.MXRT 的客戶量產(chǎn)產(chǎn)品越來越多,關(guān)于 OTA 安全升級(jí)的客戶支持也越來越多。早期的 i.MXRT 型號(hào)(比如 i.MXRT1050/1020/1015)在做基于 FlexSPI NOR Flash 的 OTA 升級(jí)時(shí),有一個(gè)最大痛點(diǎn)即 App 版本切換不便,因此后面的 i.MXRT 型號(hào)中(比如 i.MXRT1064/1060/1010)新增了 FlexSPI 的 Remap 功能。今天痞子衡就來介紹一下這個(gè) Remap 功能是如何用于安全 OTA 的。
一、OTA 設(shè)計(jì)中的痛點(diǎn)
1.1 OTA 一般設(shè)計(jì)
在講 App 版本切換不便痛點(diǎn)前,先給大家簡(jiǎn)單介紹一下 OTA 升級(jí)設(shè)計(jì)過程中處理 App 版本的一般套路。下面是一個(gè)典型的 OTA 設(shè)計(jì)中 NOR Flash 里內(nèi)容分布,最前面一般是 L2 OTA Boot,負(fù)責(zé)更新升級(jí)或者啟動(dòng) App;接下來是主 App 區(qū),就是真正實(shí)現(xiàn)產(chǎn)品功能的 App;然后是 Temp 區(qū),一般用作 App 更新臨時(shí)緩沖區(qū);最后是 User Data 區(qū),存放一些固定不變的圖片資源(如果有 GUI 的話),或者放一些動(dòng)態(tài)保存的系統(tǒng)關(guān)鍵數(shù)據(jù)。
這里面的 Temp 區(qū)設(shè)計(jì)是一個(gè)關(guān)鍵,如果沒有 Temp 區(qū),在 OTA 升級(jí)時(shí)只能原地覆蓋主 App 區(qū)(App 1),升級(jí)過程中一旦發(fā)生意外(比如斷電),系統(tǒng)里就沒有完整 App 可用了,會(huì)導(dǎo)致產(chǎn)品變磚。而有了 Temp 區(qū)作緩存,升級(jí)過程就會(huì)可靠多了,如下圖所示,新版本 App(App 2)首先會(huì)被放在 Temp 區(qū),僅當(dāng) App 2 完整性校驗(yàn)通過之后,才會(huì)從 Temp 區(qū)搬移到主 App 區(qū),搬移完成之后再擦除 Temp 區(qū)。這樣的設(shè)計(jì)下,即使 App 2 下載到 Temp 區(qū)或者 App 2 往 App 1 搬移時(shí)發(fā)生意外,系統(tǒng)里都有完整 App 用于恢復(fù)。
?
上面介紹的處理 App 版本的典型設(shè)計(jì)在實(shí)際應(yīng)用中其實(shí)不算特別常用,因?yàn)橄到y(tǒng)中僅存在一份最新的 App,其不支持版本回滾。有時(shí)候我們的新版本 App 因?yàn)橐恍┰颍ū热缧略龉δ苡?bug)導(dǎo)致運(yùn)行并不穩(wěn)定,我們希望能夠回退到上一個(gè)已經(jīng)運(yùn)行穩(wěn)定的舊版本 App,系統(tǒng)需要保留兩份不同版本 App,所以就有了如下改進(jìn)的 OTA 設(shè)計(jì) NOR Flash 內(nèi)容分布,在主 App 區(qū)(App 2)后面增加一個(gè)次 App 區(qū)(App 1)。
?
這時(shí)候升級(jí)過程稍微復(fù)雜一點(diǎn),如下圖所示,多了一步主 App 區(qū)(App 2)搬移到次 App 區(qū)(App 1)的過程(Step 2),這也是版本回滾的關(guān)鍵。不過萬事都是有代價(jià)的,版本回滾的代價(jià)就是增加了 OTA 升級(jí)的時(shí)間,以及將 Flash 中 App 區(qū)從兩段劃分成三段,導(dǎo)致 App 最大長(zhǎng)度減少了 1/3。
?
?
1.2 App 版本切換痛點(diǎn)
前面介紹了 OTA 升級(jí)設(shè)計(jì)中管理 App 版本的兩種方法,注意這里的 App 都是指在 FlexSPI NOR Flash 中原地執(zhí)行(XIP)的 App,代碼鏈接在芯片內(nèi)部 SRAM 或者外擴(kuò) RAM 的 App 不在討論范疇(這種 Non-XIP 屬性的 App 升級(jí)不存在版本切換的痛點(diǎn))?,F(xiàn)在聊 XIP App 版本切換的痛點(diǎn):
?
在上面的圖中你會(huì)發(fā)現(xiàn),新版本 App 最終都會(huì)被搬到主 App 區(qū)(就是緊接著 L2 OTA Boot 后面的第一個(gè) App 位置),為什么要這么做?這就涉及 MCU 中 App 鏈接相關(guān)知識(shí)了,因?yàn)?MCU 不同于 MPU,其沒有 MMU 組件,不支持虛擬內(nèi)存,所以 App 一般都是固定地址鏈接,App 代碼體二進(jìn)制數(shù)據(jù)僅放在鏈接的位置才可以正常執(zhí)行,將 App 拷貝到非鏈接位置是不能運(yùn)行的。OTA 升級(jí)中雖然 App 版本不同,但是這些 App 都有一個(gè)共同的鏈接地址,即都是鏈接在主 App 區(qū)的。
?
比如下圖 OTA 系統(tǒng)中使用了一塊 8MB 的 Flash,在 i.MXRT 里的系統(tǒng)映射起始地址是 0x60000000,L2 OTA Boot 和 User Data 各占 1MB,剩余 6MB 被均分成 3 段,那么 App x/2/1 都需要從 0x60100000 地址開始鏈接放中斷向量表。
?
?
可能你會(huì)說,我們也可以設(shè)計(jì)不同鏈接地址的 App,這樣就不需要將新版本 App 都往主 App 區(qū)搬移了,是的,原理上可以這么做,但實(shí)踐中,需要管理不同鏈接地址的 App,導(dǎo)致 OTA 升級(jí)上位機(jī)端操作比較復(fù)雜,容易出錯(cuò)(當(dāng)前待升級(jí)的 App 必須與上一次升級(jí)的 App 鏈接地址不同),因此這種方法不推薦。
?
所以最大的痛點(diǎn)就是 App 總要往主 App 區(qū)搬移,既增加了 OTA 升級(jí)時(shí)間,也因?yàn)榘嵋撇僮鬟^多減小了 Flash 的壽命(總擦寫次數(shù)是一定的)。
?
二、詳解 FlexSPI Remap 功能
2.1 FlexSPI NOR 系統(tǒng)映射地址
我們知道 FlexSPI 連接的 NOR Flash 能夠?qū)崿F(xiàn) XIP,最主要的原因是 FlexSPI 有對(duì)應(yīng)系統(tǒng)映射空間且 NOR Flash 自身可以按 Byte 地址訪問,這里的系統(tǒng)映射空間主要用于 AHB 方式讀。CPU 去從系統(tǒng)映射空間里讀 App 指令碼,F(xiàn)lexSPI 模塊會(huì)自動(dòng)將 AHB 總線傳來的地址數(shù)據(jù)請(qǐng)求轉(zhuǎn)換成 IPG 命令方式去獲取 NOR Flash 里的對(duì)應(yīng)指令內(nèi)容。
?
i.MXRT1060 中分配給 FlexSPI 的系統(tǒng)映射空間如下,兩個(gè) FlexSPI 一共分配了 496MB。
?
?
i.MXRT1010 中分配給 FlexSPI 的系統(tǒng)映射空間如下,一個(gè) FlexSPI 分配了 504MB。
?
?
2.2 FlexSPI Remap 功能設(shè)計(jì)
i.MXRT 中的 Remap 設(shè)計(jì)其實(shí)是系統(tǒng)架構(gòu)層面的,在 AHB 總線層面做一個(gè)地址重定向,并不是在 FlexSPI 模塊里實(shí)現(xiàn)的,這也是為什么 Remap 相關(guān)控制在 IOMUXC_GPR 寄存器里(設(shè)置后 Remap 立刻生效,但這些寄存器不是非易失性的,普通軟復(fù)位就會(huì)置位)。下面是 Remap 控制寄存器(對(duì)于含兩個(gè) FlexSPI 的型號(hào),Remap 控制是同時(shí)作用的):
?
Remap 功能 | 對(duì)應(yīng)控制寄存器 | |
---|---|---|
i.MXRT106x | i.MXRT1010 | |
ADDR_START | IOMUXC_GPR_GPR30 | IOMUXC_GPR_GPR27 |
ADDR_END | IOMUXC_GPR_GPR31 | IOMUXC_GPR_GPR28 |
ADDR_OFFSET | IOMUXC_GPR_GPR32 | IOMUXC_GPR_GPR29 |
?
Remap 設(shè)計(jì)說起來其實(shí)特別簡(jiǎn)單,就是地址(addr)落在[ADDR_START, ADDR_END]里的 AHB 訪問,其實(shí)際訪問到的是 addr + ADDR_OFFSET 位置處的數(shù)據(jù)。(注意 ADDR_START, ADDR_END, ADDR_OFFSET 都是 4KB 對(duì)齊的)
?
舉例來看,根據(jù) ADDR_OFFSET 的大小不同,會(huì)有三種情況:第一種是 ADDR_OFFSET = ADDR_END - ADDR_START,如下圖所示。這也是 OTA 中最常用的情況,ADDR_START 可設(shè)為主 App 區(qū)起始地址,ADDR_END 可設(shè)為次 App 區(qū)起始地址。
?
第二種是 ADDR_OFFSET > ADDR_END - ADDR_START,如下圖所示:
?
第三種是 ADDR_OFFSET < ADDR_END - ADDR_START,如下圖所示。不過這種情況在實(shí)際應(yīng)用中并不推薦。
?
?
2.3 Remap 對(duì)擦寫 Flash 的影響
啟用了 Remap 功能后,很多人會(huì)對(duì)調(diào)用 FlexSPI NOR 驅(qū)動(dòng)函數(shù)去擦寫 Flash 有點(diǎn)疑惑。其實(shí)完全不必要有這種疑惑,擦寫 Flash 操作走的是 FlexSPI IPG 命令方式,屬于 FlexSPI 模塊內(nèi)部的事情,完全不受上層系統(tǒng) Remap 功能影響,你可以就當(dāng) Remap 功能完全不存在,原來怎么做還是怎么做。
?
三、FlexSPI Remap 解決 OTA 痛點(diǎn)
有了 Remap 功能,現(xiàn)在再回到 OTA 設(shè)計(jì),此時(shí)我們只需要兩個(gè) App 分區(qū)即可。新版本 App(App 2)首先會(huì)被放在后 Temp 區(qū),App 2 更新完成且校驗(yàn)通過之后,直接使用 Remap 功能將 App 2 重映射到 App 1 位置,此舉既不增加額外物理搬移操作,也同時(shí)保留了新舊兩份 App 可以實(shí)現(xiàn)版本回滾,而且整個(gè) OTA 過程僅有一次 App 擦寫耗時(shí)也最短,完美解決痛點(diǎn)。
?
當(dāng) Remap 功能已被使能,再有新版本 App(App 3)更新需求時(shí),其需要被下載到前 Temp 區(qū),注意 Flash 擦寫操作都是通過 IPG 方式實(shí)現(xiàn),所以不受 Remap 功能干擾,僅需關(guān)注絕對(duì)物理地址偏移,App 下載完成,取消 Remap 功能即可,如此往復(fù)。
?
至此,i.MXRT 部分型號(hào)上新增的 FlexSPI Remap 功能痞子衡便介紹完畢了,掌聲在哪里~~~