0
\$\begingroup\$

I'm trying to set up the output compare channels of TIM3 of an STM32F103RB MCU.

For now I only enabled channel 1, but later I'll need CH2 and CH3 as well.

When CH1 triggers, the TIM3->SR register gets the value of 0x0000001f. I have looked at it in the debugger. The other channels are not even set up, so their interrupts should be disabled, right?

It enters the TIM3_IRQHandler function and it executes the ISR of all the channels. Not only that, but it doesn't even reset the CCxIF bits when I tell it to. It just goes over the line and does nothing. According to the debugger, the TIM3->SR value remains unchanged.

Also, the TIM3->SR gets the value 0x0000001f when the counter enable CEN bit is set, and when I modify the prescaler or enable the CC1IE bit.

Have I misunderstood something about interrupt operation? What could be the problem? Why do all interrupt channel flags set at once? Could you provide some example as to how to properly setup output compare interrupts?

My timer setup function:

void TIM3_Init(void)
{
 RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; //Enable timer 3 clock
 
 TIM3->PSC = 65536-1; // Set timer 3 prescaler
 TIM3->ARR = 7200-1; //Set timer 3 auto reload value
 TIM3->CR1 &= ~(3 << TIM_CR1_CMS_Pos); //selecting edge aligned PWM
 TIM3->CR1 |= TIM_CR1_ARPE; //Enable auto-reload preload
 TIM3->CCER &= ~TIM_CCER_CC1E;//Capture compare 1 disable
 TIM3->CCER &= ~TIM_CCER_CC1P;//Capture compare polarity active high
 TIM3->CCMR1 &= ~(3 << TIM_CCMR1_CC1S_Pos);//CC1 channel is output
 TIM3->CCMR1 &= ~(7 << TIM_CCMR1_OC1M_Pos);//OC no output selected
 TIM3->CCER |= TIM_CCER_CC1E;//Capture compare 1 enable
}

The TIM3_IRQHandler function:

void TIM3_IRQHandler(void)
{
 //Determine which channel interrupted with the if statements
 if (TIM3->SR & (1 << 1)) //Channel 1 ISR
 {
 TIM3->SR &= ~(1 << 1); //Clear the interrupt flag, doesn't do anything...
 flag = 1;
 }
 if (TIM3->SR & (1 << 2)) //Channel 2 ISR
 {
 TIM3->SR &= ~(1 << 2); //Clear the interrupt flag, doesn't do anything...
 //Do stuff...
 }
 if (TIM3->SR & (1 << 3)) //Channel 3 ISR
 {
 TIM3->SR &= ~(1 << 3); //Clear the interrupt flag, doesn't do anything...
 //Do stuff...
 }
}

Main function and global variable flag:

volatile uint8_t flag = 0;
int main(void)
{
 SystemClock_Config();
 TIM3_Init();
 
 TIM_Start(TIM3);
 uint8_t counter = 0;
 TIM3->PSC = 2;
 TIM3->CCR1 = 5000;
 TIM3->CNT = 0;
 TIM3->DIER |= TIM_DIER_CC1IE;//Enable CH1 output compare interrupt bit
 NVIC_SetPriority(TIM3_IRQn, 2); //Set timer 3 ISR priority
 NVIC_EnableIRQ(TIM3_IRQn); //Enable timer 3 ISR
 while(counter < 10)
 {
 if (flag == 1)
 {
 counter++;
 flag = 0;
 }
 }
}

The TIM3 Start function:

void TIM_Start(TIM_TypeDef* TIM)
{
 TIM->EGR |= TIM_EGR_UG;//Generate update
 TIM->CR1 |= TIM_CR1_CEN; //Enable the counter
 TIM->SR = 0x00;
}

System clock configuration fuction:

void SystemClock_Config(void)
{
 RCC->CR |= RCC_CR_HSEON; //Enable the high speed external crystal
 while(!(RCC->CR & RCC_CR_HSERDY)); //Wait until clock stabilized
 
 RCC->APB1ENR |= RCC_APB1ENR_PWREN;
 
 FLASH->ACR |= FLASH_ACR_PRFTBE //Set up the flash memory (enable prefetch buffer, 
 | FLASH_ACR_LATENCY_2; //set latency to two wait states)
 
 RCC->CFGR |= RCC_CFGR_PLLMULL9 //Set Phase locked loop multiplication
 | (1 << RCC_CFGR_PLLSRC_Pos) //Set PLL source to HSE
 | RCC_CFGR_PLLXTPRE_HSE //Set PLL HSE prescaler
 | RCC_CFGR_HPRE_DIV1 //Set AHB prescaler 
 | RCC_CFGR_PPRE1_DIV2 //Set APB1 peripheral prescaler 
 | RCC_CFGR_PPRE2_DIV1 //Set APB1 peripheral prescaler 
 | RCC_CFGR_ADCPRE_DIV6; //Set ADC prescaler
 
 RCC->CR |= RCC_CR_PLLON; //Turn on PLL
 while(!(RCC->CR & RCC_CR_PLLRDY)); //Wait until PLL locks
 
 RCC->CFGR |= RCC_CFGR_SW_PLL; //Set PLL as system clock source
}
asked Oct 27, 2021 at 12:37
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

So in the meantime I got the answers to my questions.

When CH1 triggers, the TIM3->SR register gets the value of 0x0000001f. I have looked at it in the debugger. The other channels are not even set up, so their interrupts should be disabled, right?

Well as it turns out, the channels, which are "not set up" are rather in their reset states. So the reset register settings apply to them.

It enters the TIM3_IRQHandler function and it executes the ISR of all the channels. Not only that, but it doesn't even reset the CCxIF bits when I tell it to. It just goes over the line and does nothing. According to the debugger, the TIM3->SR value remains unchanged.

Yes, it executes them, because the interrupt flags are set, no matter the settings in the TIMx->DIER register. The TIMx->DIER register serves only to set whether an interrupt is made, not if the interrupt flag sets or not. So what happened is, the CCRx registers of the unused channels were 0, and when the CNT register reached 0, they set the corresponding CCxIF interrupt flags. So in the interrupt handler I have to check not only if the interrupt flag is set for the channel, but if the channel DIER bit is enabled.

The reason all flags appeared to set at once is because in debugging mode the timer clock continued to tick, even when the code execution halted. That explains everything else that was unclear.

answered Oct 27, 2021 at 15:33
\$\endgroup\$
1
  • \$\begingroup\$ Note that you can control whether a timer runs or pauses at a breakpoint by clearing/setting the appropriate bit in the DBGMCU_CR register \$\endgroup\$ Commented Oct 27, 2021 at 18:39

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.