diff --git a/src/examples/pwm/bluepill.go b/src/examples/pwm/bluepill.go new file mode 100644 index 00000000..b8fe1c7e --- /dev/null +++ b/src/examples/pwm/bluepill.go @@ -0,0 +1,11 @@ +// +build bluepill + +package main + +import "machine" + +var ( + pwm = &machine.TIM2 + pinA = machine.PA0 + pinB = machine.PA1 +) diff --git a/src/machine/board_bluepill.go b/src/machine/board_bluepill.go index 480aa19e..6d0e4dd9 100644 --- a/src/machine/board_bluepill.go +++ b/src/machine/board_bluepill.go @@ -7,45 +7,6 @@ import ( "runtime/interrupt" ) -// https://wiki.stm32duino.com/index.php?title=File:Bluepillpinout.gif -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 - PC13 = portC + 13 - PC14 = portC + 14 - PC15 = portC + 15 -) - const ( LED = PC13 ) diff --git a/src/machine/board_nucleof103rb.go b/src/machine/board_nucleof103rb.go index 89ce8449..6fa0c27c 100644 --- a/src/machine/board_nucleof103rb.go +++ b/src/machine/board_nucleof103rb.go @@ -7,76 +7,6 @@ import ( "runtime/interrupt" ) -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 -) - const ( LED = LED_BUILTIN LED_BUILTIN = LED_GREEN diff --git a/src/machine/machine_stm32_tim.go b/src/machine/machine_stm32_tim.go index 75dc9c84..1bcd8b76 100644 --- a/src/machine/machine_stm32_tim.go +++ b/src/machine/machine_stm32_tim.go @@ -1,4 +1,4 @@ -// +build stm32f4 stm32l5 stm32l0 stm32l4 stm32l5 stm32f7 +// +build stm32 package machine @@ -178,7 +178,8 @@ func (t *TIM) Channel(pin Pin) (uint8, error) { for chi, ch := range t.Channels { for _, p := range ch.Pins { if p.Pin == pin { - p.Pin.ConfigureAltFunc(PinConfig{Mode: PinModePWMOutput}, p.AltFunc) + t.configurePin(uint8(chi), p) + //p.Pin.ConfigureAltFunc(PinConfig{Mode: PinModePWMOutput}, p.AltFunc) return uint8(chi), nil } } diff --git a/src/machine/machine_stm32_tim_moder.go b/src/machine/machine_stm32_tim_moder.go new file mode 100644 index 00000000..e1c359ba --- /dev/null +++ b/src/machine/machine_stm32_tim_moder.go @@ -0,0 +1,10 @@ +// +build stm32,!stm32f1 + +package machine + +// Configuration of a GPIO pin for PWM output for STM32 MCUs with MODER +// register (most MCUs except STM32F1 series). + +func (t *TIM) configurePin(channel uint8, pf PinFunction) { + pf.Pin.ConfigureAltFunc(PinConfig{Mode: PinModePWMOutput}, pf.AltFunc) +} diff --git a/src/machine/machine_stm32f103.go b/src/machine/machine_stm32f103.go index e7a51898..61469767 100644 --- a/src/machine/machine_stm32f103.go +++ b/src/machine/machine_stm32f103.go @@ -6,6 +6,8 @@ package machine import ( "device/stm32" + "runtime/interrupt" + "runtime/volatile" "unsafe" ) @@ -13,6 +15,12 @@ func CPUFrequency() uint32 { return 72000000 } +// 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 = 72e6 // 72MHz +const APB2_TIM_FREQ = 72e6 // 72MHz + const ( PinInput PinMode = 0 // Input mode PinOutput10MHz PinMode = 1 // Output mode, max speed 10MHz @@ -31,6 +39,111 @@ const ( PinOutputModeAltOpenDrain PinMode = 12 // Output mode alt. purpose open drain ) +// Pin constants for all stm32f103 package sizes +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 + + PF0 = portF + 0 + PF1 = portF + 1 + PF2 = portF + 2 + PF3 = portF + 3 + PF4 = portF + 4 + PF5 = portF + 5 + PF6 = portF + 6 + PF7 = portF + 7 + PF8 = portF + 8 + PF9 = portF + 9 + PF10 = portF + 10 + PF11 = portF + 11 + PF12 = portF + 12 + PF13 = portF + 13 + PF14 = portF + 14 + PF15 = portF + 15 +) + // Configure this pin with the given I/O settings. // stm32f1xx uses different technique for setting the GPIO pins than the stm32f407 func (p Pin) Configure(config PinConfig) { @@ -280,3 +393,285 @@ func (i2c *I2C) getSpeed(config I2CConfig) uint32 { } } } + +//---------- Timer related code + +// For Pin Mappings see RM0008, pg 179 +// https://www.st.com/resource/en/reference_manual/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf +// +// Note: for STM32F1 series the pin mapping is done 'per timer' not per channel, +// not all channels on a timer have the same degrees of flexibility, and some +// combinations are only available on some packages - so care is needed at app +// level to ensure valid combinations of pins are used. +// + +var ( + TIM1 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM1EN, + Device: stm32.TIM1, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PE9, 0b11}, {PA8, 0b00}}}, + TimerChannel{Pins: []PinFunction{{PE11, 0b11}, {PA9, 0b00}}}, + TimerChannel{Pins: []PinFunction{{PE13, 0b11}, {PA10, 0b00}}}, + TimerChannel{Pins: []PinFunction{{PE14, 0b11}, {PA11, 0b00}}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM2 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM2EN, + Device: stm32.TIM2, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA0, 0b00}, {PA15, 0b01}}}, + TimerChannel{Pins: []PinFunction{{PA1, 0b00}, {PB3, 0b01}}}, + TimerChannel{Pins: []PinFunction{{PA2, 0b00}, {PB10, 0b10}}}, + TimerChannel{Pins: []PinFunction{{PA3, 0b00}, {PB11, 0b10}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM3 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM3EN, + Device: stm32.TIM3, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA6, 0b00}, {PC6, 0b11}, {PB4, 0b10}}}, + TimerChannel{Pins: []PinFunction{{PA7, 0b00}, {PC7, 0b11}, {PB5, 0b10}}}, + TimerChannel{Pins: []PinFunction{{PB0, 0b00}, {PC8, 0b11}}}, + TimerChannel{Pins: []PinFunction{{PB1, 0b00}, {PC9, 0b11}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM4 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM4EN, + Device: stm32.TIM4, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PD12, 0b1}, {PB6, 0}}}, + TimerChannel{Pins: []PinFunction{{PD13, 0b1}, {PB7, 0}}}, + TimerChannel{Pins: []PinFunction{{PD14, 0b1}, {PB8, 0}}}, + TimerChannel{Pins: []PinFunction{{PD15, 0b1}, {PB9, 0}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM5 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM5EN, + Device: stm32.TIM5, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{{PA3, 0b0}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM6 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM6EN, + Device: stm32.TIM6, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM7 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM7EN, + Device: stm32.TIM7, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM8 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM8EN, + Device: stm32.TIM8, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM9 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM9EN, + Device: stm32.TIM9, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA2, 0b0}, {PE5, 0b1}}}, + TimerChannel{Pins: []PinFunction{{PA3, 0b0}, {PE6, 0b1}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM10 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM10EN, + Device: stm32.TIM10, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PB8, 0b0}, {PF6, 0b1}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM11 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM11EN, + Device: stm32.TIM11, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PB9, 0b0}, {PF7, 0b1}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM12 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM12EN, + Device: stm32.TIM12, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM13 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM13EN, + Device: stm32.TIM13, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA6, 0b0}, {PF8, 0b1}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM14 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM14EN, + Device: stm32.TIM14, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA7, 0b0}, {PF9, 0b1}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB1_TIM_FREQ, + } +) + +func (t *TIM) registerUPInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_UP, TIM1.handleUPInterrupt) + case &TIM2: + return interrupt.New(stm32.IRQ_TIM2, TIM2.handleUPInterrupt) + case &TIM3: + return interrupt.New(stm32.IRQ_TIM3, TIM3.handleUPInterrupt) + case &TIM4: + return interrupt.New(stm32.IRQ_TIM4, TIM4.handleUPInterrupt) + case &TIM5: + return interrupt.New(stm32.IRQ_TIM5, TIM5.handleUPInterrupt) + case &TIM6: + return interrupt.New(stm32.IRQ_TIM6, TIM6.handleUPInterrupt) + case &TIM7: + return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) + case &TIM8: + return interrupt.New(stm32.IRQ_TIM8_UP, TIM8.handleUPInterrupt) + } + + return interrupt.Interrupt{} +} + +func (t *TIM) registerOCInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleOCInterrupt) + case &TIM2: + return interrupt.New(stm32.IRQ_TIM2, TIM2.handleOCInterrupt) + case &TIM3: + return interrupt.New(stm32.IRQ_TIM3, TIM3.handleOCInterrupt) + case &TIM4: + return interrupt.New(stm32.IRQ_TIM4, TIM4.handleOCInterrupt) + case &TIM5: + return interrupt.New(stm32.IRQ_TIM5, TIM5.handleOCInterrupt) + case &TIM6: + return interrupt.New(stm32.IRQ_TIM6, TIM6.handleOCInterrupt) + case &TIM7: + return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) + case &TIM8: + return interrupt.New(stm32.IRQ_TIM8_CC, TIM8.handleOCInterrupt) + } + + return interrupt.Interrupt{} +} + +func (t *TIM) configurePin(channel uint8, pf PinFunction) { + remap := uint32(pf.AltFunc) + + switch t { + case &TIM1: + stm32.AFIO.MAPR.ReplaceBits(remap<