通过UART调试ARM Cortex-M微控制器

在本文中,我将告诉您如何在基于ARM Cortex-M内核构建的微控制器中使用调试寄存器和断点

介绍


您是否知道微控制器中的ARM Cortex-M内核可以调试自己?
事实证明他们可以。

通过阅读Cortex M3内核上的技术参考手册》,我发现它具有DebugMon中断。接下来,我分析了与之关联的所有寄存器。结果,我发现如果PC寄存器和FP_COMP寄存器之一相等,MK可能会陷入该中断。
这意味着我们可以在调试的固件中设置断点。您也可以通过将DEMCR寄存器的MON_PEND位置1来强制DebugMon中断。

理论检查


由于这些寄存器存在于整个ARM Cortex-M内核系列中,因此我们采用了第一个调试板。原来对我来说是stm32f723e-disco。为了不浪费时间为外设编写初始化代码,我们使用CubeMX。
从外设中,我们只需要将UART6连接到ST-Link和板上的LED:

CubeMX中的设置
image

我们生成项目并立即打开其IDE。

为了避免混淆与调试相关的寄存器,我们立即在代码中引入它们的定义:

注册定义
#define DHCSR (*(uint32_t*)0xE000EDF0)
#define DCRSR (*(uint32_t*)0xE000EDF4)
#define DCRDR (*(uint32_t*)0xE000EDF8)
#define DEMCR (*(uint32_t*)0xE000EDFC)

#define NUMOFBKPTS 8

typedef struct {
  uint32_t FP_CTRL;
  uint32_t FP_REMAP;
  uint32_t FP_COMP[NUMOFBKPTS];
} fp_t;

#define FP ((fp_t*)0xE0002000)


为验证我们的项目正常工作,请编写一个带有LED闪烁的代码:

LED闪烁
  while (1)
  {
    for (int i=0;i<1000000;i++)
      asm("nop");
    
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_7);
  }


LED成功闪烁,表示项目已成功编译并启动。

将行添加到此循环:

asm("BKPT #0");

该汇编器插件是一个软件断点。现在,通过ST-Link进行调试时,程序将始终在此行停止。我们在IDE中退出Debug,并且LED像以前一样开始闪烁。

但是它给了我们什么?

而且我们可以通过中断DebugMon来捕获断点。

我们编写其处理程序:

DebugMon处理程序
void DebugMon_Handler(void)
{
  while (1)
  {
    if ((USART6->ISR & USART_ISR_TXE) != 0U)
    {
      USART6->TDR = '!';
    }
  }
}


我们编译,刷新,没有任何变化。要启用DebugMon中断,您需要提高DEMCR寄存器中的MON_EN位。

现在,通过ST-Link调试时,该程序将像以前一样在此行停止。一旦退出调试模式,感叹号将出现在终端中:

终端输出
image

接下来,使用FP_COMP寄存器进行检查。

我们使用IDE在主函数循环中找到任何指令的地址,并激活断点:

FP->FP_COMP[0] = 0x080017CC | 1; //     = 0x080017CC

禁用硬件调试器时,微控制器也会进入DebugMon中断。

如何使用它


使用上述寄存器和DebugMon中断,可以在没有SWD / JTAG调试器的情况下调试微控制器。也可以调试与之连接的设备的固件,但是很难访问SWD引脚。

未完待续…

All Articles