加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 一、引出调试问题
    • 二、什么是 Debug Mailbox?
    • 三、ROM 中 Debug Mailbox 实现
    • 四、激活 Debug Mailbox 的 JLink Script
    • 五、芯片调试模式(REQUEST = 0x07)下的状态
    • 六、Debug Mailbox 对 JLink 调试的影响
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

为何用JLink连接上这款MCU后PC指向0x1c04a?

2020/11/27
229
阅读需 18 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是 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 调试的影响:

  1. 当芯片在 ROM 中执行(比如 ISP 模式,比如 Flash 中没有应用程序)时,JLink 要想正常连接,必须加载使能芯片调试模式的 Script 才行,否则会连不上芯片。通过加载执行 JLink Script 成功连接上芯片后,PC 总是停在 0x1c04a,这是 Debug Mailbox 机制决定的。只有当芯片正常启动 Flash 里的应用程序后(即离开了 ROM),用 JLink 连接芯片(选择 CM33,不加载 Script),halt 住内核,PC 指向的才是真实的应用程序位置。

至此,i.MXRT600 中的 Debug Mailbox 实现对 JLink 调试的影响痞子衡便介绍完毕了,掌声在哪里~~~

相关推荐

电子产业图谱

硕士毕业于苏州大学电子信息学院,目前就职于恩智浦(NXP)半导体MCU系统部门,担任嵌入式系统应用工程师。痞子衡会定期分享嵌入式相关文章