mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-06 03:53:42 +00:00
4c3680635e
The UART handleInterrupt handler unconditionally read RDR on every interrupt without checking which flag triggered it. On newer STM32 USART peripherals (U5, L4, L5, L0, G0, F7, WL), RXNEIE enables interrupts for both RXFNE (data ready) and ORE (overrun error). Unlike older families (F1, F4), ORE is not cleared by reading the data register, it must be explicitly cleared via the ICR register. When an overrun occurred (e.g. serial data arriving while ADC busy-waits in Get()), ORE would trigger the interrupt, the handler would fire without clearing it, and the interrupt would re-trigger immediately, causing an infinite interrupt storm that locks up the CPU. Fix by: - Checking RXFNE/RXNE (bit 5) before reading data from RDR - Clearing ORE (bit 3) via ICR on newer peripherals when set - Adding errClearReg field to UART struct, set to &Bus.ICR in setRegisters() for all ICR-capable families - Preserving the SR+DR clearing sequence for older F1/F4 families Signed-off-by: deadprogram <ron@hybridgroup.com>
319 lines
8.2 KiB
Go
319 lines
8.2 KiB
Go
//go:build stm32l0
|
|
|
|
package machine
|
|
|
|
// Peripheral abstraction layer for the stm32l0
|
|
|
|
import (
|
|
"device/stm32"
|
|
"runtime/interrupt"
|
|
)
|
|
|
|
func CPUFrequency() uint32 {
|
|
return 32000000
|
|
}
|
|
|
|
var deviceIDAddr = []uintptr{0x1FF80050, 0x1FF80054, 0x1FF80058}
|
|
|
|
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept
|
|
// in sync with any changes to runtime package which configures the oscillators
|
|
// and clock frequencies
|
|
const APB1_TIM_FREQ = 32e6 // 32MHz
|
|
const APB2_TIM_FREQ = 32e6 // 32MHz
|
|
|
|
const (
|
|
PA0 = portA + 0
|
|
PA1 = portA + 1
|
|
PA2 = portA + 2
|
|
PA3 = portA + 3
|
|
PA4 = portA + 4
|
|
PA5 = portA + 5
|
|
PA6 = portA + 6
|
|
PA7 = portA + 7
|
|
PA8 = portA + 8
|
|
PA9 = portA + 9
|
|
PA10 = portA + 10
|
|
PA11 = portA + 11
|
|
PA12 = portA + 12
|
|
PA13 = portA + 13
|
|
PA14 = portA + 14
|
|
PA15 = portA + 15
|
|
|
|
PB0 = portB + 0
|
|
PB1 = portB + 1
|
|
PB2 = portB + 2
|
|
PB3 = portB + 3
|
|
PB4 = portB + 4
|
|
PB5 = portB + 5
|
|
PB6 = portB + 6
|
|
PB7 = portB + 7
|
|
PB8 = portB + 8
|
|
PB9 = portB + 9
|
|
PB10 = portB + 10
|
|
PB11 = portB + 11
|
|
PB12 = portB + 12
|
|
PB13 = portB + 13
|
|
PB14 = portB + 14
|
|
PB15 = portB + 15
|
|
|
|
PC0 = portC + 0
|
|
PC1 = portC + 1
|
|
PC2 = portC + 2
|
|
PC3 = portC + 3
|
|
PC4 = portC + 4
|
|
PC5 = portC + 5
|
|
PC6 = portC + 6
|
|
PC7 = portC + 7
|
|
PC8 = portC + 8
|
|
PC9 = portC + 9
|
|
PC10 = portC + 10
|
|
PC11 = portC + 11
|
|
PC12 = portC + 12
|
|
PC13 = portC + 13
|
|
PC14 = portC + 14
|
|
PC15 = portC + 15
|
|
|
|
PD0 = portD + 0
|
|
PD1 = portD + 1
|
|
PD2 = portD + 2
|
|
PD3 = portD + 3
|
|
PD4 = portD + 4
|
|
PD5 = portD + 5
|
|
PD6 = portD + 6
|
|
PD7 = portD + 7
|
|
PD8 = portD + 8
|
|
PD9 = portD + 9
|
|
PD10 = portD + 10
|
|
PD11 = portD + 11
|
|
PD12 = portD + 12
|
|
PD13 = portD + 13
|
|
PD14 = portD + 14
|
|
PD15 = portD + 15
|
|
|
|
PE0 = portE + 0
|
|
PE1 = portE + 1
|
|
PE2 = portE + 2
|
|
PE3 = portE + 3
|
|
PE4 = portE + 4
|
|
PE5 = portE + 5
|
|
PE6 = portE + 6
|
|
PE7 = portE + 7
|
|
PE8 = portE + 8
|
|
PE9 = portE + 9
|
|
PE10 = portE + 10
|
|
PE11 = portE + 11
|
|
PE12 = portE + 12
|
|
PE13 = portE + 13
|
|
PE14 = portE + 14
|
|
PE15 = portE + 15
|
|
|
|
PH0 = portH + 0
|
|
PH1 = portH + 1
|
|
)
|
|
|
|
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 7:
|
|
return stm32.GPIOH
|
|
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.IOPENR.SetBits(stm32.RCC_IOPENR_IOPAEN)
|
|
case 1:
|
|
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPBEN)
|
|
case 2:
|
|
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPCEN)
|
|
case 3:
|
|
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPDEN)
|
|
case 4:
|
|
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPEEN)
|
|
case 7:
|
|
stm32.RCC.IOPENR.SetBits(stm32.RCC_IOPENR_IOPHEN)
|
|
default:
|
|
panic("machine: unknown port")
|
|
}
|
|
}
|
|
|
|
func (p Pin) registerInterrupt() interrupt.Interrupt {
|
|
pin := uint8(p) % 16
|
|
|
|
switch pin {
|
|
case 0:
|
|
return interrupt.New(stm32.IRQ_EXTI0_1, func(interrupt.Interrupt) { handlePinInterrupt(0) })
|
|
case 1:
|
|
return interrupt.New(stm32.IRQ_EXTI0_1, func(interrupt.Interrupt) { handlePinInterrupt(1) })
|
|
case 2:
|
|
return interrupt.New(stm32.IRQ_EXTI2_3, func(interrupt.Interrupt) { handlePinInterrupt(2) })
|
|
case 3:
|
|
return interrupt.New(stm32.IRQ_EXTI2_3, func(interrupt.Interrupt) { handlePinInterrupt(3) })
|
|
case 4:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(4) })
|
|
case 5:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(5) })
|
|
case 6:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(6) })
|
|
case 7:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(7) })
|
|
case 8:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(8) })
|
|
case 9:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(9) })
|
|
case 10:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(10) })
|
|
case 11:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(11) })
|
|
case 12:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(12) })
|
|
case 13:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(13) })
|
|
case 14:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(14) })
|
|
case 15:
|
|
return interrupt.New(stm32.IRQ_EXTI4_15, func(interrupt.Interrupt) { handlePinInterrupt(15) })
|
|
}
|
|
|
|
return interrupt.Interrupt{}
|
|
}
|
|
|
|
//---------- UART related types and code
|
|
|
|
// Configure the UART.
|
|
func (uart *UART) configurePins(config UARTConfig) {
|
|
// enable the alternate functions on the TX and RX pins
|
|
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
|
|
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
|
}
|
|
|
|
// UART baudrate calc based on the bus and clockspeed
|
|
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
|
|
var clock, rate uint32
|
|
switch uart.Bus {
|
|
case stm32.LPUART1:
|
|
clock = CPUFrequency() / 2 // APB1 Frequency
|
|
rate = uint32((256 * clock) / baudRate)
|
|
case stm32.USART1:
|
|
clock = CPUFrequency() / 2 // APB2 Frequency
|
|
rate = uint32(clock / baudRate)
|
|
case stm32.USART2:
|
|
clock = CPUFrequency() / 2 // APB1 Frequency
|
|
rate = uint32(clock / baudRate)
|
|
}
|
|
|
|
return rate
|
|
}
|
|
|
|
// Register names vary by ST processor, these are for STM L0 family
|
|
func (uart *UART) setRegisters() {
|
|
uart.rxReg = &uart.Bus.RDR
|
|
uart.txReg = &uart.Bus.TDR
|
|
uart.statusReg = &uart.Bus.ISR
|
|
uart.txEmptyFlag = stm32.USART_ISR_TXE
|
|
uart.errClearReg = &uart.Bus.ICR
|
|
}
|
|
|
|
//---------- SPI related types and code
|
|
|
|
// SPI on the STM32Fxxx using MODER / alternate function pins
|
|
type SPI struct {
|
|
Bus *stm32.SPI_Type
|
|
AltFuncSelector uint8
|
|
}
|
|
|
|
func (spi *SPI) config8Bits() {
|
|
// no-op on this series
|
|
}
|
|
|
|
// Set baud rate for SPI
|
|
func (spi *SPI) getBaudRate(config SPIConfig) uint32 {
|
|
var conf uint32
|
|
|
|
localFrequency := config.Frequency
|
|
|
|
// Default
|
|
if config.Frequency == 0 {
|
|
config.Frequency = 4e6
|
|
}
|
|
|
|
if spi.Bus != stm32.SPI1 {
|
|
// Assume it's SPI2 or SPI3 on APB1 at 1/2 the clock frequency of APB2, so
|
|
// we want to pretend to request 2x the baudrate asked for
|
|
localFrequency = localFrequency * 2
|
|
}
|
|
|
|
// set frequency dependent on PCLK prescaler. Since these are rather weird
|
|
// speeds due to the CPU frequency, pick a range up to that frequency for
|
|
// clients to use more human-understandable numbers, e.g. nearest 100KHz
|
|
|
|
// These are based on APB2 clock frequency (84MHz on the discovery board)
|
|
// TODO: also include the MCU/APB clock setting in the equation
|
|
switch {
|
|
case localFrequency < 328125:
|
|
conf = stm32.SPI_CR1_BR_Div256
|
|
case localFrequency < 656250:
|
|
conf = stm32.SPI_CR1_BR_Div128
|
|
case localFrequency < 1312500:
|
|
conf = stm32.SPI_CR1_BR_Div64
|
|
case localFrequency < 2625000:
|
|
conf = stm32.SPI_CR1_BR_Div32
|
|
case localFrequency < 5250000:
|
|
conf = stm32.SPI_CR1_BR_Div16
|
|
case localFrequency < 10500000:
|
|
conf = stm32.SPI_CR1_BR_Div8
|
|
// NOTE: many SPI components won't operate reliably (or at all) above 10MHz
|
|
// Check the datasheet of the part
|
|
case localFrequency < 21000000:
|
|
conf = stm32.SPI_CR1_BR_Div4
|
|
case localFrequency < 42000000:
|
|
conf = stm32.SPI_CR1_BR_Div2
|
|
default:
|
|
// None of the specific baudrates were selected; choose the lowest speed
|
|
conf = stm32.SPI_CR1_BR_Div256
|
|
}
|
|
|
|
return conf << stm32.SPI_CR1_BR_Pos
|
|
}
|
|
|
|
// Configure SPI pins for input output and clock
|
|
func (spi *SPI) configurePins(config SPIConfig) {
|
|
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
|
|
config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
|
|
config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector)
|
|
}
|
|
|
|
//---------- I2C related types and code
|
|
|
|
// Gets the value for TIMINGR register
|
|
func (i2c I2C) getFreqRange(br uint32) uint32 {
|
|
// This is a 'magic' value calculated by STM32CubeMX
|
|
// for 16MHz PCLK1.
|
|
// TODO: Do calculations based on PCLK1
|
|
switch br {
|
|
case 10 * KHz:
|
|
return 0x40003EFF
|
|
case 100 * KHz:
|
|
return 0x00303D5B
|
|
case 400 * KHz:
|
|
return 0x0010061A
|
|
case 500 * KHz:
|
|
return 0x00000117
|
|
default:
|
|
return 0
|
|
}
|
|
}
|