STM32 gotchas
24.UART Rx stops working

In the previous gotcha, we've discussed the consequence of not handling UART Rx overflows in the UART interrupt. But what happens, if we don't handle overruns in polled, or DMA-based UART Rx implementations?

Well, the Rx simply stops working.

This is not well documented in the RM, but UART stops generating RXNE upon arriving valid bytes, when USART_SR/ISR.ORE is set.

So, it's vital, that this particular error is properly handled, both in polled, and DMA implementations. In the former, it will probably be part of the polling procedure, e.g.

  uint_least8_t UsartWaitRxByte(USART_TypeDef * USART) {
    uint32_t sr;

    do {
      sr = USART->SR;
      if (sr & USART_SR_ORE) {
        (void)USART->DR;  // in older USARTs with SR, ORE is cleared by reading SR and then DR
    } while (!(sr & USART_SR_RXNE)) ;
    return USART->DR;
For DMA-based implementations, it makes more sense to detect and handle overruns in interrupt.

As mentioned already,, in newer USART, overruns can be also ignored, by setting USART_CR3.OVRDIS.

There may be two possible implementations of this behaviour internally, with the same outward effect: the UART may receive but discard all incoming frames as long as ORE is set; or it may stop receiving altogether until ORE is cleared. It appears, the actual STM32 implementation does the latter, as it does not update other error flags (parity error, framing error) either. This behaviour is different from many other UART implementations. A minor, but interesting consequence was, where a nonstandard protocol used already on other mcus was reported to be unimplementable on STM32. This protocol stipulated ignoring incoming bytes (possibly in a sleep mode) until the transmitter transmitted a byte with deliberately crafted parity error, causing error interrupt, serving as a wakeup and framing element.