cancel
Showing results for 
Search instead for 
Did you mean: 

Generating a PWM that starts high, but ends low after N pulses have been completed.

Pepijn
Associate II

I have an Arduino Giga (STM32H7) and I'm using the timers to generate PWM's. Everything's working fine, programming is no problem, but I cannot come up with a way to implement what I want. I included a simple visual to describe what I want the output to look like.TIM1TIM8_Visual.png

 



TIM1 is the master timer, it generates a PWM, set as active high (for CNT<CCR). I have a slave TIM8, which should do the following: when TIM1 starts over again/goes high, TIM8 should generate N pulses. The time it takes for N pulses to complete is shorter than the period of TIM1, I want them to retrigger each time TIM1 goes high again. Here's the catch: The pulses should immediately start high, however, once all the pulses have fired, the output should stay low.

If it weren't for the last part, the solution would be simple: TIM1 uses UEV as output trigger, TIM8 takes an internal trigger input from TIM1, set TIM8 to One-Pulse Mode, set the repetition counter to N, and voila, you get bursts of N pulses on each TIM1 high (yes technically the first time it won't trigger, doesn't matter).

However, this will cause the pulses of TIM8 to either start 'delayed', since for CNT<CCR, the output will be low in OPM, or if we flip the polarity, it will start high, but after having finished N pulses, TIM8->CNT=0 (because of OPM), which causes the output to be high...

Can anyone think of a good solution/setup? Again, programming is no issue, it's just finding a way to get this behaviour, if that's even possible... Also, I would prefer not to use interrupts handlers for reasons related to the rest of my program.

1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

Very doable with a number of methods

Perhaps the easiest is to use the scheme that almost works except use PWM mode 2 and set it so output is low at CNT=0, high at CNT=1... X, and then low again until it reaches ARR.

TDK_0-1705856593557.png

 

If you need them to exactly match, you could use TIM8 in gated slave mode to get exactly 4 pulses at the start of each TIM1 period. Can describe this more if you need.

 

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

4 REPLIES 4
TDK
Guru

Very doable with a number of methods

Perhaps the easiest is to use the scheme that almost works except use PWM mode 2 and set it so output is low at CNT=0, high at CNT=1... X, and then low again until it reaches ARR.

TDK_0-1705856593557.png

 

If you need them to exactly match, you could use TIM8 in gated slave mode to get exactly 4 pulses at the start of each TIM1 period. Can describe this more if you need.

 

If you feel a post has answered your question, please click "Accept as Solution".
Pepijn
Associate II

Ah the combined mode, I hadn't considered that but I'm sure that will work. The single count offset is no problem. Thanks a lot!

Pepijn
Associate II

Very late response, but it's not working as I would like. I use TIM1 as a master timer, and TIM8 in slave mode.

 

  // Enable use of Timers.
  RCC->APB2ENR   |= RCC_APB2ENR_TIM1EN;     // for TIM1
  RCC->APB2ENR   |= RCC_APB2ENR_TIM8EN;     // for TIM8  


  // Enable Capture/Compare for Timers_Channels.
  TIM1->BDTR  |= TIM_BDTR_MOE;    // Enables Main Output for TIM1. Only needed for TIM1 and TIM8 (see Reference Manual)
  TIM1->CCER  |= TIM_CCER_CC2E;   // Enable channel 2

  TIM8->BDTR  |= TIM_BDTR_MOE;    // Enables Main Output for TIM8. Only needed for TIM1 and TIM8 (see Reference Manual)
  TIM8->CCER  |= TIM_CCER_CC1E;   // Enable channel 1
  TIM8->CCER  |= TIM_CCER_CC2E;   // Enable channel 2

  // Set Output Compare Mode for Timers_Channels.
  // 6:  PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCR1, else inactive.
  // 7:  PWM mode 2 - Inversed, channel is INactive as long as TIMx_CNT<TIMx_CCR1, else active.

  // Channels 1, 2 are in CCMR1. Channels 3,4 are in CCMR2, etc...
  TIM1->CCMR1   &= ~TIM_CCMR1_OC2M_Msk;               // for TIM1_CH2
  TIM1->CCMR1   |= (0x6UL << TIM_CCMR1_OC2M_Pos);

  // Basler: The Basler camera is triggered by a combined PWM mode, to ensure a low level at the end of the frame triggers,
  // while still (almost, at CNT=1) starting high.
  // 12:  Combined PWM mode 1 - OC1REF has the same behavior as in PWM mode 1. OC1REFC is the logical OR  between OC1REF and OC2REF.
  // 13:  Combined PWM mode 2 - OC1REF has the same behavior as in PWM mode 2. OC1REFC is the logical AND between OC1REF and OC2REF.

  TIM8->CCMR1   &= ~TIM_CCMR1_OC1M_Msk;               // for TIM8_CH1 - AND
  TIM8->CCMR1   |= (0x13UL << TIM_CCMR1_OC1M_Pos);    // 

  TIM8->CCMR1   &= ~TIM_CCMR1_OC2M_Msk;               // for TIM8_CH2 - OR
  TIM8->CCMR1   |= (0x12UL << TIM_CCMR1_OC2M_Pos);     // 
  
  //TIM8->CCER    |= TIM_CCER_CC1P;                     // Flip output polarity on TIM8_CH1. Should not be necessary... FIXME


  // Set Master and Slave Timers.
  TIM1->CR2   &= ~TIM_CR2_MMS_Msk;
  TIM1->CR2   |= (0x2UL << TIM_CR2_MMS_Pos);  // Set the Update Event as Trigger Output (TRGO)

  // Set slaves to One Pulse Mode. This stops the counter on the next Update Event.
  TIM8->CR1   |= TIM_CR1_OPM;

  // "Mode 6: Trigger Mode - The counter starts at a rising edge of the trigger TRGI
  // (but it is not reset). Only the start of the counter is controlled."
  // Note: We are in One Pulse Mode, so counter will be stopped at 0 (after reaching ARR) anyways...
  TIM8->SMCR  &= ~TIM_SMCR_SMS_Msk;
  TIM8->SMCR  |= (0x6UL << TIM_SMCR_SMS_Pos);

  TIM8->SMCR  &= ~TIM_SMCR_TS_Msk;            // Use Internal Trigger 0, corresponding to TIM1
  TIM8->SMCR  |= (0x0UL << TIM_SMCR_TS_Pos);

 

 

 

    TIM8->RCR = 1;
    TIM8->PSC   = 24000-1;                        // Prescaler: Set so that 1 tick is 0.1 microseconds (at 240 MHz)
    TIM8->ARR   = 10*50; 
    TIM8->CCR1  = 10*30;
    TIM8->CCR2  = 10*40;

 

(TIM1 is set to a much longer ARR)

I expected to see a 10 ms pulse, which starts after 30 ms and goes down after 40ms. Why is this not working? I do not get any output when using the combined PWM mode. When just set the normal PWM mode for TIM8 channel2 I see the normal PWM, so the output and stuff is set correctly. It's just the combined mode that is not working.

// Basler: The Basler camera is triggered by a combined PWM mode, to ensure a low level at the end of the frame triggers,
  // while still (almost, at CNT=1) starting high.
  // 12:  Combined PWM mode 1 - OC1REF has the same behavior as in PWM mode 1. OC1REFC is the logical OR  between OC1REF and OC2REF.
  // 13:  Combined PWM mode 2 - OC1REF has the same behavior as in PWM mode 2. OC1REFC is the logical AND between OC1REF and OC2REF.

  TIM8->CCMR1   &= ~TIM_CCMR1_OC1M_Msk;               // for TIM8_CH1 - AND
  TIM8->CCMR1   |= (0x13UL << TIM_CCMR1_OC1M_Pos);    // 

  TIM8->CCMR1   &= ~TIM_CCMR1_OC2M_Msk;               // for TIM8_CH2 - OR
  TIM8->CCMR1   |= (0x12UL << TIM_CCMR1_OC2M_Pos);     // 

1. 0x12/0x13 != 12/13

2. TIMx_CCMRx.OCxM bits don't form a continuous bitfield (for historical reasons)

waclawekjan_0-1723483463321.png

JW