From c61c5e5799b515c09139aa4e644fd5a3b0655b89 Mon Sep 17 00:00:00 2001 From: GeoffThomas Date: Sun, 15 Mar 2020 23:36:33 -0500 Subject: [PATCH] refactor stm32 UART code --- src/machine/board_stm32f4disco.go | 19 +++++++ src/machine/machine_stm32_moder_gpio.go | 2 +- src/machine/machine_stm32_uart.go | 62 ++++++++++++++++++++ src/machine/machine_stm32f103xx.go | 53 +++-------------- src/machine/machine_stm32f407.go | 75 ++++++------------------- 5 files changed, 107 insertions(+), 104 deletions(-) create mode 100644 src/machine/machine_stm32_uart.go diff --git a/src/machine/board_stm32f4disco.go b/src/machine/board_stm32f4disco.go index 36c173b2..9d1c5076 100644 --- a/src/machine/board_stm32f4disco.go +++ b/src/machine/board_stm32f4disco.go @@ -2,6 +2,11 @@ package machine +import ( + "device/stm32" + "runtime/interrupt" +) + const ( PA0 = portA + 0 PA1 = portA + 1 @@ -110,3 +115,17 @@ const ( UART_TX_PIN = PA2 UART_RX_PIN = PA3 ) + +var ( + UART0 = UART{ + Buffer: NewRingBuffer(), + Bus: stm32.USART2, + AltFuncSelector: stm32.AF7_USART1_2_3, + } + UART1 = &UART0 +) + +// set up RX IRQ handler. Follow similar pattern for other UARTx instances +func init() { + UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, UART0.handleInterrupt) +} diff --git a/src/machine/machine_stm32_moder_gpio.go b/src/machine/machine_stm32_moder_gpio.go index 5ce265a6..da1a2d93 100644 --- a/src/machine/machine_stm32_moder_gpio.go +++ b/src/machine/machine_stm32_moder_gpio.go @@ -82,7 +82,7 @@ func (p Pin) ConfigureAltFunc(config PinConfig, altFunc stm32.AltFunc) { port.PUPDR.ReplaceBits(stm32.GPIOPUPDRFloating, 0x3, pos) p.SetAltFunc(altFunc) - // I2C) + // I2C case PinModeI2CSCL: port.MODER.ReplaceBits(stm32.GPIOModeOutputAltFunc, 0x3, pos) port.OTYPER.ReplaceBits(stm32.GPIOOutputTypeOpenDrain, 0x1, pos) diff --git a/src/machine/machine_stm32_uart.go b/src/machine/machine_stm32_uart.go new file mode 100644 index 00000000..80d2440a --- /dev/null +++ b/src/machine/machine_stm32_uart.go @@ -0,0 +1,62 @@ +// +build stm32 + +package machine + +// Peripheral abstraction layer for UARTs on the stm32 family. + +import ( + "device/stm32" + "runtime/interrupt" + "unsafe" +) + +// 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 + } + + // 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) { + uart.Receive(byte((uart.Bus.DR.Get() & 0xFF))) +} + +// 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.Bus.DR.Set(uint32(c)) + + for !uart.Bus.SR.HasBits(stm32.USART_SR_TXE) { + } + return nil +} diff --git a/src/machine/machine_stm32f103xx.go b/src/machine/machine_stm32f103xx.go index 27b65009..bb60b929 100644 --- a/src/machine/machine_stm32f103xx.go +++ b/src/machine/machine_stm32f103xx.go @@ -104,25 +104,17 @@ func enableAltFuncClock(bus unsafe.Pointer) { } } -// UART +//---------- UART related types and code + +// UART representation type UART struct { Buffer *RingBuffer Bus *stm32.USART_Type Interrupt interrupt.Interrupt } -// 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 - } +// Configure the TX and RX pins +func (uart UART) configurePins(config UARTConfig) { // pins switch config.TX { @@ -139,23 +131,11 @@ func (uart UART) Configure(config UARTConfig) { } config.TX.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) config.RX.Configure(PinConfig{Mode: PinInputModeFloating}) - - // Enable USART clock - enableAltFuncClock(unsafe.Pointer(uart.Bus)) - - // Set baud rate - uart.SetBaudRate(config.BaudRate) - - // Enable USART port - 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() } -// SetBaudRate sets the communication speed for the UART. -func (uart UART) SetBaudRate(br uint32) { +// Determine the divisor for USARTs to get the given baudrate +func (uart UART) getBaudRateDivisor(br uint32) uint32 { + // Note: PCLK2 (from APB2) used for USART1 and PCLK1 for USART2, 3, 4, 5 var divider uint32 if uart.Bus == stm32.USART1 { @@ -165,22 +145,7 @@ func (uart UART) SetBaudRate(br uint32) { // first divide by PCLK1 prescaler (div 2) and then desired baudrate divider = CPUFrequency() / 2 / br } - uart.Bus.BRR.Set(divider) -} - -// WriteByte writes a byte of data to the UART. -func (uart UART) WriteByte(c byte) error { - uart.Bus.DR.Set(uint32(c)) - - for !uart.Bus.SR.HasBits(stm32.USART_SR_TXE) { - } - return nil -} - -// handleInterrupt should be called from the appropriate interrupt handler for -// this UART instance. -func (uart *UART) handleInterrupt(interrupt.Interrupt) { - uart.Receive(byte((uart.Bus.DR.Get() & 0xFF))) + return divider } // SPI on the STM32. diff --git a/src/machine/machine_stm32f407.go b/src/machine/machine_stm32f407.go index 85d9e2b2..4714f2b0 100644 --- a/src/machine/machine_stm32f407.go +++ b/src/machine/machine_stm32f407.go @@ -79,75 +79,32 @@ func enableAltFuncClock(bus unsafe.Pointer) { } } -// UART +//---------- UART related types and code + +// UART representation type UART struct { Buffer *RingBuffer Bus *stm32.USART_Type + Interrupt interrupt.Interrupt AltFuncSelector stm32.AltFunc } -var ( - UART0 = UART{ - Buffer: NewRingBuffer(), - Bus: stm32.USART2, - AltFuncSelector: stm32.AF7_USART1_2_3, - } - UART1 = &UART0 -) - // 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 - } - - // Enable USART clock - enableAltFuncClock(unsafe.Pointer(uart.Bus)) - - // use standard TX/RX pins PA2 and PA3 +func (uart UART) configurePins(config UARTConfig) { + // enable the alternate functions on the TX and RX pins config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector) config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector) - - /* - Set baud rate(115200) - OVER8 = 0, APB1 = 42mhz - +----------+--------+ - | baudrate | BRR | - +----------+--------+ - | 1200 | 0x88B8 | - | 2400 | 0x445C | - | 9600 | 0x1117 | - | 19200 | 0x88C | - | 38400 | 0x446 | - | 57600 | 0x2D9 | - | 115200 | 0x16D | - +----------+--------+ - */ - uart.Bus.BRR.Set(0x16c) - - // Enable USART2 port. - uart.Bus.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE) - - // Enable RX IRQ. TODO: pick the right IRQ_xxx for the bus and the uart - intr := interrupt.New(stm32.IRQ_USART2, func(interrupt.Interrupt) { - UART1.Receive(byte((UART1.Bus.DR.Get() & 0xFF))) - }) - intr.SetPriority(0xc0) - intr.Enable() } -// WriteByte writes a byte of data to the UART. -func (uart UART) WriteByte(c byte) error { - uart.Bus.DR.Set(uint32(c)) - - for !uart.Bus.SR.HasBits(stm32.USART_SR_TXE) { +// UART baudrate calc based on the bus and clockspeed +// NOTE: keep this in sync with the runtime/runtime_stm32f407.go clock init code +func (uart UART) getBaudRateDivisor(baudRate uint32) uint32 { + var clock uint32 + switch uart.Bus { + case stm32.USART1, stm32.USART6: + clock = CPUFrequency() / 2 // APB2 Frequency + case stm32.USART2, stm32.USART3, stm32.UART4, stm32.UART5: + clock = CPUFrequency() / 4 // APB1 Frequency } - return nil + return clock / baudRate }