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


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

  在上一篇文章 Boot配置(BOOT Pin, eFUSE) 裏痞子衡爲你們介紹了i.MXRT Boot的行爲配置,其中第一節裏講了Boot有三種行爲模式:Serial Downloader、Boot From Fuses、Internal Boot,後兩種是核心的加載啓動行爲模式,而Serial Downloder看起來是個次要的模式,那麼Serial Downloader模式到底有什麼用?今天痞子衡就來詳細聊一聊Serial Downloader模式。app

  痞子衡在前面已經講過Serial Downloader模式是一種串行下載模式,在這種模式下,BootROM經過指定的USB或者UART口來接收來自Host(恩智浦提供了上位機工具sdphost.exe或者mfgtool)的Flashloader數據,並將數據存儲在SRAM中執行,Flashloader程序能夠用來將你的Application下載進i.MXRT支持的全部外部非易失性存儲器中,爲後續從外部存儲器啓動作準備。編輯器

1、進入Serial Downloader模式

  i.MXRTyyyy上電永遠是從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加載啓動失敗。測試

2、sdphost/mfgtool的使用

  進入了Serial Downloader模式,此時即可以用恩智浦提供的host工具與BootROM進行命令交互,host工具在 Flashloader包 裏。ui

  下載好Flashloader包以後,在\Flashloader_i.MXRT1050_GA\Flashloader_RT1050_1.1\Tools下能夠找到全部host工具,其中用於與BootROM通訊的有兩個:sdphost.exe與MfgTool2.exe。this

2.1 支持的通訊外設pinout

  BootROM支持兩種通訊外設,分別是USB-HID和UART,pinout以下(Pinout適用RT105x和RT102x):spa

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設備管理器會識別出相關設備:設計

  讓咱們嘗試一下使用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"。

  當板子連上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文件的用法,痞子衡會在後續的文章裏再具體介紹。

3、啓動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裏的通訊外設。

  若是你試着用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 RTyyyy系列MCU的Serial Downloader模式痞子衡便介紹完畢了,掌聲在哪裏~~~

相關文章
相關標籤/搜索