大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是恩智浦i.MXRT系列MCU的ROM啟動(dòng)日志。
關(guān)于 i.MX RT 啟動(dòng)問(wèn)題解決的文章,痞子衡寫過(guò)非常多,其中大部分都是具體到某一類啟動(dòng)設(shè)備下的具體問(wèn)題分析,比較依賴經(jīng)驗(yàn),這些經(jīng)驗(yàn)當(dāng)然是非常有用的。此外也有一篇 《啟動(dòng)失敗先查看SRC_SBMRx寄存器》,這篇內(nèi)容通用于全部啟動(dòng)設(shè)備,算是葵花寶典系列了。
一直以來(lái)我們都當(dāng)芯片啟動(dòng) ROM 程序運(yùn)行狀態(tài)完全是個(gè)黑盒子,如果遇到異常,我們通常是去猜其可能遇到的問(wèn)題,那么能不能不全靠猜呢?答案是可以的!這便是痞子衡今天要聊 ROM 啟動(dòng)日志:
一、ROM啟動(dòng)日志原理
我們知道 i.MX RT 系列上電都是片內(nèi)固化的 ROM 程序代碼先運(yùn)行,由 ROM 來(lái)加載啟動(dòng)設(shè)備里的用戶程序去執(zhí)行,所以如果用戶程序不能正常啟動(dòng),一定是 ROM 程序執(zhí)行過(guò)程中遇到了異常。
i.MX RT 初始 ROM 代碼來(lái)源于它的老大哥 i.MX 處理器,翻看 i.MX 參考手冊(cè)其中有關(guān)于 ROM Log Event 功能的描述,所謂 ROM Log Event 就是 ROM 程序在執(zhí)行過(guò)程中將其重要節(jié)點(diǎn)事件(狀態(tài))按時(shí)間軸記錄到一個(gè)日志緩沖區(qū)里(日志緩沖區(qū)通常在片內(nèi) RAM 固定地址處),這個(gè)日志內(nèi)容顯然對(duì)于分析 ROM 執(zhí)行過(guò)程非常有用,那么 i.MX RT 系列 ROM 代碼里有沒有保留這個(gè)功能呢?很高興,它還在!
下表記錄了 i.MX RT 全系列型號(hào)的 ROM 啟動(dòng)日志緩沖區(qū)地址:
二、獲取ROM啟動(dòng)日志數(shù)據(jù)
上一節(jié)我們知道了 ROM 啟動(dòng)日志緩沖區(qū)存儲(chǔ)地址,獲取其數(shù)據(jù)的方法就簡(jiǎn)單了,可以直接連接上仿真器去讀取。不過(guò)這里有需要注意的地方:如果是在 ROM 跳轉(zhuǎn)用戶程序之前發(fā)生的異常(日志體現(xiàn)為啟動(dòng)失?。?,那么內(nèi)核 PC 應(yīng)該還停留在 ROM 空間,這時(shí)候 RAM 區(qū)數(shù)據(jù)是完整的,無(wú)人破壞。如果是在 ROM 跳轉(zhuǎn)到用戶程序之后發(fā)生的異常(日志體現(xiàn)為啟動(dòng)成功),這時(shí)候用戶程序已經(jīng)開始執(zhí)行了,這可能會(huì)破壞 RAM 區(qū)數(shù)據(jù)(如果用戶程序鏈接文件里用到了存儲(chǔ)啟動(dòng)日志的 RAM 區(qū)域),這時(shí)候啟動(dòng)日志內(nèi)容就不一定有效了。
以 i.MXRT1170 為例,痞子衡找了一塊開發(fā)板,上電后掛上 J-Link 調(diào)試器,使用 J-Link 命令行工具里的 SaveBin 命令從 0x2024ad78 地址處讀取最大的日志數(shù)據(jù)存儲(chǔ)到 bootlog.bin 文件中。這里需要注意在用 J-Link 連接目標(biāo)設(shè)備時(shí)盡量不要選 MCU 型號(hào),而用內(nèi)核 CORTEX-M7 代替,這樣可以防止選了 MCU 型號(hào)而自動(dòng)加載執(zhí)行相應(yīng)配套初始化腳本(萬(wàn)一腳本里有片內(nèi) RAM 相關(guān)操作破壞日志數(shù)據(jù))。
命令格式:SaveBin <filename>, <addr>, <NumBytes>
命令解釋:Save target memory range into binary file.
除了借助調(diào)試器,我們也可以借助芯片串行下載模式下配套的 MCUBoot 工具鏈(Flashloader+blhost)來(lái)獲取 ROM 日志數(shù)據(jù),具體可見 《MCUBootUtility v6.3發(fā)布,支持獲取與解析啟動(dòng)日志》 一文 2.3 小節(jié)里的途徑二。
三、解析ROM啟動(dòng)日志
i.MXRT 全系列 ROM 啟動(dòng)日志緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)并不是完全一樣的,主要分為兩個(gè)版本。其中 i.MXRT10xx 系列的日志結(jié)構(gòu)如下,跟 i.MX 處理器差不多,每條日志內(nèi)容壓縮存儲(chǔ)在一個(gè) uint32_t 型變量里,最大支持 64 條日志(當(dāng)實(shí)際日志超出 64 條時(shí),后面的日志直接被忽略不記)。
uint32_t?pu_irom_log_buffer[64];
而 i.MXRT11xx 系列以及 i.MXRTxxx 系列的日志結(jié)構(gòu)相比前一代有一些改進(jìn),其結(jié)構(gòu)如下,首先增加了 entryIndex 用于記錄有效的日志個(gè)數(shù),同時(shí)也增加了 checkSum 用于校驗(yàn)全部日志的完整性(但實(shí)際意義并不大,ROM 異常運(yùn)行時(shí)計(jì)算 checkSum 時(shí)機(jī)難以確定)。
typedef?struct?_log_context
{
????uint32_t?entryIndex;
????uint32_t?logEntries[64];
????uint32_t?checkSum;
}?log_context_t;
此時(shí)最大日志個(gè)數(shù)依舊是 64(當(dāng)實(shí)際日志超出 64 條時(shí),會(huì)找到日志緩存區(qū)里排在最后的狀態(tài)為 Fail 或者 Fatal 的日志,然后只保存其后面的正常日志并繼續(xù)向下記錄)。
舉例說(shuō)明:當(dāng)前記錄到了第 65 條日志
- 如果 logEntries[63:0] 里沒有 Fail 或者 Fatal 狀態(tài)的日志,那么清空數(shù)組,entryIndex 從 0 開始記錄。
- 如果 logEntries[31] 是排在最后的 Fail 或者 Fatal 狀態(tài)的日志,那么將 logEntries[63:32] 拷貝到 logEntries[31:0],entryIndex 重置為 32 再開始記錄。
除了以上啟動(dòng)日志緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)差別之外,i.MXRT10xx 與 i.MXRT11xx/i.MXRTxxx 在單條日志值定義上也是完全不同的,不過(guò)具體如何解析每條日志內(nèi)容,用戶無(wú)需過(guò)多關(guān)注,這在痞子衡開發(fā)的 MCUBootUtility v6.3 軟件里已經(jīng)全部搞定了,用戶可以直接查看解析后的日志結(jié)果。
還是繼續(xù)以 i.MXRT1170 為例查看解析后的日志結(jié)果,我們?cè)?FlexSPI1 連接的串行 NOR Flash 里下載一個(gè)能正常啟動(dòng)的 XIP 裸用戶程序(非簽名非加密),將芯片啟動(dòng)模式設(shè)為 2'b10,當(dāng)看到程序正常執(zhí)行后,掛上調(diào)試器讀出啟動(dòng)日志數(shù)據(jù)(確保日志存儲(chǔ)空間未被用戶程序破壞),并用 MCUBootUtility 軟件解析如下,還是能夠清晰地看到 ROM 執(zhí)行過(guò)程信息的。
至此,恩智浦i.MXRT系列MCU的ROM啟動(dòng)日志痞子衡便介紹完畢了,掌聲在哪里~~~