¿Cómo imprimo mensajes de depuración en la consola gdb con la placa de descubrimiento STM32 usando GDB, OpenOCD y arm-none-eabi-gcc?

15

Estoy programando una placa de descubrimiento STM32 Cortex M0 (32F0308DISCOVERY) usando OpenOCD, arm-none-eabi-gcc y gdb. Me preguntaba si hay alguna forma directa de registrar mensajes de depuración a través de SWD. He leído acerca de la opción de semihosting, pero esto parece requerir la incorporación de newlib u otras bibliotecas grandes. (Solo hay una memoria flash de 64k disponible). ¿Hay alguna forma más liviana de registrar texto a través de SWD, o está usando el UART la única opción práctica?

foldl
fuente
1
Te sugiero que pruebes la opción de semihosting. A modo de indicación, las bibliotecas que ofrece CooCox (un entorno gratuito de Windows Cortex-M) para M3 / 4 son bastante minimalistas, su transferencia de un solo byte es de 17 instrucciones de ensamblaje. Una reconstrucción de un proyecto antiguo (STM32F4) con su semihosting y -O0 agregó 48 bytes al tamaño del código.
markt
Es posible que su enlazador no elimine el código no utilizado. En cuanto a las alternativas, el repositorio github de texane para manejar herramientas stlink tiene un esquema de buzón simple, aunque todavía no lo he probado.
Chris Stratton

Respuestas:

15

Gracias por los punteros, Markt y Chris-Stratton. La opción de semihosting resultó ser bastante sencilla. Logré encontrar la fuente para un par de rutinas de registro simples que pueden enviar mensajes a la consola OpenOCD. Los publicaré aquí ya que (i) requirieron alguna modificación para funcionar y (ii) creo que esta información no es muy fácil de encontrar para las personas que recién comienzan.

Primero, el código D aquí se adapta fácilmente para proporcionar la siguiente función C:

void send_command(int command, void *message)
{
   asm("mov r0, %[cmd];"
       "mov r1, %[msg];"
       "bkpt #0xAB"
         :
         : [cmd] "r" (command), [msg] "r" (message)
         : "r0", "r1", "memory");
}

Ejemplo de llamar a send_command para escribir una cadena en la consola OpenOCD:

const char s[] = "Hello world\n";
uint32_t m[] = { 2/*stderr*/, (uint32_t)s, sizeof(s)/sizeof(char) - 1 };
send_command(0x05/* some interrupt ID */, m);

Segundo, la función putChar dada en los comentarios aquí funciona bien, excepto que tuve que agregar un '#' antes de 0x03:

void put_char(char c)
{
    asm (
    "mov r0, #0x03\n"   /* SYS_WRITEC */
    "mov r1, %[msg]\n"
    "bkpt #0xAB\n"
    :
    : [msg] "r" (&c)
    : "r0", "r1"
    );
}

Para ver la salida de estas funciones, primero inicio OpenOCD, luego me conecto usando arm-none-eabi-gdb de la siguiente manera:

target remote localhost:3333
monitor arm semihosting enable
monitor reset halt
load code.elf
continue

Tenga en cuenta que los mensajes aparecen en la salida estándar del proceso OpenOCD, no en la consola GDB.

foldl
fuente
1
Hay un error, el tamaño de () debe ser eliminado ().
1
Gracias usuario107642. De hecho, es posible usar sizeof aquí si 's' es una matriz en lugar de un puntero, por lo que lo he modificado de esa manera.
foldl
¡Gran respuesta! También podría escribir putchartan simple comovoid putchar(char c) { send_command(3,&c); }
mvds
1
El "sizeof" contará el \ 0 final de la cadena, mientras que strlen no lo hará. Si openocd solo imprime en stdout y una ventana de terminal xterm, eso probablemente no hará una diferencia notable ya que el terminal probablemente lo ignorará. Pero si terminas poniendo cosas en un archivo, creo que te sorprenderá encontrar esos ceros allí. ¿O el protocolo especifica que necesita enviar cadenas con el terminador final?
user242579
Ah, buen punto user242579. Agregué un '-1' para tener en cuenta el \ 0 final.
foldl