stm32: add pwm for f4 series
Этот коммит содержится в:
родитель
422ebeeec7
коммит
ee167f15de
7 изменённых файлов: 689 добавлений и 3 удалений
2
Makefile
2
Makefile
|
@ -381,6 +381,8 @@ ifneq ($(STM32), 0)
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/pwm
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
endif
|
endif
|
||||||
ifneq ($(AVR), 0)
|
ifneq ($(AVR), 0)
|
||||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||||
|
|
13
src/examples/pwm/stm32f4disco.go
Обычный файл
13
src/examples/pwm/stm32f4disco.go
Обычный файл
|
@ -0,0 +1,13 @@
|
||||||
|
// +build stm32f4disco
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "machine"
|
||||||
|
|
||||||
|
var (
|
||||||
|
// These pins correspond to LEDs on the discovery
|
||||||
|
// board
|
||||||
|
pwm = &machine.TIM4
|
||||||
|
pinA = machine.PD12
|
||||||
|
pinB = machine.PD13
|
||||||
|
)
|
|
@ -35,7 +35,7 @@ const (
|
||||||
PinInputAnalog PinMode = 11
|
PinInputAnalog PinMode = 11
|
||||||
|
|
||||||
// for PWM
|
// for PWM
|
||||||
// TBD
|
PinModePWMOutput PinMode = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
// Define several bitfields that have different names across chip families but
|
// Define several bitfields that have different names across chip families but
|
||||||
|
@ -135,6 +135,13 @@ func (p Pin) ConfigureAltFunc(config PinConfig, altFunc uint8) {
|
||||||
port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
|
port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
|
||||||
port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
|
port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
|
||||||
p.SetAltFunc(altFunc)
|
p.SetAltFunc(altFunc)
|
||||||
|
|
||||||
|
// PWM
|
||||||
|
case PinModePWMOutput:
|
||||||
|
port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
|
||||||
|
port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos)
|
||||||
|
port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
|
||||||
|
p.SetAltFunc(altFunc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
334
src/machine/machine_stm32_tim.go
Обычный файл
334
src/machine/machine_stm32_tim.go
Обычный файл
|
@ -0,0 +1,334 @@
|
||||||
|
// +build stm32f4
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"runtime/volatile"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TimerCallback func()
|
||||||
|
type ChannelCallback func(channel uint8)
|
||||||
|
|
||||||
|
type PinFunction struct {
|
||||||
|
Pin Pin
|
||||||
|
AltFunc uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimerChannel struct {
|
||||||
|
Pins []PinFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
type TIM struct {
|
||||||
|
EnableRegister *volatile.Register32
|
||||||
|
EnableFlag uint32
|
||||||
|
Device *stm32.TIM_Type
|
||||||
|
Channels [4]TimerChannel
|
||||||
|
UpInterrupt interrupt.Interrupt
|
||||||
|
OCInterrupt interrupt.Interrupt
|
||||||
|
|
||||||
|
wraparoundCallback TimerCallback
|
||||||
|
channelCallbacks [4]ChannelCallback
|
||||||
|
|
||||||
|
busFreq uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure enables and configures this PWM.
|
||||||
|
func (t *TIM) Configure(config PWMConfig) error {
|
||||||
|
// Enable device
|
||||||
|
t.EnableRegister.SetBits(t.EnableFlag)
|
||||||
|
|
||||||
|
err := t.setPeriod(config.Period, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-repeat
|
||||||
|
t.Device.EGR.SetBits(stm32.TIM_EGR_UG)
|
||||||
|
|
||||||
|
// Enable the timer
|
||||||
|
t.Device.CR1.SetBits(stm32.TIM_CR1_CEN | stm32.TIM_CR1_ARPE)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TIM) Count() uint32 {
|
||||||
|
return uint32(t.Device.CNT.Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWraparoundInterrupt configures a callback to be called each
|
||||||
|
// time the timer 'wraps-around'.
|
||||||
|
//
|
||||||
|
// For example, if `Configure(PWMConfig{Period:1000000})` is used,
|
||||||
|
// to set the timer period to 1ms, this callback will be called every
|
||||||
|
// 1ms.
|
||||||
|
func (t *TIM) SetWraparoundInterrupt(callback TimerCallback) error {
|
||||||
|
// Disable this interrupt to prevent race conditions
|
||||||
|
//t.UpInterrupt.Disable()
|
||||||
|
|
||||||
|
// Ensure the interrupt handler for Update events is registered
|
||||||
|
t.UpInterrupt = t.registerUPInterrupt()
|
||||||
|
|
||||||
|
// Clear update flag
|
||||||
|
t.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
|
||||||
|
t.wraparoundCallback = callback
|
||||||
|
t.UpInterrupt.SetPriority(0xc1)
|
||||||
|
t.UpInterrupt.Enable()
|
||||||
|
|
||||||
|
// Enable the hardware interrupt
|
||||||
|
t.Device.DIER.SetBits(stm32.TIM_DIER_UIE)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets a callback to be called when a channel reaches it's set-point.
|
||||||
|
//
|
||||||
|
// For example, if `t.Set(ch, t.Top() / 4)` is used then the callback will
|
||||||
|
// be called every quarter-period of the timer's base Period.
|
||||||
|
func (t *TIM) SetMatchInterrupt(channel uint8, callback ChannelCallback) error {
|
||||||
|
t.channelCallbacks[channel] = callback
|
||||||
|
|
||||||
|
// Ensure the interrupt handler for Output Compare events is registered
|
||||||
|
t.OCInterrupt = t.registerOCInterrupt()
|
||||||
|
|
||||||
|
// Clear the interrupt flag
|
||||||
|
t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF_Match << channel)
|
||||||
|
|
||||||
|
// Enable the interrupt
|
||||||
|
t.OCInterrupt.SetPriority(0xc1)
|
||||||
|
t.OCInterrupt.Enable()
|
||||||
|
|
||||||
|
// Enable the hardware interrupt
|
||||||
|
t.Device.DIER.SetBits(stm32.TIM_DIER_CC1IE << channel)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPeriod updates the period of this PWM peripheral.
|
||||||
|
// To set a particular frequency, use the following formula:
|
||||||
|
//
|
||||||
|
// period = 1e9 / frequency
|
||||||
|
//
|
||||||
|
// If you use a period of 0, a period that works well for LEDs will be picked.
|
||||||
|
//
|
||||||
|
// SetPeriod will not change the prescaler, but also won't change the current
|
||||||
|
// value in any of the channels. This means that you may need to update the
|
||||||
|
// value for the particular channel.
|
||||||
|
//
|
||||||
|
// Note that you cannot pick any arbitrary period after the PWM peripheral has
|
||||||
|
// been configured. If you want to switch between frequencies, pick the lowest
|
||||||
|
// frequency (longest period) once when calling Configure and adjust the
|
||||||
|
// frequency here as needed.
|
||||||
|
func (t *TIM) SetPeriod(period uint64) error {
|
||||||
|
return t.setPeriod(period, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TIM) setPeriod(period uint64, updatePrescaler bool) error {
|
||||||
|
var top uint64
|
||||||
|
if period == 0 {
|
||||||
|
top = ARR_MAX
|
||||||
|
} else {
|
||||||
|
top = (period / 1000) * (t.busFreq / 1000) / 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
var psc uint64
|
||||||
|
if updatePrescaler {
|
||||||
|
if top > ARR_MAX*PSC_MAX {
|
||||||
|
return ErrPWMPeriodTooLong
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the minimum PSC that scales the ARR value into
|
||||||
|
// range to maintain precision in ARR for changing frequencies
|
||||||
|
// later
|
||||||
|
psc = ceil(top, ARR_MAX)
|
||||||
|
top = top / psc
|
||||||
|
|
||||||
|
t.Device.PSC.Set(uint32(psc - 1))
|
||||||
|
} else {
|
||||||
|
psc = uint64(t.Device.PSC.Get()) + 1
|
||||||
|
top = top / psc
|
||||||
|
|
||||||
|
if top > ARR_MAX {
|
||||||
|
return ErrPWMPeriodTooLong
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Device.ARR.Set(arrtype(top - 1))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top returns the current counter top, for use in duty cycle calculation. It
|
||||||
|
// will only change with a call to Configure or SetPeriod, otherwise it is
|
||||||
|
// constant.
|
||||||
|
//
|
||||||
|
// The value returned here is hardware dependent. In general, it's best to treat
|
||||||
|
// it as an opaque value that can be divided by some number and passed to
|
||||||
|
// pwm.Set (see pwm.Set for more information).
|
||||||
|
func (t *TIM) Top() uint32 {
|
||||||
|
return uint32(t.Device.ARR.Get()) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel returns a PWM channel for the given pin.
|
||||||
|
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)
|
||||||
|
return uint8(chi), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0, ErrInvalidOutputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set updates the channel value. This is used to control the channel duty
|
||||||
|
// cycle. For example, to set it to a 25% duty cycle, use:
|
||||||
|
//
|
||||||
|
// t.Set(ch, t.Top() / 4)
|
||||||
|
//
|
||||||
|
// ch.Set(0) will set the output to low and ch.Set(ch.Top()) will set the output
|
||||||
|
// to high, assuming the output isn't inverted.
|
||||||
|
func (t *TIM) Set(channel uint8, value uint32) {
|
||||||
|
t.enableMainOutput()
|
||||||
|
|
||||||
|
ccr := t.channelCCR(channel)
|
||||||
|
ccmr, offset := t.channelCCMR(channel)
|
||||||
|
|
||||||
|
// Disable interrupts whilst programming to prevent spurious OC interrupts
|
||||||
|
mask := interrupt.Disable()
|
||||||
|
|
||||||
|
// Set the PWM to Mode 1 (active below set value, inactive above)
|
||||||
|
// Preload is disabled so we can change OC value within one update period.
|
||||||
|
var ccmrVal uint32
|
||||||
|
ccmrVal |= PWM_MODE1 << stm32.TIM_CCMR1_Output_OC1M_Pos
|
||||||
|
ccmr.ReplaceBits(ccmrVal, 0xFF, offset)
|
||||||
|
|
||||||
|
// Set the compare value
|
||||||
|
ccr.Set(arrtype(value))
|
||||||
|
|
||||||
|
// Enable the channel (if not already)
|
||||||
|
t.Device.CCER.ReplaceBits(stm32.TIM_CCER_CC1E, 0xD, channel*4)
|
||||||
|
|
||||||
|
// Force update
|
||||||
|
t.Device.EGR.SetBits(stm32.TIM_EGR_CC1G << channel)
|
||||||
|
|
||||||
|
// Reset Interrupt Flag
|
||||||
|
t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel)
|
||||||
|
|
||||||
|
// Restore interrupts
|
||||||
|
interrupt.Restore(mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unset disables a channel, including any configured interrupts.
|
||||||
|
func (t *TIM) Unset(channel uint8) {
|
||||||
|
// Disable interrupts whilst programming to prevent spurious OC interrupts
|
||||||
|
mask := interrupt.Disable()
|
||||||
|
|
||||||
|
// Disable the channel
|
||||||
|
t.Device.CCER.ReplaceBits(0, 0xD, channel*4)
|
||||||
|
|
||||||
|
// Reset to zero value
|
||||||
|
ccr := t.channelCCR(channel)
|
||||||
|
ccr.Set(0)
|
||||||
|
|
||||||
|
// Disable the hardware interrupt
|
||||||
|
t.Device.DIER.ClearBits(stm32.TIM_DIER_CC1IE << channel)
|
||||||
|
|
||||||
|
// Clear the interrupt flag
|
||||||
|
t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel)
|
||||||
|
|
||||||
|
// Restore interrupts
|
||||||
|
interrupt.Restore(mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInverting sets whether to invert the output of this channel.
|
||||||
|
// Without inverting, a 25% duty cycle would mean the output is high for 25% of
|
||||||
|
// the time and low for the rest. Inverting flips the output as if a NOT gate
|
||||||
|
// was placed at the output, meaning that the output would be 25% low and 75%
|
||||||
|
// high with a duty cycle of 25%.
|
||||||
|
func (t *TIM) SetInverting(channel uint8, inverting bool) {
|
||||||
|
// Enable the channel (if not already)
|
||||||
|
|
||||||
|
var val = uint32(0)
|
||||||
|
if inverting {
|
||||||
|
val |= stm32.TIM_CCER_CC1P
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Device.CCER.ReplaceBits(val, stm32.TIM_CCER_CC1P_Msk, channel*4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TIM) handleUPInterrupt(interrupt.Interrupt) {
|
||||||
|
if t.Device.SR.HasBits(stm32.TIM_SR_UIF) {
|
||||||
|
// clear the update flag
|
||||||
|
t.Device.SR.ClearBits(stm32.TIM_SR_UIF)
|
||||||
|
|
||||||
|
if t.wraparoundCallback != nil {
|
||||||
|
t.wraparoundCallback()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TIM) handleOCInterrupt(interrupt.Interrupt) {
|
||||||
|
if t.Device.SR.HasBits(stm32.TIM_SR_CC1IF) {
|
||||||
|
if t.channelCallbacks[0] != nil {
|
||||||
|
t.channelCallbacks[0](0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t.Device.SR.HasBits(stm32.TIM_SR_CC2IF) {
|
||||||
|
if t.channelCallbacks[1] != nil {
|
||||||
|
t.channelCallbacks[1](1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t.Device.SR.HasBits(stm32.TIM_SR_CC3IF) {
|
||||||
|
if t.channelCallbacks[2] != nil {
|
||||||
|
t.channelCallbacks[2](2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t.Device.SR.HasBits(stm32.TIM_SR_CC4IF) {
|
||||||
|
if t.channelCallbacks[3] != nil {
|
||||||
|
t.channelCallbacks[3](3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset interrupt flags
|
||||||
|
t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF | stm32.TIM_SR_CC2IF | stm32.TIM_SR_CC3IF | stm32.TIM_SR_CC4IF)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TIM) channelCCR(channel uint8) *arrRegType {
|
||||||
|
switch channel {
|
||||||
|
case 0:
|
||||||
|
return &t.Device.CCR1
|
||||||
|
case 1:
|
||||||
|
return &t.Device.CCR2
|
||||||
|
case 2:
|
||||||
|
return &t.Device.CCR3
|
||||||
|
case 3:
|
||||||
|
return &t.Device.CCR4
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TIM) channelCCMR(channel uint8) (reg *volatile.Register32, offset uint8) {
|
||||||
|
switch channel {
|
||||||
|
case 0:
|
||||||
|
return &t.Device.CCMR1_Output, 0
|
||||||
|
case 1:
|
||||||
|
return &t.Device.CCMR1_Output, 8
|
||||||
|
case 2:
|
||||||
|
return &t.Device.CCMR2_Output, 0
|
||||||
|
case 3:
|
||||||
|
return &t.Device.CCMR2_Output, 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func ceil(num uint64, denom uint64) uint64 {
|
||||||
|
return (num + denom - 1) / denom
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/stm32"
|
"device/stm32"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"runtime/volatile"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -95,8 +97,56 @@ const (
|
||||||
PE14 = portE + 14
|
PE14 = portE + 14
|
||||||
PE15 = portE + 15
|
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
|
||||||
|
|
||||||
PH0 = portH + 0
|
PH0 = portH + 0
|
||||||
PH1 = portH + 1
|
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 {
|
func (p Pin) getPort() *stm32.GPIO_Type {
|
||||||
|
@ -227,3 +277,271 @@ func enableAltFuncClock(bus unsafe.Pointer) {
|
||||||
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN)
|
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{{PH10, AF2_TIM3_4_5}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PH11, AF2_TIM3_4_5}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PH12, AF2_TIM3_4_5}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{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}, {PI5, AF3_TIM8_9_10_11}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PC7, AF3_TIM8_9_10_11}, {PI6, AF3_TIM8_9_10_11}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PC8, AF3_TIM8_9_10_11}, {PI7, AF3_TIM8_9_10_11}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PC9, AF3_TIM8_9_10_11}, {PI2, AF3_TIM8_9_10_11}}},
|
||||||
|
},
|
||||||
|
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}, {PE5, AF3_TIM8_9_10_11}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PA3, AF3_TIM8_9_10_11}, {PE6, AF3_TIM8_9_10_11}}},
|
||||||
|
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}, {PF6, AF3_TIM8_9_10_11}}},
|
||||||
|
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}, {PF7, AF3_TIM8_9_10_11}}},
|
||||||
|
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_CAN2_TIM12_13_14}, {PH6, AF9_CAN1_CAN2_TIM12_13_14}}},
|
||||||
|
TimerChannel{Pins: []PinFunction{{PB15, AF9_CAN1_CAN2_TIM12_13_14}, {PH9, AF9_CAN1_CAN2_TIM12_13_14}}},
|
||||||
|
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_CAN2_TIM12_13_14}, {PF8, AF9_CAN1_CAN2_TIM12_13_14}}},
|
||||||
|
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_CAN2_TIM12_13_14}, {PF9, AF9_CAN1_CAN2_TIM12_13_14}}},
|
||||||
|
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.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_DAC, TIM6.handleOCInterrupt)
|
||||||
|
case &TIM7:
|
||||||
|
return interrupt.New(stm32.IRQ_TIM7, TIM7.handleOCInterrupt)
|
||||||
|
case &TIM8:
|
||||||
|
return interrupt.New(stm32.IRQ_TIM8_UP_TIM13, 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
|
||||||
|
)
|
||||||
|
|
|
@ -13,6 +13,12 @@ func CPUFrequency() uint32 {
|
||||||
return 168000000
|
return 168000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = 42000000 * 2
|
||||||
|
const APB2_TIM_FREQ = 84000000 * 2
|
||||||
|
|
||||||
// Alternative peripheral pin functions
|
// Alternative peripheral pin functions
|
||||||
const (
|
const (
|
||||||
AF0_SYSTEM = 0
|
AF0_SYSTEM = 0
|
||||||
|
|
|
@ -12,6 +12,12 @@ func CPUFrequency() uint32 {
|
||||||
return 168000000
|
return 168000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 = 42000000 * 2
|
||||||
|
const APB2_TIM_FREQ = 84000000 * 2
|
||||||
|
|
||||||
// Alternative peripheral pin functions
|
// Alternative peripheral pin functions
|
||||||
const (
|
const (
|
||||||
AF0_SYSTEM = 0
|
AF0_SYSTEM = 0
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче