cancel
Showing results for 
Search instead for 
Did you mean: 

Multiple Frequency PWM sequencer

bobaston
Associate II
Posted on January 18, 2016 at 20:10

Hello,

I'd like to create a sequencer on my STM32F100RB (@8MHz) to control 8 independants PWM channels. I configured a timer to generate a 10us interrupt wich call the update function.

//timer 10µs 
void Init_TIMER(void)
{
TIM2->PSC = 7; // Set prescaler to 24 000 (PSC + 1)
TIM2->ARR = 10; // Auto reload value 1000
TIM2->DIER = TIM_DIER_UIE; // Enable update interrupt (timer level)
TIM2->CR1 = TIM_CR1_CEN; // Enable timer
NVIC_EnableIRQ(TIM2_IRQn); // Enable interrupt from TIM2 (NVIC level) 
}

Here my interrupt function :

void TIM2_IRQHandler(void)
{
if(TIM2->SR & TIM_SR_UIF) // if UIF flag is set
{
if (currentPeriod[0] > 0){
currentTick[0]++;
if (currentTick[0] >= currentPeriod[0]){
move(0,STEP_0,DIR_0);
currentTick[0]=0;
}
} 
if (currentPeriod[1] > 0){
currentTick[1]++;
if (currentTick[1] >= currentPeriod[1]){
move(1,STEP_1,DIR_1);
currentTick[1]=0;
}
} 
[6 more blocks]
TIM2->SR &= ~TIM_SR_UIF; // clear UIF flag
}
}

and my move function :

void move (int mot_id, uint16_t pin, uint16_t direction_pin) {
//Switch directions if end has been reached
if (currentPosition[pin] >= MAX_POSITION) {
currentState[direction_pin] = 1;
GPIO_SetBits(GPIOC,direction_pin); 
} 
else if (currentPosition[pin] <= 0) {
currentState[direction_pin] = 0;
GPIO_ResetBits(GPIOC,direction_pin);
}
//Update currentPosition
if (currentState[direction_pin] == 1){
currentPosition[pin]--;
} 
else {
currentPosition[pin]++;
}
//Pulse the control pin
if (currentState[pin]== 0){
GPIO_ResetBits(GPIOC,pin);
}
else{
GPIO_SetBits(GPIOC,pin);
}
currentState[pin] = ~currentState[pin];
}

When I try this code with one single output I generate a signal with the right frequency but if i had more output(blocks) the frequency decrease.

Have you ever experienced such a problem ? #sequencer #pwm #timer
5 REPLIES 5
Posted on January 18, 2016 at 20:31

Expecting an 8 MHz CPU to interrupt at 100 KHz is probably a bit optimistic. You have 80 machine cycles to play with. C lines != machine cycles

ARR = 10 - 1; // DIV10, remember it is N-1

TIM2->SR &= ~TIM_SR_UIF;  // this RMW form is wrong

TIM2->SR = ~TIM_SR_UIF; // Correct form  

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
matic
Associate III
Posted on January 18, 2016 at 21:07

Clive, I have also one question.

Why this is wrong: TIM2->SR &= ~TIM_SR_UIF;

It should works too, doesn't it?

Is this (TIM2->SR = ~TIM_SR_UIF;) correct because flags could not be set by software anyway?

Posted on January 18, 2016 at 22:18

It has the potential to clear interrupts other than the one you want, it is not atomic.

Review the design, and the manual, the single write clears the interrupt(s) in an atomic fashion.

This hazard has been covered here numerous times before, don't use bit-banding on TIM->SR either.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on January 18, 2016 at 23:12

It is a self replicating trap for the unwary, ready to be cut-n-pasted throughout your own code, and over the internets

Using RMW, it is not atomic on a load-store RISC processor

TIMx_SR = 0x0000 No Interrupts Pending

TIMx_SR = 0x0001 Update Interrupt Occurs

temp = TIMx_SR Read Register

.. a few bus cycles pass

TIMx_SR = 0x0003 Now a CC1 Interrupt Occurs

temp &= ~0x0001

So temp = 0x0001 & 0xFFFE

temp = 0x0000 (remember 1 & 0 = 0, and 0 & 1 = 0)

.. a few more bus cycles pass

Write Register TIMx_SR with temp (equivalent to TIMx_SR &= 0 at the register)

TIMx_SR = 0x0000 Look both Update and CC1 cleared, and no one notices

Compared to

TIMx_SR = 0x0000 No Interrupts Pending

TIMx_SR = 0x0001 Update Interrupt Occurs

TIMx_SR = 0x0003 Now a CC1 Interrupt Occurs

Write Register TIMx_SR with 0xFFFE (equivalent to TIMx_SR &= 0xFFFE at the register)

TIMx_SR = 0x0002 Just Update cleared

Write Register TIMx_SR with 0xFFFD (equivalent to TIMx_SR &= 0xFFFD at the register)

TIMx_SR = 0x0000 Just CCR1 cleared

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
bobaston
Associate II
Posted on January 19, 2016 at 20:50

Thank you for your answers, it was very interresting. I can change my 8MHz quartz to a 24MHz one It would give my more machine cycle, but i don't know if it could solve my problem.

If I lower the sequencer frequency to 40KHz for example I loose also frequency accuraty.