zoukankan      html  css  js  c++  java
  • 痞子衡嵌入式:揭秘i.MXRT600的ISP模式下用J-Link连接后PC总是停在0x1c04a的原因(Debug Mailbox)


      大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是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连接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才行,否则会连不上芯片。
    2. 通过加载执行JLink Script成功连接上芯片后,PC总是停在0x1c04a,这是Debug Mailbox机制决定的。
    3. 只有当芯片正常启动Flash里的应用程序后(即离开了ROM),用JLink连接芯片(选择CM33,不加载Script),halt住内核,PC指向的才是真实的应用程序位置。

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

    欢迎订阅

    文章会同时发布到我的 博客园主页CSDN主页知乎主页微信公众号 平台上。

    微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

  • 相关阅读:
    事件处理之二:点击事件监听器的五种写法 分类: H1_ANDROID 2013-09-11 10:32 4262人阅读 评论(1) 收藏
    如何解决安卓SDK无法下载Package的问题 分类: H1_ANDROID 2013-09-09 10:26 1199人阅读 评论(0) 收藏
    adb常用命令 分类: H1_ANDROID 2013-09-08 15:22 510人阅读 评论(0) 收藏
    用IBM WebSphere DataStage进行数据整合: 第 1 部分 分类: H2_ORACLE 2013-08-23 11:20 688人阅读 评论(0) 收藏
    三大主流ETL工具选型 分类: H2_ORACLE 2013-08-23 11:17 426人阅读 评论(0) 收藏
    ETL概述 分类: H2_ORACLE 2013-08-23 10:36 344人阅读 评论(0) 收藏
    POI操作Excel常用方法总结 分类: B1_JAVA 2013-08-23 10:01 349人阅读 评论(0) 收藏
    段的创建表user_segments 分类: H2_ORACLE 2013-08-10 11:13 714人阅读 评论(0) 收藏
    让android项目支持boost 支持c++11
    unity中全屏背景图缩放
  • 原文地址:https://www.cnblogs.com/henjay724/p/14027404.html
Copyright © 2011-2022 走看看