From 688dd814007cd4fc0f9bff641a23de302b793aa9 Mon Sep 17 00:00:00 2001 From: cn Date: Tue, 17 Sep 2019 02:21:53 +0200 Subject: [PATCH] machine/stm32f103xx: allow board specific UART usage Motivation: The bluepill uses USART1 as UART0 but other boards like the STM32 Nucleo boards (and disco as well) use USART2 for USB COM port. To avoid duplication of code the same pattern as in `machine_atsamd21.go` is applied where only UART-specific code is moved to `board_*.go`. --- src/machine/board_bluepill.go | 24 +++++++++++- src/machine/machine_stm32f103xx.go | 63 ++++++++++++++++-------------- 2 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/machine/board_bluepill.go b/src/machine/board_bluepill.go index 7ec73147..39c7d421 100644 --- a/src/machine/board_bluepill.go +++ b/src/machine/board_bluepill.go @@ -2,6 +2,8 @@ package machine +import "device/stm32" + // https://wiki.stm32duino.com/index.php?title=File:Bluepillpinout.gif const ( PA0 = portA + 0 @@ -47,10 +49,28 @@ const ( // UART pins const ( - UART_TX_PIN = PA9 - UART_RX_PIN = PA10 + UART_TX_PIN = PA9 + UART_RX_PIN = PA10 + UART_ALT_TX_PIN = PB6 + UART_ALT_RX_PIN = PB7 ) +var ( + // USART1 is the first hardware serial port on the STM32. + // Both UART0 and UART1 refer to USART1. + UART0 = UART{ + Buffer: NewRingBuffer(), + Bus: stm32.USART1, + IRQVal: stm32.IRQ_USART1, + } + UART1 = &UART0 +) + +//go:export USART1_IRQHandler +func handleUART1() { + UART1.Receive(byte((UART1.Bus.DR.Get() & 0xFF))) +} + // SPI pins const ( SPI0_SCK_PIN = PA5 diff --git a/src/machine/machine_stm32f103xx.go b/src/machine/machine_stm32f103xx.go index 44fa8742..ecded417 100644 --- a/src/machine/machine_stm32f103xx.go +++ b/src/machine/machine_stm32f103xx.go @@ -110,15 +110,10 @@ func (p Pin) Get() bool { // UART type UART struct { Buffer *RingBuffer + Bus *stm32.USART_Type + IRQVal uint32 } -var ( - // USART1 is the first hardware serial port on the STM32. - // Both UART0 and UART1 refer to USART1. - UART0 = UART{Buffer: NewRingBuffer()} - UART1 = &UART0 -) - // Configure the UART. func (uart UART) Configure(config UARTConfig) { // Default baud rate to 115200. @@ -128,53 +123,63 @@ func (uart UART) Configure(config UARTConfig) { // pins switch config.TX { - case PB6: - // use alternate TX/RX pins PB6/PB7 via AFIO mapping + case UART_ALT_TX_PIN: + // use alternate TX/RX pins via AFIO mapping stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN) - stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART1_REMAP) - PB6.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) - PB7.Configure(PinConfig{Mode: PinInputModeFloating}) + if uart.Bus == stm32.USART1 { + stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART1_REMAP) + } else if uart.Bus == stm32.USART2 { + stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART2_REMAP) + } + UART_ALT_TX_PIN.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) + UART_ALT_RX_PIN.Configure(PinConfig{Mode: PinInputModeFloating}) default: // use standard TX/RX pins PA9 and PA10 UART_TX_PIN.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull}) UART_RX_PIN.Configure(PinConfig{Mode: PinInputModeFloating}) } - // Enable USART1 clock - stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) + // Enable USART clock + if uart.Bus == stm32.USART1 { + stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN) + } else if uart.Bus == stm32.USART2 { + stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN) + } // Set baud rate uart.SetBaudRate(config.BaudRate) - // Enable USART1 port. - stm32.USART1.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE) + // 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. - arm.SetPriority(stm32.IRQ_USART1, 0xc0) - arm.EnableIRQ(stm32.IRQ_USART1) + // Enable RX IRQ + arm.SetPriority(uart.IRQVal, 0xc0) + arm.EnableIRQ(uart.IRQVal) } // SetBaudRate sets the communication speed for the UART. func (uart UART) SetBaudRate(br uint32) { - // first divide by PCLK2 prescaler (div 1) and then desired baudrate - divider := CPU_FREQUENCY / br - stm32.USART1.BRR.Set(divider) + // Note: PCLK2 (from APB2) used for USART1 and PCLK1 for USART2, 3, 4, 5 + var divider uint32 + if uart.Bus == stm32.USART1 { + // first divide by PCLK2 prescaler (div 1) and then desired baudrate + divider = CPU_FREQUENCY / br + } else { + // first divide by PCLK1 prescaler (div 2) and then desired baudrate + divider = CPU_FREQUENCY / 2 / br + } + uart.Bus.BRR.Set(divider) } // WriteByte writes a byte of data to the UART. func (uart UART) WriteByte(c byte) error { - stm32.USART1.DR.Set(uint32(c)) + uart.Bus.DR.Set(uint32(c)) - for !stm32.USART1.SR.HasBits(stm32.USART_SR_TXE) { + for !uart.Bus.SR.HasBits(stm32.USART_SR_TXE) { } return nil } -//go:export USART1_IRQHandler -func handleUART1() { - UART1.Receive(byte((stm32.USART1.DR.Get() & 0xFF))) -} - // SPI on the STM32. type SPI struct { Bus *stm32.SPI_Type