2018-07-10 04:42 AM
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-discoverySolved! Go to Solution.
2018-07-10 04:56 AM
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
2018-07-10 04:56 AM
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
2018-07-11 04:18 AM
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.
2018-07-11 04:50 AM
Thank you for the clarification
2018-07-12 08:13 AM
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 aIO_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.
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.