Depuración de microcontroladores ARM Cortex-M por UART

En este artículo, le diré cómo usar los registros de depuración y punto de interrupción en microcontroladores construidos en núcleos ARM Cortex-M

Introducción


¿Sabía que los núcleos ARM Cortex-M en microcontroladores pueden depurarse?
Resulta que pueden.

Al leer el Manual de referencia técnica en el núcleo, el Cortex M3 descubrió que tenía una interrupción DebugMon. A continuación, analicé todos los registros asociados con él. Como resultado, descubrí que MK puede caer en esta interrupción si el registro de la PC y uno de los registros FP_COMP son iguales.
Esto significa que podemos establecer puntos de interrupción en el firmware depurado. También puede forzar una interrupción de DebugMon estableciendo el bit MON_PEND del registro DEMCR en 1.

Comprobación de la teoría


Dado que estos registros están presentes en toda la familia de núcleos ARM Cortex-M, tomamos la primera placa de depuración que aparece. Resultó ser stm32f723e-disco para mí. Para no perder el tiempo escribiendo el código de inicialización para los periféricos, usamos CubeMX.
De los periféricos, solo necesitamos UART6 conectado al ST-Link y al LED en la placa:

Configuraciones en CubeMX
image

Generamos el proyecto e inmediatamente abrimos su IDE.

Para no confundirse en los registros asociados con la depuración, introducimos inmediatamente las definiciones para ellos en el código:

Definiciones de registro
#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)


Para verificar que nuestro proyecto funciona, en principio, escriba un código que parpadee con un LED:

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


El LED parpadeó con éxito, lo que significa que el proyecto se compiló y lanzó con éxito.

Agregue la línea a este bucle:

asm("BKPT #0");

Este inserto de ensamblador es un punto de interrupción de software. Ahora, al depurar a través de ST-Link, el programa siempre se detendrá en esta línea. Salimos de Debug en el IDE y el LED comienza a parpadear como antes.

¿Pero qué nos dio?

Y el hecho de que podemos alcanzar un punto de interrupción interrumpiendo DebugMon.

Escribimos su manejador:

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


Compilamos, flasheamos y nada ha cambiado. Para habilitar la interrupción de DebugMon, debe aumentar el bit MON_EN en el registro DEMCR.

Ahora, al depurar a través de ST-Link, el programa se detendrá como antes en esta línea. Tan pronto como salgamos del modo de depuración, aparecerán signos de exclamación en el terminal:

Salida terminal
image

Luego, verifique lo mismo con el registro FP_COMP.

Encontramos la dirección de cualquier instrucción en el bucle de función principal usando el IDE y activamos el punto de interrupción:

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

Cuando el depurador de hardware está deshabilitado, el microcontrolador también entra en la interrupción de DebugMon.

Cómo usarlo


Usando los registros anteriores y las interrupciones de DebugMon, es posible depurar un microcontrolador sin un depurador SWD / JTAG. También es posible depurar el firmware de un dispositivo con el que hay una conexión, pero el acceso a los pines SWD es difícil.

Continuará…

All Articles