#15569·betaflight

UART NVIC-enable gate checks only RX DMA, can leave TX IRQ permanently disabled

Author: nerdCopterCreated Aug 13, 2026Updated Sep 13, 2026
LabelsInactive

AI Generated issue-ticket

Summary

serialUART()'s post-init NVIC-enable gate checks only the RX-side DMA resource before deciding whether to enable the USART/UART peripheral's NVIC interrupt line. The same line services both RX and TX interrupt sources on these parts. When RX resolves to DMA (so the RX-IRQ path is genuinely unneeded) but TX does not, this gate leaves the shared NVIC line disabled, and any driver code that depends on IRQ-driven TX (UART_IT_TXE/UART_IT_TC) can no longer run.

Where

Confirmed identical in shape across all four HAL/StdPeriph "modern" STM32 UART driver files (StdPeriph-only and pure-HAL variants don't gate NVIC enable at all, so they are unaffected):

  • src/main/drivers/stm32/serial_uart_stm32f4xx.c:363
  • src/main/drivers/stm32/serial_uart_stm32f7xx.c:395
  • src/main/drivers/stm32/serial_uart_stm32g4xx.c:328
  • src/main/drivers/stm32/serial_uart_stm32h7xx.c:505
c
#ifdef USE_DMA
    if (!s->rxDMAResource)
#endif
    {
        HAL_NVIC_SetPriority(hardware->rxIrq, NVIC_PRIORITY_BASE(hardware->rxPriority), NVIC_PRIORITY_SUB(hardware->rxPriority));
        HAL_NVIC_EnableIRQ(hardware->rxIrq);
    }

Trigger condition

Any UART whose resolved DMA assignment is asymmetric between RX and TX — RX-DMA active while TX-DMA is not (the common direction, since RX benefits most from DMA offload). In that case !s->rxDMAResource is false, so HAL_NVIC_EnableIRQ() is skipped, and the shared NVIC line stays disabled for the life of the port. TX bytes queued via the non-DMA IRQ path (UART_IT_TXE) then never get serviced at the NVIC level, regardless of what the peripheral's own CR1/CR3 interrupt-enable bits say.

Not confirmed reachable on any specific shipped target/config — that would require auditing every target's per-UART rxDmaopt/txDmaopt resolution. Filed as a defect in the shared gating pattern itself, present identically in all four files.

Suggested fix

Gate on both resources, e.g.:

c
if (!s->rxDMAResource || !s->txDMAResource) {
    HAL_NVIC_SetPriority(...);
    HAL_NVIC_EnableIRQ(hardware->rxIrq);
}

so the shared NVIC line is enabled whenever either direction still needs IRQ service, not only when RX does.