tinygo/src/machine/machine_stm32f407.go
2019-05-26 20:48:50 +02:00

220 строки
5,5 КиБ
Go

// +build stm32,stm32f407
package machine
// Peripheral abstraction layer for the stm32.
import (
"device/arm"
"device/stm32"
)
const CPU_FREQUENCY = 168000000
const (
// Mode Flag
PinOutput PinMode = 0
PinInput PinMode = PinInputFloating
PinInputFloating PinMode = 1
PinInputPulldown PinMode = 2
PinInputPullup PinMode = 3
// for UART
PinModeUartTX PinMode = 4
PinModeUartRX PinMode = 5
//GPIOx_MODER
GPIO_MODE_INPUT = 0
GPIO_MODE_GENERAL_OUTPUT = 1
GPIO_MODE_ALTERNABTIVE = 2
GPIO_MODE_ANALOG = 3
//GPIOx_OTYPER
GPIO_OUTPUT_MODE_PUSH_PULL = 0
GPIO_OUTPUT_MODE_OPEN_DRAIN = 1
// GPIOx_OSPEEDR
GPIO_SPEED_LOW = 0
GPIO_SPEED_MID = 1
GPIO_SPEED_HI = 2
GPIO_SPEED_VERY_HI = 3
// GPIOx_PUPDR
GPIO_FLOATING = 0
GPIO_PULL_UP = 1
GPIO_PULL_DOWN = 2
)
func (p Pin) getPort() *stm32.GPIO_Type {
switch p / 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
case 7:
return stm32.GPIOH
case 8:
return stm32.GPIOI
default:
panic("machine: unknown port")
}
}
// enableClock enables the clock for this desired GPIO port.
func (p Pin) enableClock() {
switch p / 16 {
case 0:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOAEN)
case 1:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOBEN)
case 2:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOCEN)
case 3:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIODEN)
case 4:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOEEN)
case 5:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOFEN)
case 6:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOGEN)
case 7:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOHEN)
case 8:
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOIEN)
default:
panic("machine: unknown port")
}
}
// Configure this pin with the given configuration.
func (p Pin) Configure(config PinConfig) {
// Configure the GPIO pin.
p.enableClock()
port := p.getPort()
pin := uint8(p) % 16
pos := pin * 2
if config.Mode == PinInputFloating {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
} else if config.Mode == PinInputPulldown {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_DOWN) << pos)))
} else if config.Mode == PinInputPullup {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
} else if config.Mode == PinOutput {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_GENERAL_OUTPUT) << pos)))
port.OSPEEDR.Set((uint32(port.OSPEEDR.Get())&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
} else if config.Mode == PinModeUartTX {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
port.OSPEEDR.Set((uint32(port.OSPEEDR.Get())&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
p.setAltFunc(0x7)
} else if config.Mode == PinModeUartRX {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
p.setAltFunc(0x7)
}
}
func (p Pin) setAltFunc(af uint32) {
port := p.getPort()
pin := uint8(p) % 16
pos := pin * 4
if pin >= 8 {
port.AFRH.Set(uint32(port.AFRH.Get())&^(0xF<<pos) | ((af & 0xF) << pos))
} else {
port.AFRL.Set(uint32(port.AFRL.Get())&^(0xF<<pos) | ((af & 0xF) << pos))
}
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p Pin) Set(high bool) {
port := p.getPort()
pin := p % 16
if high {
port.BSRR.Set(1 << uint8(pin))
} else {
port.BSRR.Set(1 << uint8(pin+16))
}
}
// UART
type UART struct {
Buffer *RingBuffer
}
var (
// Both UART0 and UART1 refer to USART2.
UART0 = UART{Buffer: NewRingBuffer()}
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 {
default:
// use standard TX/RX pins PA2 and PA3
UART_TX_PIN.Configure(PinConfig{Mode: PinModeUartTX})
UART_RX_PIN.Configure(PinConfig{Mode: PinModeUartRX})
}
// Enable USART2 clock
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN)
/*
Set baud rate(115200)
OVER8 = 0, APB2 = 42mhz
+----------+--------+
| baudrate | BRR |
+----------+--------+
| 1200 | 0x88B8 |
| 2400 | 0x445C |
| 9600 | 0x1117 |
| 19200 | 0x88C |
| 38400 | 0x446 |
| 57600 | 0x2D9 |
| 115200 | 0x16D |
+----------+--------+
*/
stm32.USART2.BRR.Set(0x16c)
// Enable USART2 port.
stm32.USART2.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_USART2, 0xc0)
arm.EnableIRQ(stm32.IRQ_USART2)
}
// WriteByte writes a byte of data to the UART.
func (uart UART) WriteByte(c byte) error {
stm32.USART2.DR.Set(uint32(c))
for (stm32.USART2.SR.Get() & stm32.USART_SR_TXE) == 0 {
}
return nil
}
//go:export USART2_IRQHandler
func handleUSART2() {
UART1.Receive(byte((stm32.USART2.DR.Get() & 0xFF)))
}