cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 timer with toggled output triggered by CCx - is there any way to reset the state of OCxREF at a given point?

LGrov.1
Associate II

I have set up a timer to generate a given waveform using the capture-compare register, fed from DMA. The OCxREF output is set to TOGGLE mode. The waveform consists of a pattern, repeating n times, after each ARR update. A new pattern is loaded into DMA every n cycles.

Everything works, except for the fact that:

  • there seems to be no way of guaranteeing the start point of OCxREF is '0'
  • the OCxREF state appears to change every so often (usually after nth repeat, when new data is loaded into the DMA array), resulting in the pattern becoming inverted.Sometimes this occurs with setting CNT = 0, but not always.
  • At regular intervals, the first timer run (of the n repeats, from '0' to ARR) does NOT react to the DMA settings (or only starts part way through the timer count). This also often then affects the state of OCxREF going forward.

It would help if:

  • I could reliably return OCxREF to '0' at the start of each run of n repeats (I have tried first forcing it low via assignment in OCxM, then to 'toggle', but that doesn't work. Also, OCxCE only seems to respond to ETRF, so cannot clear OCxREF in firmware).
  • I could ensure that in the first 0->ARR interval the CCx is definitely loaded when it should be. I have tried: a) full re-initialisation of both DMA and timer each n-cycle. b) changing the order of initialisation (timer vs DMA) c) preloading the CCx, etc, etc.

I am losing the will to live! Any ideas? I can share code if that helps.

11 REPLIES 11
LGrov.1
Associate II

Gents (@alister​ @Community member​ ),

Many thanks for your input. I have fixed the issues in the following way.

  • At the start of each pulse train I first set the timer to interrupt after an arbitrary short run (ARR=5us).
  • I ensure that during this all CCR values are well outside the window (set them to 0xFFFF), so as not to accidentally capture-compare
  • After this interrupt (on next interrupt) I then set up the pulse train with DMA-driven CCR feed, and off it runs.

In addition, I do the following:

  • DMA is kept disabled when in interrupts, re-enabled just before timer re-start
  • NB: The timers are NEVER reset by setting CNT=0. Instead, I disable UDIS and then trigger a UG, as follows:
TIMx->CR1 &= ~TIM_CR1_CEN;   // Disable the master timer
 
TIMx->CR1 |= TIM_CR1_UDIS;   // Update disabled. UG resets CNT/PRESCALE
 
TIMx->EGR |= TIM_EGR_UG;
 
// wait until the RESET of UG bit
 
while((TIMx->EGR & TIM_EGR_UG) == SET){}
 
TIMx->CR1 &= ~TIM_CR1_UDIS;            // Update enabled

  • Finally, the timer UIF is reset bitwise (&= ~UIF), rather than my previous lazy use of TIMx->SR=0 (!)

All of these factors together seem to give the desired result.

I am still not completely clear as to why I first need to do the 5us interrupt timeout. @alister​ , it may be that your suggestion above would work instead.

I may yet post again on this topic, in an attempt to get final, full clarity.

> Finally, the timer UIF is reset bitwise (&= ~UIF), rather than my previous lazy use of TIMx->SR=0 (!)

Don't use RMW (&=) to clear TIMx_SR bits, use direct write.

JW