From 8f983cfb202f834d0d4d00a7a4179064f5dfcb89 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Thu, 13 Dec 2018 16:12:33 +0100 Subject: [PATCH 1/6] machine/stm32: WIP on UART implementation Signed-off-by: Ron Evans --- src/machine/machine_stm32.go | 95 +++++++++++++++++++++++++++++++++--- src/machine/uart.go | 2 +- src/runtime/runtime_stm32.go | 70 +++++++++++++++++++++++++- 3 files changed, 158 insertions(+), 9 deletions(-) diff --git a/src/machine/machine_stm32.go b/src/machine/machine_stm32.go index 2c6f8bfcea..7bd40df06b 100644 --- a/src/machine/machine_stm32.go +++ b/src/machine/machine_stm32.go @@ -5,14 +5,28 @@ package machine // Peripheral abstraction layer for the stm32. import ( + "device/arm" "device/stm32" ) type GPIOMode uint8 const ( - GPIO_INPUT = 0 // Input mode - GPIO_OUTPUT = 2 // Output mode, max speed 2MHz + GPIO_INPUT = 0 // Input mode + GPIO_OUTPUT_10MHz = 1 // Output mode, max speed 10MHz + GPIO_OUTPUT_2MHz = 2 // Output mode, max speed 2MHz + GPIO_OUTPUT_50MHz = 3 // Output mode, max speed 50MHz + GPIO_OUTPUT = GPIO_OUTPUT_2MHz + + GPIO_INPUT_MODE_ANALOG = 0 // Input analog mode + GPIO_INPUT_MODE_FLOATING = 4 // Input floating mode + GPIO_INPUT_MODE_PULL_UP_DOWN = 8 // Input pull up/down mode + GPIO_INPUT_MODE_RESERVED = 12 // Input mode (reserved) + + GPIO_OUTPUT_MODE_GP_PUSH_PULL = 0 // Output mode general purpose push/pull + GPIO_OUTPUT_MODE_GP_OPEN_DRAIN = 4 // Output mode general purpose open drain + GPIO_OUTPUT_MODE_ALT_PUSH_PULL = 8 // Output mode alt. purpose push/pull + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN = 12 // Output mode alt. purpose open drain ) const ( @@ -26,20 +40,30 @@ const ( ) func (p GPIO) getPort() *stm32.GPIO_Type { + // Also enable clock for that GPIO port. + // Do this always, as it isn't known whether the clock has already been + // enabled. switch p.Pin / 16 { case 0: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPAEN return stm32.GPIOA case 1: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPBEN return stm32.GPIOB case 2: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPCEN return stm32.GPIOC case 3: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPDEN return stm32.GPIOD case 4: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPEEN return stm32.GPIOE case 5: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPFEN return stm32.GPIOF case 6: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPGEN return stm32.GPIOG default: panic("machine: unknown port") @@ -48,11 +72,6 @@ func (p GPIO) getPort() *stm32.GPIO_Type { // Configure this pin with the given configuration. func (p GPIO) Configure(config GPIOConfig) { - // Enable clock. - // Do this always, as it isn't known whether the clock has already been - // enabled. - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPCEN - // Configure the GPIO pin. port := p.getPort() pin := p.Pin % 16 @@ -75,3 +94,65 @@ func (p GPIO) Set(high bool) { port.BSRR = 1 << (pin + 16) } } + +// UART +var ( + // USART1 is the first hardware serial port on the STM32. + // Both UART0 and UART1 refers to USART1. + UART0 = &UART{} + UART1 = UART0 +) + +// Configure the UART. +func (uart UART) Configure(config UARTConfig) { + // Default baud rate to 115200. + if config.BaudRate == 0 { + config.BaudRate = 115200 + } + + // Enable USART1 clock + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_USART1EN + + // use standard pins PA9 and PA10 + GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz & GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) + GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) + + // uncomment to use alternate pins PB6/PB7 via AFIO mapping + // stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN + // stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP + // GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz & GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) + // GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) + + // Set baud rate + uart.SetBaudRate(config.BaudRate) + + // configure + stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE + + // Enable RX IRQ. + arm.SetPriority(stm32.IRQ_USART1, 0x0) // low priority + arm.EnableIRQ(stm32.IRQ_USART1) +} + +// SetBaudRate sets the communication speed for the UART. +func (uart UART) SetBaudRate(br uint32) { + divider := 8000000 / br + stm32.USART1.BRR = stm32.RegValue(divider) +} + +// WriteByte writes a byte of data to the UART. +func (uart UART) WriteByte(c byte) error { + for (stm32.USART1.SR & stm32.USART_SR_TXE) == 0 { + } + stm32.USART1.DR = stm32.RegValue(c) + return nil +} + +//go:export USART1_IRQHandler +func handleUART0() { + UART0.handleInterrupt() +} + +func (uart UART) handleInterrupt() { + bufferPut(byte((stm32.USART1.DR & 0xFF))) +} diff --git a/src/machine/uart.go b/src/machine/uart.go index 566094fb0d..659c545dfc 100644 --- a/src/machine/uart.go +++ b/src/machine/uart.go @@ -1,4 +1,4 @@ -// +build avr nrf +// +build avr nrf stm32 package machine diff --git a/src/runtime/runtime_stm32.go b/src/runtime/runtime_stm32.go index e068a4d475..798508497d 100644 --- a/src/runtime/runtime_stm32.go +++ b/src/runtime/runtime_stm32.go @@ -4,12 +4,51 @@ package runtime import ( "device/arm" + "device/stm32" + "machine" ) type timeUnit int64 const tickMicros = 1 // TODO +const ( + // Flash Access Control Register flag values. + FLASH_ACR_LATENCY_0 = (0) + FLASH_ACR_LATENCY_1 = (1) + FLASH_ACR_LATENCY_2 = (2) + FLASH_ACR_HLFCYA = (1 << 3) + FLASH_ACR_PRFTBE = (1 << 4) + FLASH_ACR_PRFTBS = (1 << 5) + + // Reset and Clock Control Control Register flag values. + RCC_CFGR_SW_HSI = (0 << 0) + RCC_CFGR_SW_HSE = (1 << 0) + RCC_CFGR_SW_PLL = (2 << 0) + + RCC_CFGR_PPRE1_DIV_NONE = (0 << 8) + RCC_CFGR_PPRE1_DIV_2 = ((1 << 10) | (0 << 8)) + RCC_CFGR_PPRE1_DIV_4 = ((1 << 10) | (1 << 8)) + RCC_CFGR_PPRE1_DIV_8 = ((1 << 10) | (2 << 8)) + RCC_CFGR_PPRE1_DIV_16 = ((1 << 10) | (3 << 8)) + + RCC_CFGR_PLLMUL_2 = (0 << 18) + RCC_CFGR_PLLMUL_3 = (1 << 18) + RCC_CFGR_PLLMUL_4 = (2 << 18) + RCC_CFGR_PLLMUL_5 = (3 << 18) + RCC_CFGR_PLLMUL_6 = (4 << 18) + RCC_CFGR_PLLMUL_7 = (5 << 18) + RCC_CFGR_PLLMUL_8 = (6 << 18) + RCC_CFGR_PLLMUL_9 = (7 << 18) + RCC_CFGR_PLLMUL_10 = (8 << 18) + RCC_CFGR_PLLMUL_11 = (9 << 18) + RCC_CFGR_PLLMUL_12 = (10 << 18) + RCC_CFGR_PLLMUL_13 = (11 << 18) + RCC_CFGR_PLLMUL_14 = (12 << 18) + RCC_CFGR_PLLMUL_15 = (13 << 18) + RCC_CFGR_PLLMUL_16 = (14 << 18) +) + //go:export Reset_Handler func main() { preinit() @@ -18,8 +57,37 @@ func main() { abort() } +func init() { + initCLK() + machine.UART0.Configure(machine.UARTConfig{}) +} + func putchar(c byte) { - // TODO + machine.UART0.WriteByte(c) +} + +func initCLK() { + stm32.FLASH.ACR |= FLASH_ACR_LATENCY_2 // Two wait states, per datasheet + stm32.RCC.CFGR |= RCC_CFGR_PPRE1_DIV_2 // prescale AHB1 = HCLK/2 + stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock + + // wait for the HSEREADY flag + for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 { + } + + stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC // set PLL source to HSE + stm32.RCC.CFGR |= RCC_CFGR_PLLMUL_9 // multiply by 9 + stm32.RCC.CR |= stm32.RCC_CR_PLLON // enable the PLL + + // wait for the PLLRDY flag + for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 { + } + + stm32.RCC.CFGR |= RCC_CFGR_SW_PLL // set clock source to pll + + // wait for PLL to be CLK + for (stm32.RCC.CFGR & RCC_CFGR_SW_PLL) == 0 { + } } func sleepTicks(d timeUnit) { From 67ab338ba94780af084d2390ba396624a73878c9 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Fri, 14 Dec 2018 13:31:52 +0100 Subject: [PATCH 2/6] machine/stm32: fully functional UART0 for STM32F103C8T6 aka Bluepill Signed-off-by: Ron Evans --- src/machine/machine_stm32.go | 34 ++++++++++-------- src/machine/uart.go | 2 ++ src/runtime/runtime_stm32.go | 69 +++++++++++++++++++----------------- 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/machine/machine_stm32.go b/src/machine/machine_stm32.go index 7bd40df06b..2ad0852d06 100644 --- a/src/machine/machine_stm32.go +++ b/src/machine/machine_stm32.go @@ -11,6 +11,8 @@ import ( type GPIOMode uint8 +const SystemClockSpeed = 72000000 + const ( GPIO_INPUT = 0 // Input mode GPIO_OUTPUT_10MHz = 1 // Output mode, max speed 10MHz @@ -110,41 +112,45 @@ func (uart UART) Configure(config UARTConfig) { config.BaudRate = 115200 } + // pins + switch config.TXPin { + case PB6: + // use alternate TX/RX pins PB6/PB7 via AFIO mapping + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN + stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP + GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) + GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) + default: + // use standard TX/RX pins PA9 and PA10 + GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) + GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) + } + // Enable USART1 clock stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_USART1EN - // use standard pins PA9 and PA10 - GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz & GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) - GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) - - // uncomment to use alternate pins PB6/PB7 via AFIO mapping - // stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN - // stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP - // GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz & GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) - // GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) - // Set baud rate uart.SetBaudRate(config.BaudRate) - // configure + // Enable USART1 port. stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE // Enable RX IRQ. - arm.SetPriority(stm32.IRQ_USART1, 0x0) // low priority arm.EnableIRQ(stm32.IRQ_USART1) } // SetBaudRate sets the communication speed for the UART. func (uart UART) SetBaudRate(br uint32) { - divider := 8000000 / br + divider := SystemClockSpeed / br stm32.USART1.BRR = stm32.RegValue(divider) } // WriteByte writes a byte of data to the UART. func (uart UART) WriteByte(c byte) error { + stm32.USART1.DR = stm32.RegValue(c) + for (stm32.USART1.SR & stm32.USART_SR_TXE) == 0 { } - stm32.USART1.DR = stm32.RegValue(c) return nil } diff --git a/src/machine/uart.go b/src/machine/uart.go index 659c545dfc..55eb5b2304 100644 --- a/src/machine/uart.go +++ b/src/machine/uart.go @@ -6,6 +6,8 @@ import "errors" type UARTConfig struct { BaudRate uint32 + TXPin uint8 + RXPin uint8 } type UART struct { diff --git a/src/runtime/runtime_stm32.go b/src/runtime/runtime_stm32.go index 798508497d..7a7599c96a 100644 --- a/src/runtime/runtime_stm32.go +++ b/src/runtime/runtime_stm32.go @@ -14,39 +14,43 @@ const tickMicros = 1 // TODO const ( // Flash Access Control Register flag values. - FLASH_ACR_LATENCY_0 = (0) - FLASH_ACR_LATENCY_1 = (1) - FLASH_ACR_LATENCY_2 = (2) - FLASH_ACR_HLFCYA = (1 << 3) - FLASH_ACR_PRFTBE = (1 << 4) - FLASH_ACR_PRFTBS = (1 << 5) + FLASH_ACR_LATENCY_0 = 0x00000004 + FLASH_ACR_LATENCY_1 = 0x00000002 + FLASH_ACR_LATENCY_2 = 0x00000004 + FLASH_ACR_HLFCYA = 0x00000008 + FLASH_ACR_PRFTBE = 0x00000010 + FLASH_ACR_PRFTBS = 0x00000020 // Reset and Clock Control Control Register flag values. - RCC_CFGR_SW_HSI = (0 << 0) - RCC_CFGR_SW_HSE = (1 << 0) - RCC_CFGR_SW_PLL = (2 << 0) - - RCC_CFGR_PPRE1_DIV_NONE = (0 << 8) - RCC_CFGR_PPRE1_DIV_2 = ((1 << 10) | (0 << 8)) - RCC_CFGR_PPRE1_DIV_4 = ((1 << 10) | (1 << 8)) - RCC_CFGR_PPRE1_DIV_8 = ((1 << 10) | (2 << 8)) - RCC_CFGR_PPRE1_DIV_16 = ((1 << 10) | (3 << 8)) - - RCC_CFGR_PLLMUL_2 = (0 << 18) - RCC_CFGR_PLLMUL_3 = (1 << 18) - RCC_CFGR_PLLMUL_4 = (2 << 18) - RCC_CFGR_PLLMUL_5 = (3 << 18) - RCC_CFGR_PLLMUL_6 = (4 << 18) - RCC_CFGR_PLLMUL_7 = (5 << 18) - RCC_CFGR_PLLMUL_8 = (6 << 18) - RCC_CFGR_PLLMUL_9 = (7 << 18) - RCC_CFGR_PLLMUL_10 = (8 << 18) - RCC_CFGR_PLLMUL_11 = (9 << 18) - RCC_CFGR_PLLMUL_12 = (10 << 18) - RCC_CFGR_PLLMUL_13 = (11 << 18) - RCC_CFGR_PLLMUL_14 = (12 << 18) - RCC_CFGR_PLLMUL_15 = (13 << 18) - RCC_CFGR_PLLMUL_16 = (14 << 18) + RCC_CFGR_SW_HSI = 0 + RCC_CFGR_SW_HSE = 1 + RCC_CFGR_SW_PLL = 2 + + RCC_CFGR_SWS_HSI = 0x00000000 + RCC_CFGR_SWS_HSE = 0x00000004 + RCC_CFGR_SWS_PLL = 0x00000008 + + RCC_CFGR_PPRE1_DIV_NONE = 0x00000000 + RCC_CFGR_PPRE1_DIV_2 = 0x00000400 + RCC_CFGR_PPRE1_DIV_4 = 0x00000500 + RCC_CFGR_PPRE1_DIV_8 = 0x00000600 + RCC_CFGR_PPRE1_DIV_16 = 0x00000700 + + RCC_CFGR_PLLMUL_2 = 0x00000000 + RCC_CFGR_PLLMUL_3 = 0x00040000 + RCC_CFGR_PLLMUL_4 = 0x00080000 + RCC_CFGR_PLLMUL_5 = 0x000C0000 + RCC_CFGR_PLLMUL_6 = 0x00100000 + RCC_CFGR_PLLMUL_7 = 0x00140000 + RCC_CFGR_PLLMUL_8 = 0x00180000 + RCC_CFGR_PLLMUL_9 = 0x001C0000 + RCC_CFGR_PLLMUL_10 = 0x00200000 + RCC_CFGR_PLLMUL_11 = 0x00240000 + RCC_CFGR_PLLMUL_12 = 0x00280000 + RCC_CFGR_PLLMUL_13 = 0x002C0000 + RCC_CFGR_PLLMUL_14 = 0x00300000 + RCC_CFGR_PLLMUL_15 = 0x00340000 + RCC_CFGR_PLLMUL_16 = 0x00380000 ) //go:export Reset_Handler @@ -66,6 +70,7 @@ func putchar(c byte) { machine.UART0.WriteByte(c) } +// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz). func initCLK() { stm32.FLASH.ACR |= FLASH_ACR_LATENCY_2 // Two wait states, per datasheet stm32.RCC.CFGR |= RCC_CFGR_PPRE1_DIV_2 // prescale AHB1 = HCLK/2 @@ -86,7 +91,7 @@ func initCLK() { stm32.RCC.CFGR |= RCC_CFGR_SW_PLL // set clock source to pll // wait for PLL to be CLK - for (stm32.RCC.CFGR & RCC_CFGR_SW_PLL) == 0 { + for (stm32.RCC.CFGR & RCC_CFGR_SWS_PLL) == 0 { } } From ef4fdf8818f182f5fae0738f1ba3a0c77448bf41 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Mon, 17 Dec 2018 15:42:59 +0100 Subject: [PATCH 3/6] machine/stm32: complete support for stm32f103xx UART and leave room for future board imeplementation Signed-off-by: Ron Evans --- src/device/stm32/stm32f103xx-bitfields.go | 44 ++++++ src/machine/machine_stm32.go | 147 ------------------- src/machine/machine_stm32f103xx.go | 165 ++++++++++++++++++++++ src/machine/uart.go | 4 +- src/runtime/runtime_stm32.go | 94 ------------ src/runtime/runtime_stm32f103xx.go | 56 ++++++++ 6 files changed, 267 insertions(+), 243 deletions(-) create mode 100644 src/device/stm32/stm32f103xx-bitfields.go create mode 100644 src/machine/machine_stm32f103xx.go create mode 100644 src/runtime/runtime_stm32f103xx.go diff --git a/src/device/stm32/stm32f103xx-bitfields.go b/src/device/stm32/stm32f103xx-bitfields.go new file mode 100644 index 0000000000..127c27322f --- /dev/null +++ b/src/device/stm32/stm32f103xx-bitfields.go @@ -0,0 +1,44 @@ +// Hand created file. DO NOT DELETE. +// STM32F103XX bitfield definitions that are not auto-generated by gen-device-svd.py + +// +build stm32,stm32f103xx + +package stm32 + +const ( + // Flash Access Control Register flag values. + FLASH_ACR_LATENCY_0 = 0x00000004 + FLASH_ACR_LATENCY_1 = 0x00000002 + FLASH_ACR_LATENCY_2 = 0x00000004 + + // Reset and Clock Control Control Register flag values. + RCC_CFGR_SW_HSI = 0 + RCC_CFGR_SW_HSE = 1 + RCC_CFGR_SW_PLL = 2 + + RCC_CFGR_SWS_HSI = 0x00000000 + RCC_CFGR_SWS_HSE = 0x00000004 + RCC_CFGR_SWS_PLL = 0x00000008 + + RCC_CFGR_PPRE1_DIV_NONE = 0x00000000 + RCC_CFGR_PPRE1_DIV_2 = 0x00000400 + RCC_CFGR_PPRE1_DIV_4 = 0x00000500 + RCC_CFGR_PPRE1_DIV_8 = 0x00000600 + RCC_CFGR_PPRE1_DIV_16 = 0x00000700 + + RCC_CFGR_PLLMUL_2 = 0x00000000 + RCC_CFGR_PLLMUL_3 = 0x00040000 + RCC_CFGR_PLLMUL_4 = 0x00080000 + RCC_CFGR_PLLMUL_5 = 0x000C0000 + RCC_CFGR_PLLMUL_6 = 0x00100000 + RCC_CFGR_PLLMUL_7 = 0x00140000 + RCC_CFGR_PLLMUL_8 = 0x00180000 + RCC_CFGR_PLLMUL_9 = 0x001C0000 + RCC_CFGR_PLLMUL_10 = 0x00200000 + RCC_CFGR_PLLMUL_11 = 0x00240000 + RCC_CFGR_PLLMUL_12 = 0x00280000 + RCC_CFGR_PLLMUL_13 = 0x002C0000 + RCC_CFGR_PLLMUL_14 = 0x00300000 + RCC_CFGR_PLLMUL_15 = 0x00340000 + RCC_CFGR_PLLMUL_16 = 0x00380000 +) diff --git a/src/machine/machine_stm32.go b/src/machine/machine_stm32.go index 2ad0852d06..6c4b447587 100644 --- a/src/machine/machine_stm32.go +++ b/src/machine/machine_stm32.go @@ -4,33 +4,8 @@ package machine // Peripheral abstraction layer for the stm32. -import ( - "device/arm" - "device/stm32" -) - type GPIOMode uint8 -const SystemClockSpeed = 72000000 - -const ( - GPIO_INPUT = 0 // Input mode - GPIO_OUTPUT_10MHz = 1 // Output mode, max speed 10MHz - GPIO_OUTPUT_2MHz = 2 // Output mode, max speed 2MHz - GPIO_OUTPUT_50MHz = 3 // Output mode, max speed 50MHz - GPIO_OUTPUT = GPIO_OUTPUT_2MHz - - GPIO_INPUT_MODE_ANALOG = 0 // Input analog mode - GPIO_INPUT_MODE_FLOATING = 4 // Input floating mode - GPIO_INPUT_MODE_PULL_UP_DOWN = 8 // Input pull up/down mode - GPIO_INPUT_MODE_RESERVED = 12 // Input mode (reserved) - - GPIO_OUTPUT_MODE_GP_PUSH_PULL = 0 // Output mode general purpose push/pull - GPIO_OUTPUT_MODE_GP_OPEN_DRAIN = 4 // Output mode general purpose open drain - GPIO_OUTPUT_MODE_ALT_PUSH_PULL = 8 // Output mode alt. purpose push/pull - GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN = 12 // Output mode alt. purpose open drain -) - const ( portA = iota * 16 portB @@ -40,125 +15,3 @@ const ( portF portG ) - -func (p GPIO) getPort() *stm32.GPIO_Type { - // Also enable clock for that GPIO port. - // Do this always, as it isn't known whether the clock has already been - // enabled. - switch p.Pin / 16 { - case 0: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPAEN - return stm32.GPIOA - case 1: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPBEN - return stm32.GPIOB - case 2: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPCEN - return stm32.GPIOC - case 3: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPDEN - return stm32.GPIOD - case 4: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPEEN - return stm32.GPIOE - case 5: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPFEN - return stm32.GPIOF - case 6: - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPGEN - return stm32.GPIOG - default: - panic("machine: unknown port") - } -} - -// Configure this pin with the given configuration. -func (p GPIO) Configure(config GPIOConfig) { - // Configure the GPIO pin. - port := p.getPort() - pin := p.Pin % 16 - pos := p.Pin % 8 * 4 - if pin < 8 { - port.CRL = stm32.RegValue((uint32(port.CRL) &^ (0xf << pos)) | (uint32(config.Mode) << pos)) - } else { - port.CRH = stm32.RegValue((uint32(port.CRH) &^ (0xf << pos)) | (uint32(config.Mode) << pos)) - } -} - -// Set the pin to high or low. -// Warning: only use this on an output pin! -func (p GPIO) Set(high bool) { - port := p.getPort() - pin := p.Pin % 16 - if high { - port.BSRR = 1 << pin - } else { - port.BSRR = 1 << (pin + 16) - } -} - -// UART -var ( - // USART1 is the first hardware serial port on the STM32. - // Both UART0 and UART1 refers to USART1. - UART0 = &UART{} - UART1 = UART0 -) - -// Configure the UART. -func (uart UART) Configure(config UARTConfig) { - // Default baud rate to 115200. - if config.BaudRate == 0 { - config.BaudRate = 115200 - } - - // pins - switch config.TXPin { - case PB6: - // use alternate TX/RX pins PB6/PB7 via AFIO mapping - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN - stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP - GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) - GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) - default: - // use standard TX/RX pins PA9 and PA10 - GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) - GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) - } - - // Enable USART1 clock - stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_USART1EN - - // Set baud rate - uart.SetBaudRate(config.BaudRate) - - // Enable USART1 port. - stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE - - // Enable RX IRQ. - arm.EnableIRQ(stm32.IRQ_USART1) -} - -// SetBaudRate sets the communication speed for the UART. -func (uart UART) SetBaudRate(br uint32) { - divider := SystemClockSpeed / br - stm32.USART1.BRR = stm32.RegValue(divider) -} - -// WriteByte writes a byte of data to the UART. -func (uart UART) WriteByte(c byte) error { - stm32.USART1.DR = stm32.RegValue(c) - - for (stm32.USART1.SR & stm32.USART_SR_TXE) == 0 { - } - return nil -} - -//go:export USART1_IRQHandler -func handleUART0() { - UART0.handleInterrupt() -} - -func (uart UART) handleInterrupt() { - bufferPut(byte((stm32.USART1.DR & 0xFF))) -} diff --git a/src/machine/machine_stm32f103xx.go b/src/machine/machine_stm32f103xx.go new file mode 100644 index 0000000000..fa9d29d46e --- /dev/null +++ b/src/machine/machine_stm32f103xx.go @@ -0,0 +1,165 @@ +// +build stm32,stm32f103xx + +package machine + +// Peripheral abstraction layer for the stm32. + +import ( + "device/arm" + "device/stm32" +) + +const SystemClockSpeed = 72000000 + +const ( + GPIO_INPUT = 0 // Input mode + GPIO_OUTPUT_10MHz = 1 // Output mode, max speed 10MHz + GPIO_OUTPUT_2MHz = 2 // Output mode, max speed 2MHz + GPIO_OUTPUT_50MHz = 3 // Output mode, max speed 50MHz + GPIO_OUTPUT = GPIO_OUTPUT_2MHz + + GPIO_INPUT_MODE_ANALOG = 0 // Input analog mode + GPIO_INPUT_MODE_FLOATING = 4 // Input floating mode + GPIO_INPUT_MODE_PULL_UP_DOWN = 8 // Input pull up/down mode + GPIO_INPUT_MODE_RESERVED = 12 // Input mode (reserved) + + GPIO_OUTPUT_MODE_GP_PUSH_PULL = 0 // Output mode general purpose push/pull + GPIO_OUTPUT_MODE_GP_OPEN_DRAIN = 4 // Output mode general purpose open drain + GPIO_OUTPUT_MODE_ALT_PUSH_PULL = 8 // Output mode alt. purpose push/pull + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN = 12 // Output mode alt. purpose open drain +) + +func (p GPIO) getPort() *stm32.GPIO_Type { + switch p.Pin / 16 { + case 0: + return stm32.GPIOA + case 1: + return stm32.GPIOB + case 2: + return stm32.GPIOC + case 3: + return stm32.GPIOD + case 4: + return stm32.GPIOE + case 5: + return stm32.GPIOF + case 6: + return stm32.GPIOG + default: + panic("machine: unknown port") + } +} + +// enableClock enables the clock for this desired GPIO port. +func (p GPIO) enableClock() { + switch p.Pin / 16 { + case 0: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPAEN + case 1: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPBEN + case 2: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPCEN + case 3: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPDEN + case 4: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPEEN + case 5: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPFEN + case 6: + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPGEN + default: + panic("machine: unknown port") + } +} + +// Configure this pin with the given configuration. +func (p GPIO) Configure(config GPIOConfig) { + // Configure the GPIO pin. + p.enableClock() + port := p.getPort() + pin := p.Pin % 16 + pos := p.Pin % 8 * 4 + if pin < 8 { + port.CRL = stm32.RegValue((uint32(port.CRL) &^ (0xf << pos)) | (uint32(config.Mode) << pos)) + } else { + port.CRH = stm32.RegValue((uint32(port.CRH) &^ (0xf << pos)) | (uint32(config.Mode) << pos)) + } +} + +// Set the pin to high or low. +// Warning: only use this on an output pin! +func (p GPIO) Set(high bool) { + port := p.getPort() + pin := p.Pin % 16 + if high { + port.BSRR = 1 << pin + } else { + port.BSRR = 1 << (pin + 16) + } +} + +// UART +var ( + // USART1 is the first hardware serial port on the STM32. + // Both UART0 and UART1 refers to USART1. + UART0 = &UART{} + UART1 = UART0 +) + +// Configure the UART. +func (uart UART) Configure(config UARTConfig) { + // Default baud rate to 115200. + if config.BaudRate == 0 { + config.BaudRate = 115200 + } + + // pins + switch config.TX { + case PB6: + // use alternate TX/RX pins PB6/PB7 via AFIO mapping + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN + stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP + GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) + GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) + default: + // use standard TX/RX pins PA9 and PA10 + GPIO{PA9}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL}) + GPIO{PA10}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING}) + } + + // Enable USART1 clock + stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_USART1EN + + // Set baud rate + uart.SetBaudRate(config.BaudRate) + + // Enable USART1 port. + stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE + + // Enable RX IRQ. + arm.EnableIRQ(stm32.IRQ_USART1) +} + +// SetBaudRate sets the communication speed for the UART. +func (uart UART) SetBaudRate(br uint32) { + divider := SystemClockSpeed / br + stm32.USART1.BRR = stm32.RegValue(divider) +} + +// WriteByte writes a byte of data to the UART. +func (uart UART) WriteByte(c byte) error { + stm32.USART1.DR = stm32.RegValue(c) + + for (stm32.USART1.SR & stm32.USART_SR_TXE) == 0 { + } + return nil +} + +//go:export USART1_IRQHandler +func handleUART0() { + UART0.handleInterrupt() +} + +func (uart UART) handleInterrupt() { + bufferPut(byte((stm32.USART1.DR & 0xFF))) +} diff --git a/src/machine/uart.go b/src/machine/uart.go index 55eb5b2304..84f3f08885 100644 --- a/src/machine/uart.go +++ b/src/machine/uart.go @@ -6,8 +6,8 @@ import "errors" type UARTConfig struct { BaudRate uint32 - TXPin uint8 - RXPin uint8 + TX uint8 + RX uint8 } type UART struct { diff --git a/src/runtime/runtime_stm32.go b/src/runtime/runtime_stm32.go index 7a7599c96a..b1eb98df63 100644 --- a/src/runtime/runtime_stm32.go +++ b/src/runtime/runtime_stm32.go @@ -2,57 +2,8 @@ package runtime -import ( - "device/arm" - "device/stm32" - "machine" -) - type timeUnit int64 -const tickMicros = 1 // TODO - -const ( - // Flash Access Control Register flag values. - FLASH_ACR_LATENCY_0 = 0x00000004 - FLASH_ACR_LATENCY_1 = 0x00000002 - FLASH_ACR_LATENCY_2 = 0x00000004 - FLASH_ACR_HLFCYA = 0x00000008 - FLASH_ACR_PRFTBE = 0x00000010 - FLASH_ACR_PRFTBS = 0x00000020 - - // Reset and Clock Control Control Register flag values. - RCC_CFGR_SW_HSI = 0 - RCC_CFGR_SW_HSE = 1 - RCC_CFGR_SW_PLL = 2 - - RCC_CFGR_SWS_HSI = 0x00000000 - RCC_CFGR_SWS_HSE = 0x00000004 - RCC_CFGR_SWS_PLL = 0x00000008 - - RCC_CFGR_PPRE1_DIV_NONE = 0x00000000 - RCC_CFGR_PPRE1_DIV_2 = 0x00000400 - RCC_CFGR_PPRE1_DIV_4 = 0x00000500 - RCC_CFGR_PPRE1_DIV_8 = 0x00000600 - RCC_CFGR_PPRE1_DIV_16 = 0x00000700 - - RCC_CFGR_PLLMUL_2 = 0x00000000 - RCC_CFGR_PLLMUL_3 = 0x00040000 - RCC_CFGR_PLLMUL_4 = 0x00080000 - RCC_CFGR_PLLMUL_5 = 0x000C0000 - RCC_CFGR_PLLMUL_6 = 0x00100000 - RCC_CFGR_PLLMUL_7 = 0x00140000 - RCC_CFGR_PLLMUL_8 = 0x00180000 - RCC_CFGR_PLLMUL_9 = 0x001C0000 - RCC_CFGR_PLLMUL_10 = 0x00200000 - RCC_CFGR_PLLMUL_11 = 0x00240000 - RCC_CFGR_PLLMUL_12 = 0x00280000 - RCC_CFGR_PLLMUL_13 = 0x002C0000 - RCC_CFGR_PLLMUL_14 = 0x00300000 - RCC_CFGR_PLLMUL_15 = 0x00340000 - RCC_CFGR_PLLMUL_16 = 0x00380000 -) - //go:export Reset_Handler func main() { preinit() @@ -60,48 +11,3 @@ func main() { mainWrapper() abort() } - -func init() { - initCLK() - machine.UART0.Configure(machine.UARTConfig{}) -} - -func putchar(c byte) { - machine.UART0.WriteByte(c) -} - -// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz). -func initCLK() { - stm32.FLASH.ACR |= FLASH_ACR_LATENCY_2 // Two wait states, per datasheet - stm32.RCC.CFGR |= RCC_CFGR_PPRE1_DIV_2 // prescale AHB1 = HCLK/2 - stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock - - // wait for the HSEREADY flag - for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 { - } - - stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC // set PLL source to HSE - stm32.RCC.CFGR |= RCC_CFGR_PLLMUL_9 // multiply by 9 - stm32.RCC.CR |= stm32.RCC_CR_PLLON // enable the PLL - - // wait for the PLLRDY flag - for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 { - } - - stm32.RCC.CFGR |= RCC_CFGR_SW_PLL // set clock source to pll - - // wait for PLL to be CLK - for (stm32.RCC.CFGR & RCC_CFGR_SWS_PLL) == 0 { - } -} - -func sleepTicks(d timeUnit) { - // TODO: use a real timer here - for i := 0; i < int(d/535); i++ { - arm.Asm("") - } -} - -func ticks() timeUnit { - return 0 // TODO -} diff --git a/src/runtime/runtime_stm32f103xx.go b/src/runtime/runtime_stm32f103xx.go new file mode 100644 index 0000000000..cd20758ca3 --- /dev/null +++ b/src/runtime/runtime_stm32f103xx.go @@ -0,0 +1,56 @@ +// +build stm32,stm32f103xx + +package runtime + +import ( + "device/arm" + "device/stm32" + "machine" +) + +const tickMicros = 1 // TODO + +func init() { + initCLK() + machine.UART0.Configure(machine.UARTConfig{}) +} + +func putchar(c byte) { + machine.UART0.WriteByte(c) +} + +// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz). +func initCLK() { + stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2 // Two wait states, per datasheet + stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2 // prescale AHB1 = HCLK/2 + stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock + + // wait for the HSEREADY flag + for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 { + } + + stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC // set PLL source to HSE + stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLMUL_9 // multiply by 9 + stm32.RCC.CR |= stm32.RCC_CR_PLLON // enable the PLL + + // wait for the PLLRDY flag + for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 { + } + + stm32.RCC.CFGR |= stm32.RCC_CFGR_SW_PLL // set clock source to pll + + // wait for PLL to be CLK + for (stm32.RCC.CFGR & stm32.RCC_CFGR_SWS_PLL) == 0 { + } +} + +func sleepTicks(d timeUnit) { + // TODO: use a real timer here + for i := 0; i < int(d/535); i++ { + arm.Asm("") + } +} + +func ticks() timeUnit { + return 0 // TODO +} From efdd48bf1dc4ff973f3e3f91a5d9c65285fde128 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Mon, 17 Dec 2018 15:44:36 +0100 Subject: [PATCH 4/6] machine/stm32: correct value for FLASH_ACR_LATENCY_0 flag on stm32f103xx Signed-off-by: Ron Evans --- src/device/stm32/stm32f103xx-bitfields.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device/stm32/stm32f103xx-bitfields.go b/src/device/stm32/stm32f103xx-bitfields.go index 127c27322f..1478074ebb 100644 --- a/src/device/stm32/stm32f103xx-bitfields.go +++ b/src/device/stm32/stm32f103xx-bitfields.go @@ -7,7 +7,7 @@ package stm32 const ( // Flash Access Control Register flag values. - FLASH_ACR_LATENCY_0 = 0x00000004 + FLASH_ACR_LATENCY_0 = 0x00000001 FLASH_ACR_LATENCY_1 = 0x00000002 FLASH_ACR_LATENCY_2 = 0x00000004 From 74b5e8b994c6f50f99a6147bc04ef06776549a01 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Mon, 17 Dec 2018 21:11:16 +0100 Subject: [PATCH 5/6] machine/stm32: change SystemClockSpeed to CPU_FREQUENCY on stm32f103xx Signed-off-by: Ron Evans --- src/machine/machine_stm32f103xx.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/machine_stm32f103xx.go b/src/machine/machine_stm32f103xx.go index fa9d29d46e..63f43a2917 100644 --- a/src/machine/machine_stm32f103xx.go +++ b/src/machine/machine_stm32f103xx.go @@ -9,7 +9,7 @@ import ( "device/stm32" ) -const SystemClockSpeed = 72000000 +const CPU_FREQUENCY = 72000000 const ( GPIO_INPUT = 0 // Input mode @@ -142,7 +142,7 @@ func (uart UART) Configure(config UARTConfig) { // SetBaudRate sets the communication speed for the UART. func (uart UART) SetBaudRate(br uint32) { - divider := SystemClockSpeed / br + divider := CPU_FREQUENCY / br stm32.USART1.BRR = stm32.RegValue(divider) } From f86083f03ecec8c2d0de9f887c091f2851667ce5 Mon Sep 17 00:00:00 2001 From: Ron Evans Date: Mon, 17 Dec 2018 21:17:28 +0100 Subject: [PATCH 6/6] machine/stm32: cleanly use USART1 register for UART1 interface on stm32f103xx Signed-off-by: Ron Evans --- src/machine/machine_stm32f103xx.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/machine/machine_stm32f103xx.go b/src/machine/machine_stm32f103xx.go index 63f43a2917..714b635189 100644 --- a/src/machine/machine_stm32f103xx.go +++ b/src/machine/machine_stm32f103xx.go @@ -156,10 +156,6 @@ func (uart UART) WriteByte(c byte) error { } //go:export USART1_IRQHandler -func handleUART0() { - UART0.handleInterrupt() -} - -func (uart UART) handleInterrupt() { +func handleUART1() { bufferPut(byte((stm32.USART1.DR & 0xFF))) }