痞子衡嵌入式:飛思卡爾i.MX RT系列微控制器啟動篇(3)- Serial Downloader模式(sdphost/mfgtool)
大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾i.MX RT系列MCU的Serial Downloader模式。
在上一篇文章 飛思卡爾i.MX RT系列微控制器啟動篇(2)- Boot配置(BOOT Pin, eFUSE) 裏痞子衡為大家介紹了i.MXRT Boot的行為配置,其中第一節裏講了Boot有三種行為模式:Serial Downloader、Boot From Fuses、Internal Boot,後兩種是核心的加載啟動行為模式,而Serial Downloder看起來是個次要的模式,那麽Serial Downloader模式到底有什麽用?今天痞子衡就來詳細聊一聊Serial Downloader模式。
痞子衡在前面已經講過Serial Downloader模式是一種串行下載模式,在這種模式下,BootROM通過指定的USB或者UART口來接收來自Host(恩智浦提供了上位機工具sdphost.exe或者mfgtool)的Flashloader數據,並將數據存儲在SRAM中執行,Flashloader程序可以用來將你的Application下載進i.MXRT支持的所有外部非易失性存儲器中,為後續從外部存儲器啟動做準備。
一、進入Serial Downloader模式
i.MXRT上電永遠是從ROM啟動去執行BootROM程序,最頂層的Boot行為模式由BOOT_MODE[1:0] pins的狀態決定,想進入Serial Downloader模式最直接的方式便是將BOOT_MODE[1:0]輸入狀態撥成2‘b01,在設計i.MXRT的硬件板時BOOT_MODE[1:0] pins應設計成可通過撥碼開關選擇輸入電平,下圖是RT1052硬件板的參考設計:
撥碼開關SW5應撥向SW_DIP-8的8和10,即設置BOOT_MODE[1:0]=2‘b01,此時便直接進入了Serial Downloader模式。
當然如果SW5不按上面這麽設置,也有可能進入Serial Downloader模式,但是需要其他前提條件,即Boot From Fuses/Internal Boot模式下從Boot Device加載啟動失敗。
二、sdphost/mfgtool的使用
進入了Serial Downloader模式,此時便可以用恩智浦提供的host工具與BootROM進行命令交互,host工具在 Flashloader包 裏。
下載好Flashloader包之後,在\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools下可以找到所有host工具,其中用於與BootROM通信的有兩個:sdphost.exe與MfgTool2.exe。
2.1 支持的通信外設pinout
BootROM支持兩種通信外設,分別是USB-HID和UART,pinout如下(Pinout適用RT105x和RT102x):
Peripheral | Instance | PAD | Port | Mode |
---|---|---|---|---|
USB | OTG1 | USB_OTG1_DN | / | / |
USB_OTG1_DP | ||||
USB_OTG1_VBUS | ||||
LPUART | 1 | GPIO_AD_B0_12 | LPUART1_TX | ALT2 |
GPIO_AD_B0_13 | LPUART1_RX | ALT2 |
2.2 sdphost用法
sdphost.exe是命令行工具,使用sdphost既可以通過UART口也可以通過USB口與BootROM進行通信與命令交互。
在命令行下打開sdphost.exe,輸入-?命令可以看到sdphost使用幫助,下面痞子衡把核心的7條命令整理如下:
工具 | 接口格式 | 命令格式 | 命令解釋 |
---|---|---|---|
sdphost | [-p|--port < name>[,< speed>]] [-u|--usb [[[< vid>,]< pid>]]] | -- read-register < addr> [< format> [< count> [< file>]]] | 讀指定AIPS外設寄存器值 |
-- write-register < addr> < format> < data> | 寫值進指定AIPS外設寄存器 | ||
-- write-file < addr> < file> [< count>] | 寫image文件數據進指定SRAM地址 | ||
-- error-status | 返回上條命令的執行狀態 | ||
-- dcd-write < addr> < file> | 寫DCD table進指定SRAM地址 | ||
-- skip-dcd-header | 忽略image文件中的DCD table | ||
-- jump-address < addr> | 跳轉執行含IVT頭的image |
當使用串口轉USB模塊連接i.MXRT的LPUART1或者使用USB Cable連接上USB_OTG1口後可以看到PC設備管理器會識別出相關設備:
讓我們嘗試一下使用sdphost與BootROM通信,先試一下USB通信:
PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT10501050_1.1\Tools\sdphost\win> .\sdphost.exe -u 0x1fc9,0x0130 -- error-status
Status (HAB mode) = 1450735702 (0x56787856) HAB disabled. Reponse Status = 858993459 (0x33333333) HAB failure.
再接著試一下UART通信,似乎通信失敗了。需要註意的是,當使用USB通信過一次之後,BootROM已經激活USB外設,不會再去檢測UART外設,如果想使用UART通信,需要將板子reset一次,使BootROM重回外設檢測狀態。
PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT10501050_1.1\Tools\sdphost\win> .\sdphost.exe -p COM19 -- error-status
getStatusResponse.readPacket error 5. Status (HAB mode) = 10004 (0x2714) No response from device.
關於sdphost其他命令具體如何組合使用,痞子衡會在後續的文章裏再具體介紹。
2.3 mfgtool用法
MfgTool2.exe是GUI工具,其實際上是在sdphost工具基礎上做了一層圖形化封裝,但功能上有一些削減,並且使用MfgTool2.exe僅能通過USB口與BootROM進行通信。
如果板子不連USB Cable,直接打開MfgTool2.exe,可看到如下界面,顯示"No Device Connected"。
當板子連上USB Cable後可以看到狀態變為"HID-compliant vendor-defined device",這表明軟件已可以正常使用。
從軟件界面來看,似乎能控制的只有2個按鈕:Start和Exit,那到底如何使用這個軟件,其實秘密藏在如下兩個配置文件裏:
\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel\cfg.ini
\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel\Profiles\MXRT105X\OS Firmware\ucl2.xml
cfg.ini文件用於指定GUI工具工作平臺與模式(默認為chip = MXRT105X和name = MXRT105X-DevBoot),而ucl2.xml文件包含了不同模式的具體實現。以MXRT105x-DevBoot模式來說,點擊Start按鈕後,GUI會使用sdphost.exe與BootROM建立通信,首先用write-file命令將ivt_flashloader.bin文件下載進SRAM(地址是固定的0x20000000),然後使用jump-address命令跳轉到Flashloader程序中去執行(Stage 1),GUI繼續使用blhost.exe與Flashloader建立通信,先用get-property 1命令測試連接,然後使用receive-sb-file命令接收boot_image.sb文件。
<LIST name="MXRT105x-DevBoot" desc="Manufacturing with Flashloader">
<!-- Stage 1, load and execute Flashloader -->
<CMD state="BootStrap" type="boot" body="BootStrap" file="ivt_flashloader.bin" > Loading Flashloader. </CMD>
<CMD state="BootStrap" type="jump" onError = "ignore"> Jumping to Flashloader. </CMD>
<!-- Stage 2, Program boot image into external memory using Flashloader -->
<CMD state="Blhost" type="blhost" body="get-property 1" > Get Property 1. </CMD> <!--Used to test if flashloader runs successfully-->
<CMD state="Blhost" type="blhost" timeout="15000" body="receive-sb-file \"Profiles\\MXRT105X\\OS Firmware\\boot_image.sb\"" > Program Boot image </CMD>
<CMD state="Blhost" type="blhost" body="Update Completed!">Done</CMD>
</LIST>
關於blhost與sb文件的用法,痞子衡會在後續的文章裏再具體介紹。
三、啟動Flashloader程序
啟動Flashloader是Serial Downloader模式的核心任務,其實在上一節mfgtool工具介紹裏,大家已經看見了Flashloader的身影,但是GUI工具將Flashloader的啟動操作封裝得不太直觀,這裏痞子衡用sdphost為大家直觀地再現一遍啟動Flashloader的過程。
在\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Flashloader目錄下,有Flashloader的可執行文件(.elf格式和.srec格式),但是sdphost僅能處理純image數據文件(.bin格式),可使用IAR EWARM自帶的ielftool.exe工具將elf文件轉換成bin文件(命令為: ielftool --bin flashloader.elf flashloader.bin)。
得到flashloader.bin文件後,便可使用sdphost的write-file命令將flashloader.bin下載進SRAM,並且使用jump-address命令跳轉到Flashloader程序中,但還需要解決兩個問題:
第一個問題,該把flashloader.bin文件下載進SRAM的什麽地址?其實這裏的SRAM地址即是Flashloader程序的中斷向量表所在地址,這個地址包含在elf文件裏,可用專門的elf文件分析工具得到。也可以通過查看.srec或者.hex文件得到,由於包裏自帶了.srec文件,我們直接用文本編輯器打開.srec文件,可以得知這個地址是0x20002000。
S0130000666C6173686C6F616465722E737265638C
S31520002000705A2120914B01207B240020952E0120FF
讓我們開始將flashloader.bin下載進SRAM的0x20002000地址處:
PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT10501050_1.1\Tools\sdphost\win> .\sdphost.exe -u 0x1fc9,0x0130 -- write-file 0x20002000 ..\..\..\Flashloader\flashloader.bin
Preparing to send 81847 (0x13fb7) bytes to the target. (1/1)1%Status (HAB mode) = 1450735702 (0x56787856) HAB disabled. Reponse Status = 2290649224 (0x88888888) Write File complete.
第二個問題,如何使用jump-address命令跳轉到Flashloader程序中?痞子衡在前面sdphost命令列表裏介紹過,jump-address只能跳轉到含IVT頭的image,現在image本身已經有了,但是IVT頭是什麽?用二進制編輯器打開\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\mfgtools-rel\Profiles\MXRT105X\OS Firmware\ivt_flashloader.bin文件,可以發現除了前2KB之外的其他數據跟我們生成的flashloader.bin是一樣的,那麽IVT就藏在前2KB數據裏,仔細看一下,你會發現除了偏移0x400的位置處有一些數據外,其余都是0,是的IVT就在那裏。
offset(h)
00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
000003F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000400: D1 00 20 40 91 4B 01 20 00 00 00 00 00 00 00 00
00000410: 20 04 00 20 00 04 00 20 00 00 00 00 00 00 00 00
00000420: 00 00 00 20 B7 5F 01 00 00 00 00 00 00 00 00 00
00000430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
00001FF0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00002000: 70 5A 21 20 91 4B 01 20 7B 24 00 20 95 2E 01 20
00002010: 7B 24 00 20 7B 24 00 20 7B 24 00 20 00 00 00 00
...
00015FB0: 03 80 FF 71 00 70 08 -- -- -- -- -- -- -- --
你可能會疑問,真正有用的IVT數據只有幾十個字節,為什麽ivt_flashloader.bin文件會留出2KB的空間來放IVT?這得分析IVT本身才能知道答案,讓我們來嘗試解析IVT,IVT的原型是如下的hab_ivt_v0結構體,一共32個byte,對應的是偏移0x400 - 0x41F處的數據,hab_ivt_v0.self = 0x20000400,由於此處self成員指定的IVT地址是0x20000400,而Flashloader本身地址是0x20002000,bin文件本身並不含地址信息數據,所以只能用0來填充占位以保證IVT數據與Flashloader數據的相對位置關系,這就是0x430 - 0x1FFF全是0的原因。hab_ivt_v0.boot_data =0x20000420,指明了boot data數據在0x420 - 0x42b處,boot_data結構體原型如下,一共12個byte,boot_data.start = 0x20000000,指明boot data應從0x20000000處開始存放,所謂boot data即IVT和image的統稱,看到這,你應該明白了0x0 - 0x3FF處為何全是0的原因了吧。
#define HAB_TAG_IVT0 0xd1 /**< Image Vector Table V0 */
/** @ref hab_header structure */
typedef struct hab_hdr {
uint8_t tag; /**< Tag field */
uint8_t len[2]; /**< Length field in bytes (big-endian) */
uint8_t par; /**< Parameters field */
} hab_hdr_t;
/** @ref ivt structure */
struct hab_ivt_v0 {
/** @ref hdr with tag #HAB_TAG_IVT0, length and HAB version fields */
hab_hdr_t hdr;
/** Absolute address of the first instruction to execute from the image */
uint32_t entry;
/** Reserved in this version of HAB: should be NULL. */
uint32_t reserved1;
/** Absolute address of the image DCD: may be NULL. */
uint32_t dcd;
/** Absolute address of the Boot Data: may be NULL, but not interpreted any further by HAB */
uint32_t boot_data;
/** Absolute address of the IVT.*/
uint32_t self;
/** Absolute address of the image CSF.*/
uint32_t csf;
/** Reserved in this version of HAB: should be zero. */
uint32_t reserved2;
};
/** @ref boot_data structure */
typedef struct boot_data{
uint32_t start; /* Start address of the image */
uint32_t size; /* Size of the image */
uint32_t plugin; /* Plugin flag */
} BOOT_DATA_T;
既然ivt_flashloader.bin文件裏的前2KB有很多冗余數據,那不妨我們只把有效數據(IVT和boot data,0x400 - 0x42d處共44個byte)提取出來放到ivt_bootdata.bin文件裏,讓我們將ivt_bootdata.bin下載進SRAM的0x20000400地址處:
PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT10501050_1.1\Tools\sdphost\win> .\sdphost.exe -u 0x1fc9,0x0130 -- write-file 0x20000400 ..\..\..\Flashloader\ivt_bootdata.bin
Preparing to send 44 (0x2c) bytes to the target. (1/1)100% Completed! Status (HAB mode) = 1450735702 (0x56787856) HAB disabled. Reponse Status = 2290649224 (0x88888888) Write File complete.
到這裏IVT和image均已經下載進SRAM了,可以跳轉去執行Flashloader程序了,使用jump-address命令:
PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT10501050_1.1\Tools\sdphost\win> .\sdphost.exe -u 0x1fc9,0x0130 -- jump-address 0x20000400
Status (HAB mode) = 1450735702 (0x56787856) HAB disabled.
至此,Flashloader就算啟動完成了,jump-address命令執行完成之後,你會發現USB設備被重新枚舉了,此時新枚舉的USB-HID設備是Flashloader裏的通信外設。
如果你試著用blhost與Flashloader通信得到如下結果,恭喜你,Flashloader已被成功啟動了。
PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT10501050_1.1\Tools\sdphost\win> .\blhost.exe -u 0x15a2,0x0073 -- get-property 1
Inject command 'get-property' Response status = 0 (0x0) Success. Response word 1 = 1258422528 (0x4b020100) Current Version = K2.1.0
至此,飛思卡爾i.MX RT系列MCU的Serial Downloader模式痞子衡便介紹完畢了,掌聲在哪裏~~~
痞子衡嵌入式:飛思卡爾i.MX RT系列微控制器啟動篇(3)- Serial Downloader模式(sdphost/mfgtool)