//go:build stm32 package machine // Peripheral abstraction layer for UARTs on the stm32 family (except stm32g0). import ( "device/stm32" "runtime/interrupt" "runtime/volatile" "unsafe" ) // UART representation type UART struct { Buffer *RingBuffer Bus *stm32.USART_Type Interrupt interrupt.Interrupt TxAltFuncSelector uint8 RxAltFuncSelector uint8 // Registers specific to the chip rxReg *volatile.Register32 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. func (uart *UART) Configure(config UARTConfig) { // Default baud rate to 115200. if config.BaudRate == 0 { config.BaudRate = 115200 } // Set the GPIO pins to defaults if they're not set if config.TX == 0 && config.RX == 0 { config.TX = UART_TX_PIN config.RX = UART_RX_PIN } // STM32 families have different, but compatible, registers for // basic UART functions. For each family populate the registers // into `uart`. uart.setRegisters() // Enable USART clock enableAltFuncClock(unsafe.Pointer(uart.Bus)) uart.configurePins(config) // Set baud rate uart.SetBaudRate(config.BaudRate) // Enable USART port, tx, rx and rx interrupts uart.Bus.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE) // Enable RX IRQ uart.Interrupt.SetPriority(0xc0) uart.Interrupt.Enable() } // handleInterrupt should be called from the appropriate interrupt handler for // this UART instance. func (uart *UART) handleInterrupt(interrupt.Interrupt) { 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 // routines for calculation func (uart *UART) SetBaudRate(br uint32) { divider := uart.getBaudRateDivisor(br) uart.Bus.BRR.Set(divider) } // WriteByte writes a byte of data to the UART. func (uart *UART) writeByte(c byte) error { uart.txReg.Set(uint32(c)) for !uart.statusReg.HasBits(uart.txEmptyFlag) { } return nil } func (uart *UART) flush() {}