STM32 gotchas
23.STM32 hangs in UART interrupt

Sometimes users experience a "mysterious" hang of their system. They might find out that the processor permanently "loops" into the UART interrupt. Why is that?

The gotcha lies in the fact that UART RX overrun (i.e. when as byte arrives to Rx while the previous has not been read already), indicated by USART_SR/ISR.ORE being set, does trigger an interrupt if USART_CR1.RXNEIE is set. Note, that this is the same bit which enables the "normal" Rx interrupt, too.

So, proper handling of the UART interrupt, when USART_CR1.RXNEIE is set, must include checking both RXNE and ORE in the status register (USART_SR/ISR), and using any procedure needed to clear them.

While RXNE is cleared automatically by hardware when reading the data register; clearing ORE differs between the UART versions. In the older version of UART, reading both status register and data register clears also ORE in hardware, very similarly to clearing RXNE (to be precise, clearing RXNE does not require reading the status register, but that normally is read in the ISR prior to reading the data register, anyway). Clearing ORE in the newer version of USART ('F0 and newer, having separate Rx and Tx data registers and ISR/ICR registers) requires writing 1 to USART_ICR.ORECF.

Note, that it may happen, that ORE is set while RXNE is not set (see Overrun error subsection of Receiver subchapter of UART chapter in RM, note starting "if RXNE=0 [...]"), so the interrupt handler must be written with this possibility in mind.

The newer USART has a USART_CR3.OVRDIS bit, which suppresses generating ORE. In cases, where data consistency is ensured by other means (e.g. higher-level packetization/framing/checksumming of data), this allows to write a simpler (thus faster) ISR without running into the problem described here.