diff --git a/src/machine/machine_stm32_uart.go b/src/machine/machine_stm32_uart.go index 6beafe4e1..10cf7d87b 100644 --- a/src/machine/machine_stm32_uart.go +++ b/src/machine/machine_stm32_uart.go @@ -24,6 +24,10 @@ type UART struct { txReg *volatile.Register32 statusReg *volatile.Register32 txEmptyFlag uint32 + // errClearReg points to the ICR register on newer STM32 USART peripherals + // (L0, L4, L5, G0, F7, U5, WL, etc.) for clearing error flags. Nil for + // older peripherals (F1, F4) where errors are cleared by reading SR+DR. + errClearReg *volatile.Register32 } // Configure the UART. @@ -63,7 +67,28 @@ func (uart *UART) Configure(config UARTConfig) { // handleInterrupt should be called from the appropriate interrupt handler for // this UART instance. func (uart *UART) handleInterrupt(interrupt.Interrupt) { - uart.Receive(byte((uart.rxReg.Get() & 0xFF))) + s := uart.statusReg.Get() + + // Only read data when RXNE/RXFNE (bit 5) is set. On all STM32 families, + // RXNEIE enables both the RX-data-ready and overrun-error (ORE) interrupts. + // Without this check, an ORE-only interrupt reads garbage from RDR. + if s&0x20 != 0 { // RXNE / RXFNE + uart.Receive(byte((uart.rxReg.Get() & 0xFF))) + } + + // Clear overrun error (ORE, bit 3) to prevent an interrupt storm. + if s&0x8 != 0 { + if uart.errClearReg != nil { + // Newer USART peripherals: clear ORE via the ICR register. + uart.errClearReg.Set(0x8) // ORECF + } else if s&0x20 == 0 { + // Older USART (F1/F4): ORE is cleared by reading SR then DR. + // SR was already read above. If RXNE was set, DR was read in + // the Receive path. Otherwise do a dummy DR read to complete + // the clearing sequence. + uart.rxReg.Get() + } + } } // SetBaudRate sets the communication speed for the UART. Defer to chip-specific diff --git a/src/machine/machine_stm32f7x2.go b/src/machine/machine_stm32f7x2.go index 7da407071..350b5fd7b 100644 --- a/src/machine/machine_stm32f7x2.go +++ b/src/machine/machine_stm32f7x2.go @@ -46,6 +46,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXE + uart.errClearReg = &uart.Bus.ICR } //---------- I2C related code diff --git a/src/machine/machine_stm32g0.go b/src/machine/machine_stm32g0.go index 7390aed6c..fe89edb9e 100644 --- a/src/machine/machine_stm32g0.go +++ b/src/machine/machine_stm32g0.go @@ -232,6 +232,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXE + uart.errClearReg = &uart.Bus.ICR } //---------- SPI related types and code diff --git a/src/machine/machine_stm32l0.go b/src/machine/machine_stm32l0.go index 1ecd958b8..4903bbea6 100644 --- a/src/machine/machine_stm32l0.go +++ b/src/machine/machine_stm32l0.go @@ -224,6 +224,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXE + uart.errClearReg = &uart.Bus.ICR } //---------- SPI related types and code diff --git a/src/machine/machine_stm32l4.go b/src/machine/machine_stm32l4.go index 8453b2829..6e7e5fe9e 100644 --- a/src/machine/machine_stm32l4.go +++ b/src/machine/machine_stm32l4.go @@ -299,6 +299,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXE + uart.errClearReg = &uart.Bus.ICR } //---------- SPI related types and code diff --git a/src/machine/machine_stm32l5x2.go b/src/machine/machine_stm32l5x2.go index 82ca1ecf6..f442e9c0c 100644 --- a/src/machine/machine_stm32l5x2.go +++ b/src/machine/machine_stm32l5x2.go @@ -44,6 +44,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXE + uart.errClearReg = &uart.Bus.ICR } //---------- I2C related code diff --git a/src/machine/machine_stm32u585.go b/src/machine/machine_stm32u585.go index 5492e14e6..fcb4c0152 100644 --- a/src/machine/machine_stm32u585.go +++ b/src/machine/machine_stm32u585.go @@ -67,6 +67,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXE + uart.errClearReg = &uart.Bus.ICR } //---------- SPI related types and code diff --git a/src/machine/machine_stm32wlx.go b/src/machine/machine_stm32wlx.go index b94e551ff..c229f0322 100644 --- a/src/machine/machine_stm32wlx.go +++ b/src/machine/machine_stm32wlx.go @@ -331,6 +331,7 @@ func (uart *UART) setRegisters() { uart.txReg = &uart.Bus.TDR uart.statusReg = &uart.Bus.ISR uart.txEmptyFlag = stm32.USART_ISR_TXFNF //(TXFNF == TXE == bit 7, but depends alternate RM0461/1094) + uart.errClearReg = &uart.Bus.ICR } //---------- Timer related code