stm32/uart: Suppress additional RX idle IRQs on F4/L1.

These MCUs only clear the RX idle IRQ if the data register is read, which
won't occur if the only IRQ is the RX idle IRQ (because then reading and
discarding the DR may lead to lost data).

To work around this, explicitly suppress the RX idle IRQ so that it's only
passed through to the Python callback once.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George
2025-06-29 22:14:52 +10:00
parent d5246cea61
commit 0975255f86
2 changed files with 19 additions and 0 deletions

View File

@@ -689,6 +689,10 @@ bool uart_init(machine_uart_obj_t *uart_obj,
uart_obj->is_enabled = true;
uart_obj->attached_to_repl = false;
#if defined(STM32F4) || defined(STM32L1)
uart_obj->suppress_idle_irq = true;
#endif
if (bits == UART_WORDLENGTH_9B && parity == UART_PARITY_NONE) {
uart_obj->char_mask = 0x1ff;
uart_obj->char_width = CHAR_WIDTH_9BIT;
@@ -1274,6 +1278,9 @@ void uart_irq_handler(mp_uint_t uart_id) {
self->uartx->CR1 &= ~USART_CR1_RXNEIE;
}
}
if (self->suppress_idle_irq) {
self->mp_irq_flags &= ~USART_SR_IDLE;
}
#else
self->uartx->ICR = self->mp_irq_flags & (USART_ICR_IDLECF | USART_ICR_ORECF);
#endif
@@ -1282,6 +1289,14 @@ void uart_irq_handler(mp_uint_t uart_id) {
if (self->mp_irq_trigger & self->mp_irq_flags) {
mp_irq_handler(self->mp_irq_obj);
}
#if defined(STM32F4) || defined(STM32L1)
if (did_clear_sr) {
self->suppress_idle_irq = false;
} else {
self->suppress_idle_irq = true;
}
#endif
}
static mp_uint_t uart_irq_trigger(mp_obj_t self_in, mp_uint_t new_trigger) {

View File

@@ -26,6 +26,7 @@
#ifndef MICROPY_INCLUDED_STM32_UART_H
#define MICROPY_INCLUDED_STM32_UART_H
#include "py/mphal.h"
#include "shared/runtime/mpirq.h"
typedef enum {
@@ -63,6 +64,9 @@ typedef struct _machine_uart_obj_t {
pyb_uart_t uart_id : 8;
bool is_static : 1;
bool is_enabled : 1;
#if defined(STM32F4) || defined(STM32L1)
bool suppress_idle_irq : 1; // whether the RX idle IRQ is suppressed (F4/L1 only)
#endif
bool attached_to_repl; // whether the UART is attached to REPL
byte char_width; // 0 for 7,8 bit chars, 1 for 9 bit chars
uint16_t char_mask; // 0x7f for 7 bit, 0xff for 8 bit, 0x1ff for 9 bit