mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-19 03:54:01 +00:00
machine/stm32: fix UART transmission, baud rate, and interrupt handling
This fixes several issues in the STM32 UART implementation: - `writeByte` now waits for the transmit register to be empty before writing, preventing data loss by avoiding overwriting the shift register. - `flush` now correctly waits for the Transmission Complete (TC) flag. - The interrupt handler now clears all error flags (ORE, NE, FE, PE) to prevent interrupt storms, rather than just ORE. - Extracted `SetBaudRate` so it can be cleanly overridden by specific MCU families. It also introduces specific fixes for the STM32U5 family: - Enforces a minimum BRR divisor of 16 in `getBaudRateDivisor` to prevent undefined hardware behavior and CPU starvation. - Overrides `SetBaudRate` for STM32U585 to momentarily disable the USART (UE=0) before updating the BRR register, which is read-only when enabled. - Adds a readback after enabling the USART1 clock to ensure the clock is active before register access. Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
@@ -58,7 +58,16 @@ func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
||||
// LPUART uses BRR = 256 * fclk / baud
|
||||
return (256 * CPUFrequency()) / baudRate
|
||||
}
|
||||
return CPUFrequency() / baudRate
|
||||
// USART requires BRR >= 16 for 16x oversampling (OVER8=0).
|
||||
// A divisor below 16 is invalid per the STM32 reference manual and causes
|
||||
// undefined hardware behaviour — in practice the receiver fires ORE/RXNE
|
||||
// interrupts at an impossible rate, completely starving the CPU.
|
||||
const minBRR = 16
|
||||
divisor := CPUFrequency() / baudRate
|
||||
if divisor < minBRR {
|
||||
divisor = minBRR
|
||||
}
|
||||
return divisor
|
||||
}
|
||||
|
||||
// Register names vary by ST processor, these are for STM U5
|
||||
@@ -70,6 +79,24 @@ func (uart *UART) setRegisters() {
|
||||
uart.errClearReg = &uart.Bus.ICR
|
||||
}
|
||||
|
||||
// SetBaudRate overrides the shared implementation for STM32U5. On this
|
||||
// family the BRR register is read-only while UE=1 (USART enabled), so the
|
||||
// USART must be briefly disabled to change the baud rate. This matters when
|
||||
// the servo library (or any code) calls SetBaudRate after Configure has
|
||||
// already enabled the USART.
|
||||
func (uart *UART) SetBaudRate(br uint32) {
|
||||
cr1 := uart.Bus.CR1.Get()
|
||||
if cr1&stm32.USART_CR1_UE != 0 {
|
||||
// Disable the USART so BRR becomes writable.
|
||||
uart.Bus.CR1.Set(cr1 &^ stm32.USART_CR1_UE)
|
||||
}
|
||||
uart.Bus.BRR.Set(uart.getBaudRateDivisor(br))
|
||||
if cr1&stm32.USART_CR1_UE != 0 {
|
||||
// Restore CR1 exactly as it was (re-enables USART, TE, RE, etc.).
|
||||
uart.Bus.CR1.Set(cr1)
|
||||
}
|
||||
}
|
||||
|
||||
//---------- SPI related types and code
|
||||
|
||||
// SPI on the STM32U5 using the new SPIv2 peripheral
|
||||
|
||||
Reference in New Issue
Block a user