Blue Pill - SWO

Table des matières

TL;DR

Utiliser la PIN PB3 pour le debug (Serial Wire Output).

Le matériel

Au choix:

Le branchement

Dans mon cas, le connecteur CN4 de la NUCLEO ne fournit pas d'alimentation, je branche la Blue Pill en 5V à l'aide du connecteur CN8:
ConnecteurPinBlue Pill
CN42PA14
CN44PA13
CN46PB3
CN8GNDGND
CN85V5V

La contrainte

Il faut passer les commandes suivantes à "openocd":
tpiu config internal /tmp/swo.out uart off 8000000
itm ports on
Les commandes suivantes arrêtent le debug:
tpiu config disable
itm ports off
Le tout est intégré au Makefile:
make swo_on SWO_SPEED=72000000
make swo_off

Edit 2024-05-24

La syntaxe a évolué et il faut désormais utiliser:
swo_off:
        @echo 'stm32f1x.tpiu disable' | nc -N 127.0.0.1 4444
        @echo 'itm ports off' | nc -N 127.0.0.1 4444

swo_on:
        @echo 'stm32f1x.tpiu configure -protocol uart -traceclk $(SWO_SPEED) -output /tmp/swo.out' | nc -N 127.0.0.1 4444
        @echo 'stm32f1x.tpiu enable' | nc -N 127.0.0.1 4444
        @echo 'itm ports on' | nc -N 127.0.0.1 4444

Les avantages

Le gros du boulot se trouve dans le fichier STM32-base-STM32Cube-master/CMSIS/ARM/inc/core_cm3.h qui fournit une fonction ITM_SendChar(uint32_t ch). Il ne reste plus qu'à faire un copier/coller/remplacer de goret pour obtenir depuis usart.{h,c} une déclinaison swo.{h,c} fournissant les fonctions: La configuration est réduite au minimum: C'est tout ! Une fois le code chargé et les commandes passées à "openocd", le fichier /tmp/swo.out" est créé:
$ tail -f /tmp/swo.out
Hello world !
Hello world !
Hello world !
Hello world !
...
Le fichier n'est pas exactement du texte ("cat -vte" ou "xxd" pour voir que chaque caractère est précédé de 0x01) mais c'est bien suffisant pour du debug. Plus besoin d'adaptateur usb/série !

Le code complet: https://gitlab.com/dsx/blue-pill/-/tree/master/stm32f103c8t6/03_swo

Ce qui peut ne pas plaire

On voit bien que la seule différence entre USART et SWO est la fonction d'envoi de caractère: usart_putc d'un côté et ITM_SendChar de l'autre. Je pourrais faire
#ifdef USE_DBG_SWO
#define DBG_SEND_CHAR ITM_SendChar
#endif
#ifdef USE_DBG_USART
#define DBG_SEND_CHAR usart_putc
#endif
et tout regrouper dans 2 fonctions dbg_puts et dbg_printf mais il ne faut pas oublier que l'USART nécessite beaucoup plus de configuration (DMA, interruption ...).

A retenir

A condition d'avoir le matériel adéquat (un st-link avec une broche SWO fonctionnelle) on peut ajouter très facilement du debug "à la papa" et faire l'économie d'un adaptateur usb/série.

A lire

Bien qu'il y soit question de Rust, il faut absolument lire http://blog.japaric.io/itm/ (anglais).