I am very new to Stm32 programming and to the concept of interrupts, and I really need some guidance. For my program, I want a (global) variable to be incremented by 1 every time I press a button (in PB4).
I have tried to program this, but it isn't working. The interrupt is triggered, yet the debugger tells me that when I press the button (once), the variable just keeps getting continuously and infinitely incremented without stop.
What do I need to consider in order to achieve my goal (1 time pressed, variable ++) ?
Here is my code for interrupt initialization and the ISR :
void pb4_exti_init(void){ //GPIO_init();
//Enable clock access for GPIOB
//Enable clock access for SYSCFG
RCC->APB2ENR |= SYSCFGEN;
//Select PORTB for EXTI4
SYSCFG->EXTICR[1] |= (1U<<0);
//Unmask EXTI4
EXTI->IMR1 |= (1U<<4);
//Select falling edge trigger
EXTI->FTSR1 |= (1U<<4);
//Enable EXTI line in NVIC
NVIC_EnableIRQ(EXTI4_IRQn);
}
void EXTI4_IRQHandler(void){
z++;
}
Two things:
Let's look together at this register of EXTI (I'm using STM32F746, yours should be similar/identical):
Notice the bits are rc_w1. It's very important. From the same reference manual, it says:
So if we want to remove pending interrupt from EXTI, we need to write 1 into the corresponding bit. In your case, into PR4.
EXTI->PR = EXTI_PR_PR4; //or 1U << 4U; check the name of the register, it can be PR1, then adjust the right hand side too
Why am I not using |=? Because writing 0 to other bits doesn't change them in any way. Even if there were other EXTI interrupts and there were 1s, writing 0 doesn't change those bits, so they stay 1s. You want to keep flag clearing as small as possible, preferably atomic. It doesn't really matter if you use |= here, but if you have registers, where you can write 0, this can become a problem if some other interrupt happens in the middle of flag clearing, you may accidentally clear other flags (if interrupt happens after you read from the register, but before you write clear flag, you may write 0 to freshly happened another interrupt). But! It's not applicable here and it's far too early for you to worry about it now. It's enough to say that these things do exist, and you should just be aware of them. You'll remember this when you need it. For now, clear the EXTI pending flag, and your code should function well.
As a hint, you don't have to shift stuff 4 bits to the left. There are CMSIS definitions for that. Otherwise you'll go crazy if you need to setup 3 registers with 10 different fields for each peripheral.
EXTI->IMR1 |= (1U<<4);
Can be written as
EXTI->IMR1 |= (1U<<EXTI_IMR1_IM4_Pos);
It will be super helpful when you try other peripherals.