大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是i.MXRT600中的Debug Mailbox實現對JLink調試的影響。
事情緣起痞子衡的同事 - 喜歡打破砂鍋問到底的Kerry小姐姐,她最近在研究i.MXRT600這款晶片,她發現在晶片ROM串行下載(ISP)模式下,連上晶片USB埠可以在設備管理器中正常看到枚舉的HID設備(0x1fc9,0x0020),這個HID設備可配合上位機工具blhost.exe進行應用程式下載。但是當使用JLink正常連上晶片(選擇的是MIMXRT685,不是CM33)後,之前的那個HID設備不見了,看起來晶片像是退出了ROM正常運行,這個體驗跟i.MXRT1050上不太一樣,這是為什麼?這其實是Debug Mailbox在搗鬼,且聽痞子衡細聊:
一、引出調試問題
按照我們之前在i.MXRT1050上的調試經驗,將晶片設為串行下載模式後,使用JLink連接上晶片,並halt住內核,此時晶片PC是正常停在ROM區域的(0x200000之後),讓我們同樣的過程在i.MXRT600上也操作一次:
我們發現PC指向了0x1c04a,並且不管你如何reset再重新halt,它一直停在這個地方,更奇怪的是這個地方不在ROM區域(0x03000000或0x13000000之後)裡,這是怎麼回事?
二、什麼是Debug Mailbox?
與i.MXRT1050不同的是,i.MXRT600中引入了Debug Mailbox機制,這個機制由ROM負責實現,因此連接上JLink後的行為是由Debug Mailbox機制決定的。
翻開i.MXRT600的User Manual,在Debug subsystem這一章節可以找到Debug Mailbox相關信息,Debug Mailbox其實最早是NXP LPC系列新推的一項功能,後來也用在了i.MXRT600上面。
下圖是i.MXRT600的SWD調試系統內部連接圖,其中藍框標出的DM AP便是Debug Mailbox。
我們知道i.MXRT600是基於Cortex-M33內核的MCU,這款ARM內核主打特點是安全,因此NXP在設計晶片時也加入了很多安全方面的特性,Debug Mailbox便是其一,Debug Mailbox基於NXP debug authentication protocol version 1.0,主要作用是實現外部調試器與晶片內ROM的通信,從而賦予調試器擦寫Flash、進入ROM ISP、調試認證等功能。
三、ROM中Debug Mailbox實現
那麼ROM中的Debug Mailbox機制到底是什麼?簡單理解就是如下一段代碼插入了ROM的初始化流程。這個機制其實很簡單,就是確保debug特性是正常開啟的,然後根據晶片復位類型來初始化debug port並決定要不要進入Mailbox命令處理。
// 確認IFR裡debug特性正常開啟if (kStatus_DBG_Success != debug_auth_evaluate_dcfg_socu()){ __set_FAULTMASK(1); __WFI();}volatile uint32_t reset_status = RSTCTRL0->SYSRSTSTAT;// 根據復位類型設置初始debug port狀態if (kStatus_DBG_Success != debug_auth_hal_set_initial_debug_port_state(reset_status)){ __set_FAULTMASK(1); __WFI();}if (reset_status & 0x20){ // 處理mailbox收到的來自debugger的命令 debug_mailbox_GetRequest();} RSTCTRL0->SYSRSTSTAT[5]位即ARM_APD_RESET,表明ARM內核是否發生了軟復位(warm reset),正常晶片上電,這個位不會被置1,但是如果有調試器接入給內核發軟復位,這個位就會被置位。一旦這個位被置起來,ROM初始化過程中便會進入Mailbox命令處理函數debug_mailbox_GetRequest(),不再往後執行正常的ROM串行下載/啟動流程。
debug_mailbox_GetRequest()函數是Debug Mailbox機制的核心,它藉助的是如下三個Mailbox寄存器來實現調試器與ROM的互動。
CSW:命令狀態寄存器,調試器操作這個寄存器指示ROM進入mailbox命令解析狀態REQUEST:請求寄存器,調試器將mailbox命令寫入這個寄存器指示ROM去執行RETURN:結果寄存器,調試器通過讀這個寄存器獲取ROM執行mailbox命令結果
對於使用者來說,一般藉助調試器先向CSW寄存器寫入0x21申請re-sync同時reset device ,然後再按需寫入如下具體的命令進REQUEST寄存器,便可實現Debug Mailbox相應功能。
#define ENTER_DEBUGGER_MAILBOX (0x0001) // Start Mailbox debug#define GET_CRP_LEVEL (0x0002) // Deprecated and retuen 3#define DM_ERASE_FLASH (0x0003) // Mass erase flash#define EXIT_DEBUGGER_MAILBOX (0x0004) // Exit Mailbox debug#define ENTER_ISP_MODE (0x0005) // Enter specified ISP mode#define SET_FA_MODE (0x0006) // Set to "Fault Analysis" mode#define START_DEBUG_SESSION (0x0007) // Start Debug session#define DEBUG_AUTH_START (0x0010) // Start Debug Authentication Protocol#define DEBUG_AUTH_RESP (0x0011) // Debug Authentication response四、激活Debug Mailbox的JLink Script
了解了Debug Mailbox機制原理,我們再來看JLink連接i.MXRT600時必須要加載執行的如下Script內容(開頭痞子衡說了必須選擇MIMXRT685,而不是CM33,因為在JLink DLL / JLinkDevices.xml裡MIMXRT685才默認指定了配套Script腳本)。關於JLink Script知識,可以先看痞子衡之前文章 《JLink Script文件基礎及其在IAR下調用方法》。
這個腳本內容其實在i.MXRT600的User Manual中已經給出了相應偽代碼,通過調用JLINK_CORESIGHT_WriteAP()來寫Mailbox寄存器(index 0對應CSW,index 1對應REQUEST),基本是按照前面介紹的Debug Mailbox使用流程來的,最後通過寫入START_DEBUG_SESSION命令進REQUEST寄存器開啟晶片調試模式。
void InitTarget(void) { int v; JLINK_CORESIGHT_Configure("IRPre=0;DRPre=0;IRPost=0;DRPost=0;IRLenDevice=4"); // Pre-select that we have a Cortex-M33 connected CPU = CORTEX_M33; // J-Link is allowed to use a TAP reset for JTAG-chain auto-detection JTAG_AllowTAPReset = 0; JTAG_SetDeviceId(0, 0x6BA02477); // Read AP ID register to identify DM AP at index 2 JLINK_CORESIGHT_WriteDP(2, 0x020000f0); v = JLINK_CORESIGHT_ReadAP(3); JLINK_SYS_Report1("DAP-IDCODE:", v); // Select DM AP index 2 JLINK_CORESIGHT_WriteDP(2, 0x02000000); JLINK_CORESIGHT_ReadDP(0); // Active DebugMailbox JLINK_CORESIGHT_WriteAP(0, 0x21); JLINK_CORESIGHT_ReadAP(0); // Enter Debug Session JLINK_CORESIGHT_WriteAP(1, 0x07); JLINK_CORESIGHT_ReadAP(0);}五、晶片調試模式(REQUEST = 0x07)下的狀態
前面講了JLink Script會使晶片進入調試模式,那調試模式下晶片到底是什麼狀態?ROM其實是通過如下函數加載執行了0x1c040 - 0x1c04B處的一小段代碼,並最終停在了0x1c04a處的while(1);,至此真相大白。
void go_debug_mode(void){#define VECTOR_DUMMY_ROUTINE 0x0001c000u#define APP_ENTRY (VECTOR_DUMMY_ROUTINE + 0x40 + 1) uint32_t dummy_loop_routines[] = { VECTOR_DUMMY_ROUTINE + 0x1000, // SP APP_ENTRY, // Reset Handler APP_ENTRY, // NMI Handler APP_ENTRY, // HardFault_Handler APP_ENTRY, // MemManage_Handler APP_ENTRY, // BusFault_Handler APP_ENTRY, // UsageFault_Handler APP_ENTRY, // SecureFault_Handler 0, // Reserved 0, // Reserved 0, // Reserved APP_ENTRY, // SVC_Handler APP_ENTRY, // DebugMon_Handler 0, // Reserved APP_ENTRY, // PendSV_Handler APP_ENTRY, // SysTick_Handler // Below are the binary codes for : // register uint32_t dummy = SCB->CPUID; // while(1); 0x5000f64eu, 0x0000f2ceu, 0xe7fe6801u, }; { uint32_t *dest = (uint32_t *)VECTOR_DUMMY_ROUTINE; uint32_t *src = (uint32_t *)&dummy_loop_routines[0]; for (uint32_t i = 0u; i < ARRAY_SIZE(dummy_loop_routines); i++) { *dest++ = *src++; } jump_to_boot_image(VECTOR_DUMMY_ROUTINE); }}六、Debug Mailbox對JLink調試的影響
基於上面分析,最後痞子衡再總結一下Debug Mailbox對JLink調試的影響:
當晶片在ROM中執行(比如ISP模式,比如Flash中沒有應用程式)時,JLink要想正常連接,必須加載使能晶片調試模式的Script才行,否則會連不上晶片。通過加載執行JLink Script成功連接上晶片後,PC總是停在0x1c04a,這是Debug Mailbox機制決定的。只有當晶片正常啟動Flash裡的應用程式後(即離開了ROM),用JLink連接晶片(選擇CM33,不加載Script),halt住內核,PC指向的才是真實的應用程式位置。
至此,i.MXRT600中的Debug Mailbox實現對JLink調試的影響痞子衡便介紹完畢了,掌聲在哪裡~~~
歡迎訂閱
文章會同時發布到我的 博客園主頁、CSDN主頁、知乎主頁、微信公眾號 平臺上。
微信搜索"痞子衡嵌入式"或者掃描下面二維碼,就可以在手機上第一時間看了哦。