Communication série via interruption et DMA sur STM32

La communication série sur microcontrôleurs STM32 peut être optimisée en utilisant les interruptions matérielles ou le transfert direct mémoire (DMA). Ces méthodes permettent de libérer le CPU pendant les échanges de données, améliorent ainsi l'efficacité globale du système.

Configuration matérielle et logicielle

  • Carte cible : STM32F103C8T6
  • Outil de configuration : STM32CubeMX v6.9.2
  • Environnement de compilation : Keil MDK v5

Initialisation des périphériques avec STM32CubeMX

Les broches suivantes sont configurées :

PA9  → USART1_TX
PA10 → USART1_RX
PC13 → GPIO_Output (LED témoin)

Le contrôleur USART1 est activé en mode asynchrone avec une vitesse de 9600 bauds. Les interruptions et le canal DMA sont également activés pour la réception et l'émission.

Implémentation par interruption

Dans le fichier main.c, on déclare un tampon de réception et un indicateur d'état :

/* Tampon de réception */
#define BUF_LEN 4
uint8_t recv_buf[BUF_LEN];
volatile uint8_t recv_done = 0;

Avant la boucle principale, on initialise la communication et lance l'écoute :

HAL_UART_Transmit(&huart1, (uint8_t*)"Prêt à recevoir 'stop'\r\n", 22, HAL_MAX_DELAY);
HAL_UART_Receive_IT(&huart1, recv_buf, BUF_LEN);

Dans la boucle infinie, le microcontrôleur envoie périodiquement un message tant qu’aucun signal d’arrêt n’est reçu :

while (1) {
    if (!recv_done) {
        HAL_UART_Transmit(&huart1, (uint8_t*)"Bonjour PC !\r\n", 14, 100);
        HAL_Delay(1000);
    } else {
        HAL_UART_Transmit(&huart1, (uint8_t*)"Transmission suspendue.\r\n", 24, HAL_MAX_DELAY);
        break;
    }
}

Gestion de la réception via callback

La fonction de rappel gère la logique d’arrêt/démarrage :

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if (huart == &huart1) {
        if (memcmp(recv_buf, "stop", 4) == 0) {
            recv_done = 1;
        }
        HAL_UART_Receive_IT(&huart1, recv_buf, BUF_LEN);
    }
}

Implémentation avec DMA

Pour le mode DMA, on utilise un tampon dynamique et un indicateur de transmission :

#define RX_BUF_SIZE 64
uint8_t dma_rx_buf[RX_BUF_SIZE];
uint8_t single_char = 0;
uint8_t msg[] = "Salut Windows !\r\n";
volatile uint8_t is_active = 1;

La boucle principale transmet via DMA et vérifie l’état :

HAL_UART_Receive_IT(&huart1, &single_char, 1);

while (1) {
    if (is_active) {
        HAL_UART_Transmit_DMA(&huart1, msg, strlen((char*)msg));
        HAL_Delay(1000);
    }
}

Le callback analyse les commandes reçues caractère par caractère :

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    static uint8_t idx = 0;
    if (huart == &huart1) {
        dma_rx_buf[idx++] = single_char;
        
        if (idx >= 4 && strncmp((char*)dma_rx_buf, "stop", 4) == 0) {
            is_active = 0;
            idx = 0;
        } else if (idx >= 5 && strncmp((char*)dma_rx_buf, "start", 5) == 0) {
            is_active = 1;
            idx = 0;
        }

        memset(dma_rx_buf, 0, RX_BUF_SIZE);
        HAL_UART_Receive_IT(&huart1, &single_char, 1);
    }
}

Résultats observés

Les deux méthodes produisent des signaux séries stables, vérifiés via un analyseur logique intégré à Keil. Le débit mesuré reste proche de 9600 bauds, avec une légère variation due aux latences système.

Étiquettes: STM32 DMA UART interruption Keil

Publié le 18 septembre à 04h43