Configuration de printf()

STM32F722 avec VS Code, J-Link et SWO

Pendant le développement d'un programme embarqué, il est souvent utile d'afficher des messages pour suivre son exécution ou vérifier la valeur de certaines variables.

Sur un STM32F722, la fonction printf() peut envoyer des messages vers l'environnement de débogage grâce au mécanisme ITM (Instrumentation Trace Macrocell) et à la sortie SWO (Serial Wire Output).

Cette méthode nécessite une sonde de débogage compatible, comme la J-Link, ainsi qu'une configuration adaptée du microcontrôleur et de VS Code. Voici les principales étapes pour mettre en place cette solution.

1. Câblage entre le STM32 et la J-Link

Relier les signaux suivants entre le microcontrôleur et la sonde de débogage :

STM32F722 J-Link Fonction
PA13 / SWDIO SWDIO Données de débogage
PA14 / SWCLK SWCLK Horloge de débogage
GND GND Masse commune
NRST RESET Réinitialisation, conseillée
PB3 / SWO SWO Sortie des messages ITM

Important : la liaison SWD permet de programmer et de déboguer le microcontrôleur, mais la broche SWO est nécessaire pour transmettre les messages ITM vers la sonde.

2. Configuration dans STM32CubeMX

Dans STM32CubeMX, ouvrir System Core → SYS, puis sélectionner Trace Asynchronous SW dans le paramètre Debug.
Cette configuration active le mode de trace asynchrone. Vérifier également que la broche PB3 est bien configurée pour la fonction SWO. Régénérer ensuite le code et compiler le projet.

3. Configuration de launch.json

La configuration dépend de l'extension de débogage installée dans VS Code. Avec Cortex-Debug, il faut notamment configurer la fréquence du processeur et activer la prise en charge de SWO.

Attention : cpuFrequency doit correspondre à la fréquence réelle du cœur du processeur. Ne pas recopier automatiquement la fréquence du PLL : la fréquence HCLK dépend également des diviseurs d'horloge.

Exemple de configuration à adapter à votre projet :

{
    "name": "STM32F722 - SWO",
    "type": "cortex-debug",
    "request": "launch",
    "servertype": "jlink",
    "interface": "swd",
    "runToEntryPoint": "main",
    "swoConfig": {
        "enabled": true,
        "cpuFrequency": 216000000,
        "swoFrequency": 2000000,
        "source": "probe"
    }
}

Les fréquences indiquées sont des exemples et doivent être adaptées à votre configuration. Vérifier aussi la syntaxe attendue par la version de Cortex-Debug utilisée : ce bloc ne constitue pas nécessairement un fichier launch.json complet.

4. Activer l'ITM

Avant d'envoyer des caractères, il faut activer le bloc de trace et le port ITM utilisé pour la sortie. Dans un projet STM32F7 utilisant les en-têtes CMSIS, on peut commencer par cette fonction :

#include "stm32f7xx.h"

static void ITM_Init(void)
{
    /* Autoriser l'accès au bloc de trace */
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;

    /* Activer le port ITM numéro 0 */
    ITM->TCR = ITM_TCR_ITMENA_Msk
             | (1UL << ITM_TCR_TraceBusID_Pos);

    ITM->TER = 1UL;
}

Appeler ITM_Init() une fois au démarrage, après la configuration système et les horloges.

Cette initialisation active le port ITM numéro 0. Elle ne configure pas à elle seule toute la chaîne SWO : la sonde et l'outil de débogage doivent également être configurés pour recevoir les données.

5. Rediriger printf() vers l'ITM

Pour que les caractères envoyés par printf() arrivent sur le port ITM, il faut rediriger la sortie standard. Avec de nombreuses configurations utilisant newlib, cela peut être réalisé en définissant la fonction _write().

#include <stdio.h>
#include "stm32f7xx.h"

int _write(int file, char *ptr, int len)
{
    (void)file;

    for (int i = 0; i < len; i++)
    {
        /* Ne pas attendre si la trace n'est pas activée */
        if ((CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk) == 0U
            || (ITM->TCR & ITM_TCR_ITMENA_Msk) == 0U
            || (ITM->TER & 1UL) == 0U)
        {
            return len;
        }

        ITM_SendChar((uint32_t)ptr[i]);
    }

    return len;
}

Cette fonction transmet les caractères au port ITM numéro 0. Elle convient aux projets dont la bibliothèque C utilise _write() pour la sortie standard. Selon la bibliothèque et les options de liaison, une autre fonction de redirection peut être nécessaire.

Les contrôles évitent de rester bloqué lorsque l'ITM n'est pas activé. Ils ne garantissent toutefois pas que les messages seront reçus si la sonde ou la configuration SWO est incorrecte.

6. Inclure le fichier stdio.h

Dans chaque fichier C qui utilise printf(), ajouter :

#include <stdio.h>

Cette en-tête déclare la fonction printf(). Sans lui, le compilateur peut signaler une déclaration manquante.

7. Utiliser printf()

Une fois la redirection en place, les messages peuvent être écrits comme dans un programme C classique :

printf("Demarrage du programme\n");
printf("Valeur du compteur : %lu\n", (unsigned long)compteur);
printf("Temperature : %.1f C\n", temperature);

Le caractère \n termine la ligne, mais ne garantit pas à lui seul l'envoi immédiat du message. Le comportement dépend notamment de la bibliothèque C et de la mise en tampon de la sortie standard.

Pour les messages de diagnostic, privilégier des textes courts et éviter d'envoyer trop de données dans une boucle très rapide.

8. Lancer le débogage

Démarrer une session de débogage dans VS Code avec la configuration adaptée à la J-Link et à SWO.

Selon l'extension et sa version, les messages apparaissent dans une vue dédiée à la trace ou à l'ITM, et pas nécessairement dans le terminal intégré classique.

Exemple de résultat attendu :

Demarrage du programme
Valeur du compteur : 1234
Temperature : 24.5 C

9. Vérification

Si aucun message n'apparaît, vérifier les points suivants :

Remarque : SWO ou SEGGER RTT ?

Pour afficher quelques messages pendant les premiers développements, SWO avec printf() est une solution simple et pratique.

Pour des projets plus importants, SEGGER RTT constitue souvent une alternative intéressante : il offre généralement un débit supérieur, plusieurs canaux de communication et ne dépend pas d'une liaison de trace SWO.

Pour nos premiers développements autour du STUSB4500, la solution SWO reste toutefois adaptée pour afficher des messages de diagnostic sans ajouter de liaison série dédiée.