cancel
Showing results for 
Search instead for 
Did you mean: 

pwm and time based interrupt

Den In
Associate II
Posted on July 10, 2018 at 13:42

Hi all,

I am working on STM32F746G - DISCO. I have started working with STM32 just recently, sorry if this is a silly question. 

I need to use 1 timer to get PWM output from one of its channels, and generate time based interrupts from another channel. I have configured channel 1 for the PWM. The timer clock is 100MHz. ARR is set to (50000 - 1) and PSC is set to (2 - 1). Therefore I have achieved 1KHz PWM output of which duty cycle (CCR1) varies as needed. This part is perfectly fine. 

I have tried to configure channel 2 to generate time-based interrupts, which should vary in the range, let's say 1ms or less (for now). The output of the prescaler in this case is 50MHz, which means an interrupt should be generated every 50K clock ticks for 1ms delay. The timer is in the upcounting mode, the CNT counts up to ARR and then restarts from 0.  So the max value CCR2 can get is ARR

(50000 - 1)

, and the maximum possible duration between two timer interrupts is 1ms. Am I right?

If I set CCR2 to something less than ARR, I expect the interrupt period is expected to be less. Interestingly, regardless of CCR2, the interrupt frequency is 500Hz, half of PWM frequency . When I change the PWM frequency, interrupt frequency changes accordingly, always half of it. 

-What could be wrong with this? 

-Is a delay of more than 1ms possible with this configuration if the need be?

-What is the usual approach?Should I use another timer for the time based interrupts?

I will be glad if you can please give me some hints. 

Regards,

Den

#pwm #time-base-interrupt #different-timer-channels #stm32f746-discovery
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on July 10, 2018 at 13:56

If I set CCR2 to something less than ARR, I expect the interrupt period is expected to be less.

No, the period is still the same, given by ARR (and PSC if you'd set it to nonzero).  Only the relative position of interrupt against the moment of timer overflow changes.

If you want periodic interrupt with a different period than the PWM, use a different timer. For this purpose, the 'basic timers' e.g. TIM6 or TIM7, are perfect (they don't have pins assigned so they can't be used for other tasks).

JW

View solution in original post

4 REPLIES 4
Posted on July 10, 2018 at 13:56

If I set CCR2 to something less than ARR, I expect the interrupt period is expected to be less.

No, the period is still the same, given by ARR (and PSC if you'd set it to nonzero).  Only the relative position of interrupt against the moment of timer overflow changes.

If you want periodic interrupt with a different period than the PWM, use a different timer. For this purpose, the 'basic timers' e.g. TIM6 or TIM7, are perfect (they don't have pins assigned so they can't be used for other tasks).

JW

henry.dick
Senior II
Posted on July 11, 2018 at 13:18

The usual approach is to use oxffff as the period as in most cases you don't care about precisely pwm frequency.

In cases where you do care about pwm frequency (period register is no longer 0xffff), you can still use the output compare for timing. Essentially keep track of the cycles that remains and in the compare interrupt update the remain cycles.

Something like this.

Output compare isr:

  If CyclesRemain :

    CyclesRemain -= ARR+1; /decrement cycle counts

  Else dosomething.

In initialization.

  temp = CycleRrmain mod (ARR + 1)

  CCRn = CNT + temp

  CycleRemain -= temp

  Enable compare interrupt.

That it does is to load up the portion of desired cycles that is less than ARR first and then in whole increments of ARR.

Basically using the output compare channels as a timer. 

The math gets easier when the period is 0xffff.

Posted on July 11, 2018 at 11:50

Thank you for the clarification 

Posted on July 12, 2018 at 15:13

I tested this on an ATtiny85, TIMER1. Output compare channel A is configured to have a period of 200 ticks (each = 256 * 1024 * 1/2Mhz), and a duty cycle of 100 ticks.

Output compare channel B is configured to generate user specified delay. 450 ticks in this case.

Timer1 output compare ch b ISR:

//tmr1 output compare ch b isr

ISR(TIMER1_COMPB_vect) {

//clear the flag - done automatically

if (tmr1b_ticks == 0) { //time has run out

TIMSK &=~(1<<OCIE1B); //0->disable interrupt, 1->enable interrupt

//optionally, run a quick user routine here

//IO_FLP(OUT_PORT, OUT_PIN); //flip out_pin

} else { //more time to go

tmr1b_ticks-= OCR1C; //decrement tmr1b_ticks

//do nothing here

}

}

the main code: 

pwm1_init(TMR1_PS1024x); //initialize pwm1. top at 200

pwm1a_setdc(100); //duty cycle on timer1 ch a

IO_OUT(OUT_DDR, OUT_PIN); //out_pin as output

ei(); //enable the interrupt

while(1) {

if (tmr1b_ovf()) { //if time is up, restart the delay

tmr1b_start(OUT_TICKS); //re-start the delay

IO_FLP(OUT_PORT, OUT_PIN); //flip the output pin

}

}

here is the output, as expected.

0690X0000060M92QAE.png

Now, the mcu is different but the basic approach applies to stm32/8 (or any other mcu) as well. So what was considered ''impossible'' is actually very easy to execute.

hope it helps.