github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/machine_stm32_tim.go (about)

     1  //go:build stm32
     2  
     3  package machine
     4  
     5  // The type alias `arrtype` should be defined to either uint32 or uint16
     6  // depending on the size of that register in the MCU's TIM_Type structure.
     7  
     8  import (
     9  	"device/stm32"
    10  	"runtime/interrupt"
    11  	"runtime/volatile"
    12  )
    13  
    14  const PWM_MODE1 = 0x6
    15  
    16  type TimerCallback func()
    17  type ChannelCallback func(channel uint8)
    18  
    19  type PinFunction struct {
    20  	Pin     Pin
    21  	AltFunc uint8
    22  }
    23  
    24  type TimerChannel struct {
    25  	Pins []PinFunction
    26  }
    27  
    28  type TIM struct {
    29  	EnableRegister *volatile.Register32
    30  	EnableFlag     uint32
    31  	Device         *stm32.TIM_Type
    32  	Channels       [4]TimerChannel
    33  	UpInterrupt    interrupt.Interrupt
    34  	OCInterrupt    interrupt.Interrupt
    35  
    36  	wraparoundCallback TimerCallback
    37  	channelCallbacks   [4]ChannelCallback
    38  
    39  	busFreq uint64
    40  }
    41  
    42  // Configure enables and configures this PWM.
    43  func (t *TIM) Configure(config PWMConfig) error {
    44  	// Enable device
    45  	t.EnableRegister.SetBits(t.EnableFlag)
    46  
    47  	err := t.setPeriod(config.Period, true)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	// Auto-repeat
    53  	t.Device.EGR.SetBits(stm32.TIM_EGR_UG)
    54  
    55  	// Enable the timer
    56  	t.Device.CR1.SetBits(stm32.TIM_CR1_CEN | stm32.TIM_CR1_ARPE)
    57  
    58  	return nil
    59  }
    60  
    61  func (t *TIM) Count() uint32 {
    62  	return uint32(t.Device.CNT.Get())
    63  }
    64  
    65  // SetWraparoundInterrupt configures a callback to be called each
    66  // time the timer 'wraps-around'.
    67  //
    68  // For example, if `Configure(PWMConfig{Period:1000000})` is used,
    69  // to set the timer period to 1ms, this callback will be called every
    70  // 1ms.
    71  func (t *TIM) SetWraparoundInterrupt(callback TimerCallback) error {
    72  	// Disable this interrupt to prevent race conditions
    73  	//t.UpInterrupt.Disable()
    74  
    75  	// Ensure the interrupt handler for Update events is registered
    76  	t.UpInterrupt = t.registerUPInterrupt()
    77  
    78  	// Clear update flag
    79  	t.Device.SR.ClearBits(stm32.TIM_SR_UIF)
    80  
    81  	t.wraparoundCallback = callback
    82  	t.UpInterrupt.SetPriority(0xc1)
    83  	t.UpInterrupt.Enable()
    84  
    85  	// Enable the hardware interrupt
    86  	t.Device.DIER.SetBits(stm32.TIM_DIER_UIE)
    87  
    88  	return nil
    89  }
    90  
    91  // Sets a callback to be called when a channel reaches it's set-point.
    92  //
    93  // For example, if `t.Set(ch, t.Top() / 4)` is used then the callback will
    94  // be called every quarter-period of the timer's base Period.
    95  func (t *TIM) SetMatchInterrupt(channel uint8, callback ChannelCallback) error {
    96  	t.channelCallbacks[channel] = callback
    97  
    98  	// Ensure the interrupt handler for Output Compare events is registered
    99  	t.OCInterrupt = t.registerOCInterrupt()
   100  
   101  	// Clear the interrupt flag
   102  	t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel)
   103  
   104  	// Enable the interrupt
   105  	t.OCInterrupt.SetPriority(0xc1)
   106  	t.OCInterrupt.Enable()
   107  
   108  	// Enable the hardware interrupt
   109  	t.Device.DIER.SetBits(stm32.TIM_DIER_CC1IE << channel)
   110  
   111  	return nil
   112  }
   113  
   114  // SetPeriod updates the period of this PWM peripheral.
   115  // To set a particular frequency, use the following formula:
   116  //
   117  //	period = 1e9 / frequency
   118  //
   119  // If you use a period of 0, a period that works well for LEDs will be picked.
   120  //
   121  // SetPeriod will not change the prescaler, but also won't change the current
   122  // value in any of the channels. This means that you may need to update the
   123  // value for the particular channel.
   124  //
   125  // Note that you cannot pick any arbitrary period after the PWM peripheral has
   126  // been configured. If you want to switch between frequencies, pick the lowest
   127  // frequency (longest period) once when calling Configure and adjust the
   128  // frequency here as needed.
   129  func (t *TIM) SetPeriod(period uint64) error {
   130  	return t.setPeriod(period, false)
   131  }
   132  
   133  func (t *TIM) setPeriod(period uint64, updatePrescaler bool) error {
   134  	var top uint64
   135  	if period == 0 {
   136  		top = ARR_MAX
   137  	} else {
   138  		top = (period / 1000) * (t.busFreq / 1000) / 1000
   139  	}
   140  
   141  	var psc uint64
   142  	if updatePrescaler {
   143  		if top > ARR_MAX*PSC_MAX {
   144  			return ErrPWMPeriodTooLong
   145  		}
   146  
   147  		// Select the minimum PSC that scales the ARR value into
   148  		// range to maintain precision in ARR for changing frequencies
   149  		// later
   150  		psc = ceil(top, ARR_MAX)
   151  		top = top / psc
   152  
   153  		t.Device.PSC.Set(uint32(psc - 1))
   154  	} else {
   155  		psc = uint64(t.Device.PSC.Get()) + 1
   156  		top = top / psc
   157  
   158  		if top > ARR_MAX {
   159  			return ErrPWMPeriodTooLong
   160  		}
   161  	}
   162  
   163  	t.Device.ARR.Set(arrtype(top - 1))
   164  	return nil
   165  }
   166  
   167  // Top returns the current counter top, for use in duty cycle calculation. It
   168  // will only change with a call to Configure or SetPeriod, otherwise it is
   169  // constant.
   170  //
   171  // The value returned here is hardware dependent. In general, it's best to treat
   172  // it as an opaque value that can be divided by some number and passed to
   173  // pwm.Set (see pwm.Set for more information).
   174  func (t *TIM) Top() uint32 {
   175  	return uint32(t.Device.ARR.Get()) + 1
   176  }
   177  
   178  // Channel returns a PWM channel for the given pin.
   179  func (t *TIM) Channel(pin Pin) (uint8, error) {
   180  
   181  	for chi, ch := range t.Channels {
   182  		for _, p := range ch.Pins {
   183  			if p.Pin == pin {
   184  				t.configurePin(uint8(chi), p)
   185  				//p.Pin.ConfigureAltFunc(PinConfig{Mode: PinModePWMOutput}, p.AltFunc)
   186  				return uint8(chi), nil
   187  			}
   188  		}
   189  	}
   190  
   191  	return 0, ErrInvalidOutputPin
   192  }
   193  
   194  // Set updates the channel value. This is used to control the channel duty
   195  // cycle. For example, to set it to a 25% duty cycle, use:
   196  //
   197  //	t.Set(ch, t.Top() / 4)
   198  //
   199  // ch.Set(0) will set the output to low and ch.Set(ch.Top()) will set the output
   200  // to high, assuming the output isn't inverted.
   201  func (t *TIM) Set(channel uint8, value uint32) {
   202  	t.enableMainOutput()
   203  
   204  	ccr := t.channelCCR(channel)
   205  	ccmr, offset := t.channelCCMR(channel)
   206  
   207  	// Disable interrupts whilst programming to prevent spurious OC interrupts
   208  	mask := interrupt.Disable()
   209  
   210  	// Set the PWM to Mode 1 (active below set value, inactive above)
   211  	// Preload is disabled so we can change OC value within one update period.
   212  	var ccmrVal uint32
   213  	ccmrVal |= PWM_MODE1 << stm32.TIM_CCMR1_Output_OC1M_Pos
   214  	ccmr.ReplaceBits(ccmrVal, 0xFF, offset)
   215  
   216  	// Set the compare value
   217  	ccr.Set(arrtype(value))
   218  
   219  	// Enable the channel (if not already)
   220  	t.Device.CCER.ReplaceBits(stm32.TIM_CCER_CC1E, 0xD, channel*4)
   221  
   222  	// Force update
   223  	t.Device.EGR.SetBits(stm32.TIM_EGR_CC1G << channel)
   224  
   225  	// Reset Interrupt Flag
   226  	t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel)
   227  
   228  	// Restore interrupts
   229  	interrupt.Restore(mask)
   230  }
   231  
   232  // Unset disables a channel, including any configured interrupts.
   233  func (t *TIM) Unset(channel uint8) {
   234  	// Disable interrupts whilst programming to prevent spurious OC interrupts
   235  	mask := interrupt.Disable()
   236  
   237  	// Disable the channel
   238  	t.Device.CCER.ReplaceBits(0, 0xD, channel*4)
   239  
   240  	// Reset to zero value
   241  	ccr := t.channelCCR(channel)
   242  	ccr.Set(0)
   243  
   244  	// Disable the hardware interrupt
   245  	t.Device.DIER.ClearBits(stm32.TIM_DIER_CC1IE << channel)
   246  
   247  	// Clear the interrupt flag
   248  	t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF << channel)
   249  
   250  	// Restore interrupts
   251  	interrupt.Restore(mask)
   252  }
   253  
   254  // SetInverting sets whether to invert the output of this channel.
   255  // Without inverting, a 25% duty cycle would mean the output is high for 25% of
   256  // the time and low for the rest. Inverting flips the output as if a NOT gate
   257  // was placed at the output, meaning that the output would be 25% low and 75%
   258  // high with a duty cycle of 25%.
   259  func (t *TIM) SetInverting(channel uint8, inverting bool) {
   260  	// Enable the channel (if not already)
   261  
   262  	var val = uint32(0)
   263  	if inverting {
   264  		val |= stm32.TIM_CCER_CC1P
   265  	}
   266  
   267  	t.Device.CCER.ReplaceBits(val, stm32.TIM_CCER_CC1P_Msk, channel*4)
   268  }
   269  
   270  func (t *TIM) handleUPInterrupt(interrupt.Interrupt) {
   271  	if t.Device.SR.HasBits(stm32.TIM_SR_UIF) {
   272  		// clear the update flag
   273  		t.Device.SR.ClearBits(stm32.TIM_SR_UIF)
   274  
   275  		if t.wraparoundCallback != nil {
   276  			t.wraparoundCallback()
   277  		}
   278  	}
   279  }
   280  
   281  func (t *TIM) handleOCInterrupt(interrupt.Interrupt) {
   282  	if t.Device.SR.HasBits(stm32.TIM_SR_CC1IF) {
   283  		if t.channelCallbacks[0] != nil {
   284  			t.channelCallbacks[0](0)
   285  		}
   286  	}
   287  	if t.Device.SR.HasBits(stm32.TIM_SR_CC2IF) {
   288  		if t.channelCallbacks[1] != nil {
   289  			t.channelCallbacks[1](1)
   290  		}
   291  	}
   292  	if t.Device.SR.HasBits(stm32.TIM_SR_CC3IF) {
   293  		if t.channelCallbacks[2] != nil {
   294  			t.channelCallbacks[2](2)
   295  		}
   296  	}
   297  	if t.Device.SR.HasBits(stm32.TIM_SR_CC4IF) {
   298  		if t.channelCallbacks[3] != nil {
   299  			t.channelCallbacks[3](3)
   300  		}
   301  	}
   302  
   303  	// Reset interrupt flags
   304  	t.Device.SR.ClearBits(stm32.TIM_SR_CC1IF | stm32.TIM_SR_CC2IF | stm32.TIM_SR_CC3IF | stm32.TIM_SR_CC4IF)
   305  }
   306  
   307  func (t *TIM) channelCCR(channel uint8) *arrRegType {
   308  	switch channel {
   309  	case 0:
   310  		return &t.Device.CCR1
   311  	case 1:
   312  		return &t.Device.CCR2
   313  	case 2:
   314  		return &t.Device.CCR3
   315  	case 3:
   316  		return &t.Device.CCR4
   317  	}
   318  
   319  	return nil
   320  }
   321  
   322  func (t *TIM) channelCCMR(channel uint8) (reg *volatile.Register32, offset uint8) {
   323  	switch channel {
   324  	case 0:
   325  		return &t.Device.CCMR1_Output, 0
   326  	case 1:
   327  		return &t.Device.CCMR1_Output, 8
   328  	case 2:
   329  		return &t.Device.CCMR2_Output, 0
   330  	case 3:
   331  		return &t.Device.CCMR2_Output, 8
   332  	}
   333  
   334  	return nil, 0
   335  }
   336  
   337  //go:inline
   338  func ceil(num uint64, denom uint64) uint64 {
   339  	return (num + denom - 1) / denom
   340  }