Blue Pill - USART

Table des matières

TL;DR

Utiliser n'importe quel USART.

Les ports série

Le tableau suivant récapitule les ports série disponibles:
NomBridgeRxTx
USART1APB2PA10PA9
USART2APB1PA3PA2
USART3APB1PB11PB10
USART1
remap
APB2PB7PB6
Ces différentes configurations sont placées dans un fichier usart_config.h:
...
#if defined USE_USART1
#define USART_USART      USART1
#define USART_APB2_EN    (RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN)  // usart 1 + gpio A + alternate function @APB2
#define USART_GPIO       GPIOA
#define USART_PIN_TX     9

#elif defined USE_USART2
...
On sélectionne l'USART et la vitesse du lien série depuis le Makefile:
CFLAGS += -DUSE_USART2
...
CFLAGS += -DUSART_BAUD_RATE=9600

Un peu de code

J'ajoute une fonction d'initialisation:
void
usart_init(uint16_t usart_div_value) {
#ifdef USART_APB1_EN
    RCC->APB1ENR     |= USART_APB1_EN;                    // Enable USART[23]
#endif
    RCC->APB2ENR     |= USART_APB2_EN;                    // Enable [USART1 &] GPIOs & Alternate Function
#ifdef USE_USART1_REMAP
    AFIO->MAPR       |= AFIO_MAPR_USART1_REMAP;           // Remap USART1 *after* USART
#endif
    USART_USART->BRR  = ( ((usart_div_value / 16) << 4) | ((usart_div_value % 16) << 0) );
    USART_USART->CR1 |= (USART_CR1_TE | USART_CR1_UE);    // enable Transmission & Usart

    gpio_pin_init(USART_GPIO, USART_PIN_TX, O02_AF_PP);
}
La boucle principale se contente d'afficher l'USART et la vitesse sélectionnés:
...
#define xstr(s) str(s)
#define str(s)  #s
...
    while (1) { 
        __WFI();
        usart_puts("Hello world from " USART_NAME " @" xstr(USART_BAUD_RATE) " !");
    }
Je pensais rencontrer des problèmes (carte à 8 MHz, PIN à 2 MHz) mais même à 115 200 bauds j'obtiens bien:
...
Hello world from USART2 @115200 !
Hello world from USART2 @115200 !
...
La longueur réduite du texte et la carte qui ne fait rien d'autre doivent faire "tomber en marche" ce code qui devrait, en fonction de la vitesse du lien série, configurer la PIN TX à une vitesse plus élevée sans oublier le changement de la source d'horloge. L'objectif ici est de pouvoir tester tous les USARTs, j'en reste là pour le moment.

Chef, un printf, on a soif !

J'utilise une petite astuce pour afficher la valeur de la macro USART_BAUD_RATE mais pour formater du texte je dois implémenter ma fonction printf:
#ifdef USE_USART_PRINTF
void
usart_printf(const char * const fmt, ...) {
...
}
#endif
Cette fonction utilise un tampon de 10 caractères suffisant pour stocker la représentation d'un unsigned int et supporte uniquement '%%', '%c' et '%d'. La boucle principale devient:
#ifdef USE_USART_PRINTF
        usart_printf("Hello world from " USART_NAME " @%d !\r\n", USART_BAUD_RATE);
#else
        usart_puts("Hello world from " USART_NAME " @" xstr(USART_BAUD_RATE) " !");
#endif
Le code complet: https://gitlab.com/dsx/blue-pill/-/tree/master/stm32f103c8t6/02_usart_usarts

A suivre

Il est possible, moyennant un tampon, de consommer encore moins de ressources à l'aide du Direct Memory Access.

A retenir

Il est possible d'avoir un lien à 115 200 bauds sans configuration particulière à condition de ne transmettre qu'un faible volume de données et que la carte ne soit pas occupée à faire autre chose. Il faut implémenter une fonction de formatage.