cancel
Showing results for 
Search instead for 
Did you mean: 

Asymmetric PWM centre-aligned with update event 180 degrees out of phase with pulse

rleigh-electradx
Associate II

Hi folks, I'm using one timer to generate a pulse train (TIM4), and a second slave timer to count the pulses (TIM8).  This is on an STM32U575.

I have this working nicely using a timer with centre aligned mode 3 for the counter mode, with the channel using asymmetric PWM mode 2.  I set CCR1 and CCR2 to high values near the ARR value and this generates a small pulse of whatever duration is needed.  The slave timer prescaler divides the update events by two, so I count up on every two update events, and this occurs when the underflow update event occurs.  This results in the update events being 180 degrees out of phase with the pulses, which is exactly what I need.

However, I would like to dynamically adjust the frequency through DMA updates of ARR.  Ideally, I would avoid any CCR1 or CCR2 updates and just update ARR only.  To do this, I'd like to use asymmetric PWM mode 1 and use fixed low values for CCR1 and CCR2.  This would allow ARR updates without any CCR1 or CCR2 updates.

The problem I have is that the counter update ends up being in phase with the pulse generation:

rleighelectradx_0-1759612189810.jpeg

I'd like to shift it 180 degrees so it happens on counter overflow, not on underflow.

I've tried to start the timer with the direction set to down and CNT set to a high value near ARR so that the first update event is on underflow, and the second update event which will increment the counter is on overflow.  However, no matter which way I have tried it, I can't get this to work!

 

 

  // Master timer (TIM4) - start in down-count mode
  LL_TIM_SetCounter(TIM4, LL_TIM_GetAutoReload(TIM4) - 2);
  TIM4->CR1 |= TIM_CR1_DIR;
  LL_TIM_ClearFlag_UPDATE(TIM4);

  // Slave timer (TIM8) - ensure prescaler starts at 0
  LL_TIM_SetPrescaler(TIM8, 1);
  LL_TIM_SetCounter(TIM8, 0);
  LL_TIM_GenerateEvent_UPDATE(TIM8);  // Reset prescaler counter
  LL_TIM_ClearFlag_UPDATE(TIM8);

  // Enable both timers
  LL_TIM_EnableIT_UPDATE(TIM8);
  LL_TIM_EnableCounter(TIM8);
  LL_TIM_CC_EnableChannel(TIM4, LL_TIM_CHANNEL_CH1);
  LL_TIM_EnableCounter(TIM4);

 

I also have an interrupt handler to toggle a GPIO pin when TIM8 overflows to generate the bottom trace.

 

I started with the STM32 HAL, then tried raw register use and now LL HAL as shown above.  To avoid any possibility of the ST HAL resetting anything on PWM channel start, I tried the other alternatives, but without any success so far.

Setting the CNT value high and setting the direction to down is working.  The first pulse has the correct width, and if I start at zero it's half-width, so those settings are taking effect as intended.  But the update events are still in sync with the pulses, implying that one was issued before the underflow event.. or that the first underflow event was ignored:

rleighelectradx_1-1759613465372.png

With TIM8 ARR=19, I get 20 pulses per cycle... except for the first where there are 21.

 

I really just wanted to check if what I'm doing is on the right track, and if it's possible to set up the timer so that the first update event occurs on underflow rather than overflow.  Am I setting up the timer in the right way to do this, or have I missed out anything fundamental?  Does the centre-aligned mode 3 require an overflow event to be the first update event and ignore any preceding underflow event?  If that's the problem, are there any alternative methods of achieving the same end?

 

Many thanks,

Roger

 

0 REPLIES 0