From ac543023017911548cb2e31db014bf200b769497 Mon Sep 17 00:00:00 2001 From: Kenneth Bell Date: Sun, 9 May 2021 13:26:29 -0700 Subject: [PATCH] stm32f7: add pwm --- src/examples/pwm/nucleo-f722ze.go | 11 + src/machine/machine_stm32_tim.go | 2 +- src/machine/machine_stm32f7.go | 422 +++++++++++++++++++++++++++++- src/machine/machine_stm32f7x2.go | 6 + 4 files changed, 438 insertions(+), 3 deletions(-) create mode 100644 src/examples/pwm/nucleo-f722ze.go diff --git a/src/examples/pwm/nucleo-f722ze.go b/src/examples/pwm/nucleo-f722ze.go new file mode 100644 index 00000000..fdd0f67f --- /dev/null +++ b/src/examples/pwm/nucleo-f722ze.go @@ -0,0 +1,11 @@ +// +build stm32f7 + +package main + +import "machine" + +var ( + pwm = &machine.TIM1 + pinA = machine.PA8 + pinB = machine.PA9 +) diff --git a/src/machine/machine_stm32_tim.go b/src/machine/machine_stm32_tim.go index bfe241d3..75dc9c84 100644 --- a/src/machine/machine_stm32_tim.go +++ b/src/machine/machine_stm32_tim.go @@ -1,4 +1,4 @@ -// +build stm32f4 stm32l5 stm32l0 stm32l4 +// +build stm32f4 stm32l5 stm32l0 stm32l4 stm32l5 stm32f7 package machine diff --git a/src/machine/machine_stm32f7.go b/src/machine/machine_stm32f7.go index a84e19cf..51235709 100644 --- a/src/machine/machine_stm32f7.go +++ b/src/machine/machine_stm32f7.go @@ -6,9 +6,29 @@ package machine import ( "device/stm32" + "runtime/interrupt" + "runtime/volatile" "unsafe" ) +// Alternative peripheral pin functions +const ( + AF0_SYSTEM = 0 + AF1_TIM1_2 = 1 + AF2_TIM3_4_5 = 2 + AF3_TIM8_9_10_11_LPTIM1 = 3 + AF4_I2C1_2_3_USART1 = 4 + AF5_SPI1_2_3_4_5_I2S1_2_3 = 5 + AF6_SPI2_3_I2S2_3_SAI1_UART4 = 6 + AF7_SPI2_3_I2S2_3_USART1_2_3_UART5 = 7 + AF8_SAI2_USART6_UART4_5_7_8_OTG1_FS = 8 + AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS = 9 + AF10_SAI2_QUADSPI_SDMMC2_OTG2_HS_OTG1_FS = 10 + AF11_SDMMC2 = 11 + AF12_UART7_FMC_SDMMC1_OTG2_FS = 12 + AF15_EVENTOUT = 15 +) + const ( PA0 = portA + 0 PA1 = portA + 1 @@ -129,8 +149,39 @@ const ( PG14 = portG + 14 PG15 = portG + 15 - PH0 = portH + 0 - PH1 = portH + 1 + PH0 = portH + 0 + PH1 = portH + 1 + PH2 = portH + 2 + PH3 = portH + 3 + PH4 = portH + 4 + PH5 = portH + 5 + PH6 = portH + 6 + PH7 = portH + 7 + PH8 = portH + 8 + PH9 = portH + 9 + PH10 = portH + 10 + PH11 = portH + 11 + PH12 = portH + 12 + PH13 = portH + 13 + PH14 = portH + 14 + PH15 = portH + 15 + + PI0 = portI + 0 + PI1 = portI + 1 + PI2 = portI + 2 + PI3 = portI + 3 + PI4 = portI + 4 + PI5 = portI + 5 + PI6 = portI + 6 + PI7 = portI + 7 + PI8 = portI + 8 + PI9 = portI + 9 + PI10 = portI + 10 + PI11 = portI + 11 + PI12 = portI + 12 + PI13 = portI + 13 + PI14 = portI + 14 + PI15 = portI + 15 ) func (p Pin) getPort() *stm32.GPIO_Type { @@ -257,3 +308,370 @@ func enableAltFuncClock(bus unsafe.Pointer) { stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN) } } + +//---------- Timer related code + +var ( + TIM1 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM1EN, + Device: stm32.TIM1, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{ + {PA8, AF1_TIM1_2}, + {PE9, AF1_TIM1_2}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA9, AF1_TIM1_2}, + {PE11, AF1_TIM1_2}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA10, AF1_TIM1_2}, + {PE13, AF1_TIM1_2}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA11, AF1_TIM1_2}, + {PE14, AF1_TIM1_2}, + }}, + }, + 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, AF1_TIM1_2}, + {PA5, AF1_TIM1_2}, + {PA15, AF1_TIM1_2}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA1, AF1_TIM1_2}, + {PB3, AF1_TIM1_2}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA2, AF1_TIM1_2}, + {PB10, AF1_TIM1_2}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA3, AF1_TIM1_2}, + {PB11, AF1_TIM1_2}, + }}, + }, + 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, AF2_TIM3_4_5}, + {PB4, AF2_TIM3_4_5}, + {PC6, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA7, AF2_TIM3_4_5}, + {PB5, AF2_TIM3_4_5}, + {PC7, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PB0, AF2_TIM3_4_5}, + {PC8, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PB1, AF2_TIM3_4_5}, + {PC9, AF2_TIM3_4_5}, + }}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM4 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM4EN, + Device: stm32.TIM4, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{ + {PB6, AF2_TIM3_4_5}, + {PD12, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PB7, AF2_TIM3_4_5}, + {PD13, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PB8, AF2_TIM3_4_5}, + {PD14, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PB9, AF2_TIM3_4_5}, + {PD15, AF2_TIM3_4_5}, + }}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM5 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR, + EnableFlag: stm32.RCC_APB1ENR_TIM5EN, + Device: stm32.TIM5, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{ + {PA0, AF2_TIM3_4_5}, + {PH10, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA1, AF2_TIM3_4_5}, + {PH11, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA2, AF2_TIM3_4_5}, + {PH12, AF2_TIM3_4_5}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA3, AF2_TIM3_4_5}, + {PI0, AF2_TIM3_4_5}, + }}, + }, + 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{ + {PC6, AF3_TIM8_9_10_11_LPTIM1}, + {PI5, AF3_TIM8_9_10_11_LPTIM1}, + }}, + TimerChannel{Pins: []PinFunction{ + {PC7, AF3_TIM8_9_10_11_LPTIM1}, + {PI6, AF3_TIM8_9_10_11_LPTIM1}, + }}, + TimerChannel{Pins: []PinFunction{ + {PC8, AF3_TIM8_9_10_11_LPTIM1}, + {PI7, AF3_TIM8_9_10_11_LPTIM1}, + }}, + TimerChannel{Pins: []PinFunction{ + {PC9, AF3_TIM8_9_10_11_LPTIM1}, + {PI2, AF3_TIM8_9_10_11_LPTIM1}, + }}, + }, + 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, AF3_TIM8_9_10_11_LPTIM1}, + {PE5, AF3_TIM8_9_10_11_LPTIM1}, + }}, + TimerChannel{Pins: []PinFunction{ + {PA3, AF3_TIM8_9_10_11_LPTIM1}, + {PE6, AF3_TIM8_9_10_11_LPTIM1}, + }}, + 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, AF3_TIM8_9_10_11_LPTIM1}, + {PF6, AF3_TIM8_9_10_11_LPTIM1}, + }}, + 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, AF3_TIM8_9_10_11_LPTIM1}, + {PF7, AF3_TIM8_9_10_11_LPTIM1}, + }}, + 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{ + {PB14, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + {PH6, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + }}, + TimerChannel{Pins: []PinFunction{ + {PB15, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + {PH9, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + }}, + 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, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + {PF8, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + }}, + 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, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + {PF9, AF9_CAN1_TIM12_13_14_QUADSPI_FMC_OTG2_HS}, + }}, + 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_TIM10, 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_DAC, TIM6.handleUPInterrupt) + case &TIM7: + return interrupt.New(stm32.IRQ_TIM7, TIM7.handleUPInterrupt) + case &TIM8: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM8.handleUPInterrupt) + case &TIM9: + return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleUPInterrupt) + case &TIM10: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleUPInterrupt) + case &TIM11: + return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleUPInterrupt) + case &TIM12: + return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleUPInterrupt) + case &TIM13: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleUPInterrupt) + case &TIM14: + return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleUPInterrupt) + } + + return interrupt.Interrupt{} +} + +func (t *TIM) registerOCInterrupt() interrupt.Interrupt { + switch t { + case &TIM1: + return interrupt.New(stm32.IRQ_TIM1_CC, TIM1.handleUPInterrupt) + 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_DAC, TIM6.handleOCInterrupt) + case &TIM7: + return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt) + case &TIM8: + return interrupt.New(stm32.IRQ_TIM8_CC, TIM8.handleOCInterrupt) + case &TIM9: + return interrupt.New(stm32.IRQ_TIM1_BRK_TIM9, TIM9.handleOCInterrupt) + case &TIM10: + return interrupt.New(stm32.IRQ_TIM1_UP_TIM10, TIM10.handleOCInterrupt) + case &TIM11: + return interrupt.New(stm32.IRQ_TIM1_TRG_COM_TIM11, TIM11.handleOCInterrupt) + case &TIM12: + return interrupt.New(stm32.IRQ_TIM8_BRK_TIM12, TIM12.handleOCInterrupt) + case &TIM13: + return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, TIM13.handleOCInterrupt) + case &TIM14: + return interrupt.New(stm32.IRQ_TIM8_TRG_COM_TIM14, TIM14.handleOCInterrupt) + } + + return interrupt.Interrupt{} +} + +func (t *TIM) enableMainOutput() { + t.Device.BDTR.SetBits(stm32.TIM_BDTR_MOE) +} + +type arrtype = uint32 +type arrRegType = volatile.Register32 + +const ( + ARR_MAX = 0x10000 + PSC_MAX = 0x10000 +) diff --git a/src/machine/machine_stm32f7x2.go b/src/machine/machine_stm32f7x2.go index 376161bb..7035c38c 100644 --- a/src/machine/machine_stm32f7x2.go +++ b/src/machine/machine_stm32f7x2.go @@ -12,6 +12,12 @@ func CPUFrequency() uint32 { return 216000000 } +// 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 = 54e6 // 54MHz +const APB2_TIM_FREQ = 216e6 // 216MHz + //---------- UART related code // Configure the UART.