diff --git a/src/examples/pwm/nucleo-l552ze.go b/src/examples/pwm/nucleo-l552ze.go new file mode 100644 index 00000000..7ae31dc3 --- /dev/null +++ b/src/examples/pwm/nucleo-l552ze.go @@ -0,0 +1,11 @@ +// +build stm32l5 + +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 160e00ae..89c006eb 100644 --- a/src/machine/machine_stm32_tim.go +++ b/src/machine/machine_stm32_tim.go @@ -1,4 +1,4 @@ -// +build stm32f4 +// +build stm32f4 stm32l5 package machine @@ -8,6 +8,8 @@ import ( "runtime/volatile" ) +const PWM_MODE1 = 0x6 + type TimerCallback func() type ChannelCallback func(channel uint8) @@ -94,7 +96,7 @@ func (t *TIM) SetMatchInterrupt(channel uint8, callback ChannelCallback) error { t.OCInterrupt = t.registerOCInterrupt() // Clear the interrupt flag - t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF_Match << channel) + t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel) // Enable the interrupt t.OCInterrupt.SetPriority(0xc1) diff --git a/src/machine/machine_stm32l5.go b/src/machine/machine_stm32l5.go index 95defa9c..23aba7a0 100644 --- a/src/machine/machine_stm32l5.go +++ b/src/machine/machine_stm32l5.go @@ -6,9 +6,30 @@ package machine import ( "device/stm32" + "runtime/interrupt" + "runtime/volatile" "unsafe" ) +const ( + AF0_SYSTEM = 0 + AF1_TIM1_2_5_8_LPTIM1 = 1 + AF2_TIM1_2_3_4_5_LPTIM3 = 2 + AF3_SPI2_SAI1_I2C4_USART2_TIM1_8_OCTOSPI1 = 3 + AF4_I2C1_2_3_4 = 4 + AF5_SPI1_2_3_I2C4_DFSDM1_OCTOSPI1 = 5 + AF6_SPI3_I2C3_DFSDM1_COMP1 = 6 + AF7_USART1_2_3 = 7 + AF8_UART4_5_LPUART1_SDMMC1 = 8 + AF9_FDCAN1_TSC = 9 + AF10_USB_OCTOSPI1 = 10 + AF11_UCPD1 = 11 + AF12_SDMMC1_COMP1_2_TIM1_8_FMC = 12 + AF13_SAI1_2_TIM8 = 13 + AF14_TIM2_8_15_16_17_LPTIM2 = 14 + AF15_EVENTOUT = 15 +) + const ( PA0 = portA + 0 PA1 = portA + 1 @@ -249,3 +270,220 @@ 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_5_8_LPTIM1}, {PE9, AF1_TIM1_2_5_8_LPTIM1}}}, + TimerChannel{Pins: []PinFunction{{PA9, AF1_TIM1_2_5_8_LPTIM1}, {PE11, AF1_TIM1_2_5_8_LPTIM1}}}, + TimerChannel{Pins: []PinFunction{{PA10, AF1_TIM1_2_5_8_LPTIM1}, {PE13, AF1_TIM1_2_5_8_LPTIM1}}}, + TimerChannel{Pins: []PinFunction{{PA11, AF1_TIM1_2_5_8_LPTIM1}, {PE14, AF1_TIM1_2_5_8_LPTIM1}}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM2 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR1, + EnableFlag: stm32.RCC_APB1ENR1_TIM2EN, + Device: stm32.TIM2, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA0, AF1_TIM1_2_5_8_LPTIM1}, {PA5, AF1_TIM1_2_5_8_LPTIM1}, {PA15, AF1_TIM1_2_5_8_LPTIM1}}}, + TimerChannel{Pins: []PinFunction{{PA1, AF1_TIM1_2_5_8_LPTIM1}, {PB3, AF1_TIM1_2_5_8_LPTIM1}}}, + TimerChannel{Pins: []PinFunction{{PA2, AF1_TIM1_2_5_8_LPTIM1}, {PB10, AF1_TIM1_2_5_8_LPTIM1}}}, + TimerChannel{Pins: []PinFunction{{PA3, AF1_TIM1_2_5_8_LPTIM1}, {PB11, AF1_TIM1_2_5_8_LPTIM1}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM3 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR1, + EnableFlag: stm32.RCC_APB1ENR1_TIM3EN, + Device: stm32.TIM3, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA6, AF2_TIM1_2_3_4_5_LPTIM3}, {PB4, AF2_TIM1_2_3_4_5_LPTIM3}, {PC6, AF2_TIM1_2_3_4_5_LPTIM3}, {PE3, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PA7, AF2_TIM1_2_3_4_5_LPTIM3}, {PB5, AF2_TIM1_2_3_4_5_LPTIM3}, {PC7, AF2_TIM1_2_3_4_5_LPTIM3}, {PE4, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PB0, AF2_TIM1_2_3_4_5_LPTIM3}, {PC8, AF2_TIM1_2_3_4_5_LPTIM3}, {PE5, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PB1, AF2_TIM1_2_3_4_5_LPTIM3}, {PC9, AF2_TIM1_2_3_4_5_LPTIM3}, {PE6, AF2_TIM1_2_3_4_5_LPTIM3}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM4 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR1, + EnableFlag: stm32.RCC_APB1ENR1_TIM4EN, + Device: stm32.TIM4, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PB6, AF2_TIM1_2_3_4_5_LPTIM3}, {PD12, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PB7, AF2_TIM1_2_3_4_5_LPTIM3}, {PD13, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PB8, AF2_TIM1_2_3_4_5_LPTIM3}, {PD14, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PB9, AF2_TIM1_2_3_4_5_LPTIM3}, {PD15, AF2_TIM1_2_3_4_5_LPTIM3}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM5 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR1, + EnableFlag: stm32.RCC_APB1ENR1_TIM5EN, + Device: stm32.TIM5, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA0, AF2_TIM1_2_3_4_5_LPTIM3}, {PF6, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PA1, AF2_TIM1_2_3_4_5_LPTIM3}, {PF7, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PA2, AF2_TIM1_2_3_4_5_LPTIM3}, {PF8, AF2_TIM1_2_3_4_5_LPTIM3}}}, + TimerChannel{Pins: []PinFunction{{PA3, AF2_TIM1_2_3_4_5_LPTIM3}, {PF9, AF2_TIM1_2_3_4_5_LPTIM3}}}, + }, + busFreq: APB1_TIM_FREQ, + } + + TIM6 = TIM{ + EnableRegister: &stm32.RCC.APB1ENR1, + EnableFlag: stm32.RCC_APB1ENR1_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.APB1ENR1, + EnableFlag: stm32.RCC_APB1ENR1_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_SPI2_SAI1_I2C4_USART2_TIM1_8_OCTOSPI1}}}, + TimerChannel{Pins: []PinFunction{{PC7, AF3_SPI2_SAI1_I2C4_USART2_TIM1_8_OCTOSPI1}}}, + TimerChannel{Pins: []PinFunction{{PC8, AF3_SPI2_SAI1_I2C4_USART2_TIM1_8_OCTOSPI1}}}, + TimerChannel{Pins: []PinFunction{{PC9, AF3_SPI2_SAI1_I2C4_USART2_TIM1_8_OCTOSPI1}}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM15 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM15EN, + Device: stm32.TIM15, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA1, AF14_TIM2_8_15_16_17_LPTIM2}, {PB14, AF14_TIM2_8_15_16_17_LPTIM2}, {PF9, AF14_TIM2_8_15_16_17_LPTIM2}, {PG10, AF14_TIM2_8_15_16_17_LPTIM2}}}, + TimerChannel{Pins: []PinFunction{{PA2, AF14_TIM2_8_15_16_17_LPTIM2}, {PB15, AF14_TIM2_8_15_16_17_LPTIM2}, {PF10, AF14_TIM2_8_15_16_17_LPTIM2}, {PG11, AF14_TIM2_8_15_16_17_LPTIM2}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM16 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM16EN, + Device: stm32.TIM16, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA6, AF14_TIM2_8_15_16_17_LPTIM2}, {PB8, AF14_TIM2_8_15_16_17_LPTIM2}, {PE0, AF14_TIM2_8_15_16_17_LPTIM2}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_TIM_FREQ, + } + + TIM17 = TIM{ + EnableRegister: &stm32.RCC.APB2ENR, + EnableFlag: stm32.RCC_APB2ENR_TIM17EN, + Device: stm32.TIM17, + Channels: [4]TimerChannel{ + TimerChannel{Pins: []PinFunction{{PA7, AF14_TIM2_8_15_16_17_LPTIM2}, {PB9, AF14_TIM2_8_15_16_17_LPTIM2}, {PE1, AF14_TIM2_8_15_16_17_LPTIM2}}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + TimerChannel{Pins: []PinFunction{}}, + }, + busFreq: APB2_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) + case &TIM15: + return interrupt.New(stm32.IRQ_TIM15, TIM15.handleUPInterrupt) + case &TIM16: + return interrupt.New(stm32.IRQ_TIM16, TIM16.handleUPInterrupt) + case &TIM17: + return interrupt.New(stm32.IRQ_TIM17, TIM17.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) + case &TIM15: + return interrupt.New(stm32.IRQ_TIM15, TIM15.handleOCInterrupt) + case &TIM16: + return interrupt.New(stm32.IRQ_TIM16, TIM16.handleOCInterrupt) + case &TIM17: + return interrupt.New(stm32.IRQ_TIM17, TIM17.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_stm32l5x2.go b/src/machine/machine_stm32l5x2.go index e00970f4..fc81b274 100644 --- a/src/machine/machine_stm32l5x2.go +++ b/src/machine/machine_stm32l5x2.go @@ -12,6 +12,12 @@ func CPUFrequency() uint32 { return 110000000 } +// 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 = 110e6 // 110MHz +const APB2_TIM_FREQ = 110e6 // 110MHz + //---------- UART related code // Configure the UART. diff --git a/src/runtime/runtime_stm32l5x2.go b/src/runtime/runtime_stm32l5x2.go index e4445080..c8c84200 100644 --- a/src/runtime/runtime_stm32l5x2.go +++ b/src/runtime/runtime_stm32l5x2.go @@ -26,20 +26,6 @@ const ( PLL_R = 2 // RCC_PLLR_DIV2 ) -/* - timer settings used for tick and sleep. - - note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock - settings above, so must be kept in sync if the clock settings are changed. -*/ -const ( - TICK_RATE = 1000 // 1 KHz - SLEEP_TIMER_IRQ = stm32.IRQ_TIM15 - SLEEP_TIMER_FREQ = 110000000 // 110 MHz - TICK_TIMER_IRQ = stm32.IRQ_TIM16 - TICK_TIMER_FREQ = 110000000 // 110 MHz -) - type arrtype = uint32 func init() {