machine/stm32: add support for stm32f103xx UART
Signed-off-by: Ron Evans <ron@hybridgroup.com>
Этот коммит содержится в:
родитель
a830451426
коммит
47b667a4b8
6 изменённых файлов: 264 добавлений и 82 удалений
44
src/device/stm32/stm32f103xx-bitfields.go
Обычный файл
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.
|
// Peripheral abstraction layer for the stm32.
|
||||||
|
|
||||||
import (
|
|
||||||
"device/stm32"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GPIOMode uint8
|
type GPIOMode uint8
|
||||||
|
|
||||||
const (
|
|
||||||
GPIO_INPUT = 0 // Input mode
|
|
||||||
GPIO_OUTPUT = 2 // Output mode, max speed 2MHz
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
portA = iota * 16
|
portA = iota * 16
|
||||||
portB
|
portB
|
||||||
|
@ -24,54 +15,3 @@ const (
|
||||||
portF
|
portF
|
||||||
portG
|
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
Обычный файл
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
|
package machine
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import "errors"
|
||||||
|
|
||||||
type UARTConfig struct {
|
type UARTConfig struct {
|
||||||
BaudRate uint32
|
BaudRate uint32
|
||||||
|
TX uint8
|
||||||
|
RX uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type UART struct {
|
type UART struct {
|
||||||
|
|
|
@ -2,14 +2,8 @@
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
|
||||||
"device/arm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type timeUnit int64
|
type timeUnit int64
|
||||||
|
|
||||||
const tickMicros = 1 // TODO
|
|
||||||
|
|
||||||
//go:export Reset_Handler
|
//go:export Reset_Handler
|
||||||
func main() {
|
func main() {
|
||||||
preinit()
|
preinit()
|
||||||
|
@ -17,18 +11,3 @@ func main() {
|
||||||
mainWrapper()
|
mainWrapper()
|
||||||
abort()
|
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
Обычный файл
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
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче