痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

痞子衡發表於2018-05-27

  大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是飛思卡爾i.MX RT系列MCU的Serial Downloader模式

  在上一篇文章 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硬體板的參考設計:

痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

  撥碼開關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包 裡。

痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

  下載好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條命令:

PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\sdphost\win> .\sdphost.exe -?
usage: C:\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\sdphost\win\sdphost.exe
                       [-?|--help]
                       [-p|--port <name>[,<speed>]]
                       [-u|--usb [[[<vid>,]<pid>]]]
                       [-t|--timeout <ms>]
                       -- command <args...>

Options:
  -?/--help                    Show this help
  -p/--port <name>[,<speed>]   Connect to target over UART. Specify COM port
                               and optionally baud rate
                                 (default=COM1,115200)
                                 If -b, then port is BusPal port
  -u/--usb [[[<vid>,]<pid>] | [<path>]]
                               Connect to target over USB HID device denoted by
                               vid/pid (default=0x15a2,0x0083) or device path
  -t/--timeout <ms>            Set packet timeout in milliseconds
                                 (default=5000)
Commands:
  // 讀指定AIPS外設暫存器值
  read-register <addr> [<format> [<count> [<file>]]]
                               Read one or more registers at address.
                               Format must be 8, 16, or 32;
                                 default format is 32.
                               Count is number of bytes to read;
                                 default count is sizeof format
                                 (i.e. one register).
                               Output file is binary;
                                 default is hex display on stdout.
  // 寫值進指定AIPS外設暫存器
  write-register <addr> <format> <data>
                               Write one register at address.
                               Format must be 8, 16, or 32.
                               Data is data value to write.
  // 寫image檔案資料進指定SRAM地址
  write-file <addr> <file> [<count>]
                               Write file at address.
                               Count is size of data to write in bytes;
                                 size of file will be used by default.
  // 返回上條命令的執行狀態
  error-status                 Read error status of last command.
  // 寫DCD table進指定SRAM地址
  dcd-write <addr> <file>      Send DCD table from file.
                                 <addr> must point to a valid
                                   temporary storage area.
  // 忽略image檔案中的DCD table
  skip-dcd-header              Ignore DCD table in image.
  // 跳轉執行含IVT頭的image
  jump-address <addr>          Jump to entry point of image
                                   with IVT at specified address.

  當使用串列埠轉USB模組連線i.MXRT的LPUART1或者使用USB Cable連線上USB_OTG1口後可以看到PC裝置管理器會識別出相關裝置:

痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

  讓我們嘗試一下使用sdphost與BootROM通訊,先試一下USB通訊:

PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_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_RT1050_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"。

痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

  當板子連上USB Cable後可以看到狀態變為"HID-compliant vendor-defined device",這表明軟體已可以正常使用。

痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

  從軟體介面來看,似乎能控制的只有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_RT1050_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就藏在前8KB資料裡,仔細看一下,你會發現除了偏移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檔案會留出8KB的空間來放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檔案裡的前8KB有很多冗餘資料,那不妨我們只把有效資料(IVT和boot data,0x400 - 0x42d處共44個byte)提取出來放到ivt_bootdata.bin檔案裡,讓我們將ivt_bootdata.bin下載進SRAM的0x20000400地址處:

PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_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的關係才分步將自己建立的flashloader.bin和ivt_bootdata.bin下載進SRAM,其實你可以直接將Flashloader包裡現成的ivt_flashloader.bin下載進SRAM即可:

PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\sdphost\win> .\sdphost.exe -u 0x1fc9,0x0130 -- write-file 0x20000000 ..\..\mfgtools-rel\Profiles\MXRT105X\OS Firmware\ivt_flashloader.bin

Preparing to send 90039 (0x15fb7) bytes to the target.
(1/1)1%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_RT1050_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裡的通訊外設。

痞子衡嵌入式:飛思卡爾i.MX RT系列MCU啟動那些事(3)- Serial Downloader模式(sdphost/MfgTool)

  如果你試著用blhost與Flashloader通訊得到如下結果,恭喜你,Flashloader已被成功啟動了。

PS C:\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools\blhost\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模式痞子衡便介紹完畢了,掌聲在哪裡~~~

相關文章