machine/stm32: add support for stm32f103xx UART

Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
Ron Evans 2018-12-13 16:12:33 +01:00 коммит произвёл Ayke van Laethem
родитель a830451426
коммит 47b667a4b8
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
6 изменённых файлов: 264 добавлений и 82 удалений

44
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 = 0x00000001
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
)

Просмотреть файл

@ -4,17 +4,8 @@ package machine
// Peripheral abstraction layer for the stm32.
import (
"device/stm32"
)
type GPIOMode uint8
const (
GPIO_INPUT = 0 // Input mode
GPIO_OUTPUT = 2 // Output mode, max speed 2MHz
)
const (
portA = iota * 16
portB
@ -24,54 +15,3 @@ const (
portF
portG
)
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")
}
}
// 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
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)
}
}

161
src/machine/machine_stm32f103xx.go Обычный файл
Просмотреть файл

@ -0,0 +1,161 @@
// +build stm32,stm32f103xx
package machine
// Peripheral abstraction layer for the stm32.
import (
"device/arm"
"device/stm32"
)
const CPU_FREQUENCY = 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 := CPU_FREQUENCY / 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 handleUART1() {
bufferPut(byte((stm32.USART1.DR & 0xFF)))
}

Просмотреть файл

@ -1,4 +1,4 @@
// +build avr nrf
// +build avr nrf stm32
package machine
@ -6,6 +6,8 @@ import "errors"
type UARTConfig struct {
BaudRate uint32
TX uint8
RX uint8
}
type UART struct {

Просмотреть файл

@ -2,14 +2,8 @@
package runtime
import (
"device/arm"
)
type timeUnit int64
const tickMicros = 1 // TODO
//go:export Reset_Handler
func main() {
preinit()
@ -17,18 +11,3 @@ func main() {
mainWrapper()
abort()
}
func putchar(c byte) {
// TODO
}
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
}

56
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
}