Blue Pill - USART
Table des matières
TL;DR
Mise en place d'un lien série pour du debug.
Le matériel
Un adaptateur série/usb.
Le port série
"Le port série, c'est la vie", tout administrateur Unix pourra le confirmer. S'il permet de reprendre la main sur du (gros) matériel à la configuration rendue bancale, il s'agit ici principalement de debug, histoire de confirmer que "le plan se déroule sans accroc". C'est pourquoi je ne m'occupe que de l'émission par la carte. Je ne vais pas non plus faire le foufou avec les configurations exotiques, 8N1 rulez.
Les ports série
Le tableau suivant récapitule les ports série disponibles:
Nom | Bridge | Rx | Tx |
USART1 | APB2 | PA10 | PA9 |
USART2 | APB1 | PA3 | PA2 |
USART3 | APB1 | PB11 | PB10 |
USART1 remap | APB2 | PB7 | PB6 |
Va se poser un premier problème: les "bridges" APB2 et APB1 n'ont pas forcément la même vitesse. Et la vitesse est justement une des caractéristiques principales d'un lien série. Si 8 MHz est suffisant pour du 9 600 bauds, il faudra augmenter la cadence pour atteindre 115 200 bauds.
USART2 à 9 600 bauds
La configuration en émission d'un lien série est détaillée page 792 du manuel de référence qu'on peut résumer en:
- activer le composant USART
- calculer la valeur à placer dans son registre USART_BRR (Baud Rate Register)
- passer à 1 le bit TE (Transmission Enable) du registre USART_CR1 (Configuration Register 1)
- placer le caractère à envoyer dans le registre USART_DR (Data Register)
- attendre que le bit TC (Transmission Complete) passe à 1
La formule du calcul de la valeur de BRR: vitesse du "bridge" / vitesse en baud souhaitée. La vitesse du "bridge" correspond à SystemCoreClock / HPRE / (PPRE1 ou PPRE2 suivant l'USART). Le code suivant configure USART2 à 9 600 bauds:
#define USART_USART USART2
#define USART_RCC_APB1EN RCC_APB1ENR_USART2EN // usart 2 @APB1
#define USART_RCC_APB2EN RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN // gpio & alternate function @APB2
#define USART_GPIO GPIOA
#define USART_PIN_TX 2
#define USART_BAUD_RATE 9600
RCC->APB1ENR |= USART_RCC_APB1EN;
RCC->APB2ENR |= USART_RCC_APB2EN;
gpio_pin_init(USART_GPIO, USART_PIN_TX, O02_AF_PP); // max speed 02 MHz
// without config HPRE == PPRE1 == PPRE2 == 0 == not divided
// @APB1 == SystemCoreClock
uint16_t usart_div_value = SystemCoreClock / USART_BAUD_RATE;
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
Je ne vais pas m'étendre sur le tableau d'erreur de la page 799 ni sur les calculs à base de mantisse et de fraction. La fonction suivante attend que le registre de données soit vide et y place le caractère à envoyer:
void
usart_putc(char c) {
while (!(USART_USART->SR & USART_SR_TXE)); // wait for Transmit data register Empty
USART_USART->DR = c;
}
Pour envoyer une chaine et les "\r", "\n" kivonbien:
void
usart_puts(const char * const buf) {
const char *c = buf;
while (*c) {
usart_putc(*c++);
}
usart_putc('\r');
usart_putc('\n');
}
Le code complet: https://gitlab.com/dsx/blue-pill/-/tree/master/stm32f103c8t6/02_usart_usart
Ce qui peut ne pas plaire
J'ai volontairement choisi USART2 pour ce premier exemple mais ce n'est pas le choix le plus pertinent: comme dans tous les cas il faut activer APB2 pour les GPIOs autant utiliser USART1. Pour du debug, 9 600 bauds est bien assez rapide pour envoyer quelques centaines de caractère toutes les secondes mais en augmentant cette vitesse on s'assure que la carte puisse avoir plus de temps pour faire des choses "utiles". 8N1 est une configuration "standard" et surtout celle par défaut, pas la peine de se compliquer la vie. Je configure toujours les GPIOs à la vitesse minimale (2 MHz) mais je ne pense pas que cela reste valable pour des hauts débits.
A suivre
Pouvoir utiliser n'importe quel USART.
A retenir
La vitesse du lien série est dépendante de la vitesse du "bridge" sur lequel est connecté l'USART.