Reputation: 76
I am trying to toggle an LED using STM32C0x Reference Manual. I have connected the LED to port A pin 0 and button to port A pin 1. The circuit is correct as the LED toggles successfully when I dont use interrupts but use a while loop with if statement. However while using interrupts, the pressing the button does not do anything.
void enablePinGPIOPortA(unsigned short pin , short isInput);
void enableInterrupt(void);
int main(void){
enablePinGPIOPortA(0 , 0);
enablePinGPIOPortA(1 , 1);
enableInterrupt();
while(1);
}
void enablePinGPIOPortA(unsigned short pin , short isInput){
RCC->IOPENR |= RCC_IOPENR_GPIOAEN;
//reset the pin
GPIOA->MODER &= ~(0b11 << 2*pin);
if(!isInput){
GPIOA->MODER |= 0b01 << 2*pin;
}else{
//select pull down for input
GPIOA->PUPDR |= (0b10 << (2*pin));
}
}
void enableInterrupt(){
RCC->APBENR2 |= 1;
EXTI->EXTICR[1] |= 0b00;
EXTI->RTSR1 |= 0x2;
EXTI->IMR1 |= (1 << 1);
NVIC_EnableIRQ(EXTI0_1_IRQn);
RCC->APBENR2 &= ~(1);
}
void EXTI0_1_IRQHandler(void){
GPIOA->ODR ^= 1;
EXTI->RPR1 &= ~(1 << 1);
}
I assume the enableGPIOA
function is correct as it worked without interrupts. However I'm not sure about the enableInterrupt
function.
I'm using a simulator https://wokwi.com/projects/new/st-nucleo-c031c6
Upvotes: 0
Views: 161
Reputation: 93556
EXTI_RPR1
bits are cleared by writing 1. So:
EXTI->RPR1 &= ~(1 << 1);
should be
EXTI->RPR1 |= (1 << 1) ;
EXTI->EXTICR[1] |= 0b00;
is incorrect (althugh probably not causing your problem in this case). OR'ing with zero has no effect. Whatever is in that register will remain in that register. Its reset value is zero, so in the absence of any other write elsewhere, that is what it will contain. However it is an attempt to set the wrong bits in the wrong register. It is a write to EXTI_EXTCR1 which is the control register for EXTI4 to EXIT7 while your input is on PORTA.1 so you need EXTI1. To enable the EXTI1 for PORTA.1:
EXTI->EXTICR[0] &= ~0xFFFF00FF ;
Still though since the reset state is zero in any case, this will only have any effect if it were previously written with some other value elsewhere. To be fair the reference manual in an attempt to be concise, has made the EXTICRx register description rather confusing. In brief:
EXTI->EXTICR[0]
- CR for EXTI0 - EXTI3EXTI->EXTICR[1]
- CR for EXTI4 - EXTI7EXTI->EXTICR[2]
- CR for EXTI8 - EXTI11EXTI->EXTICR[3]
- CR for EXTI12- EXTI15Then in each of EXTI->EXTICR[n]
the source identifier is an 8 bit value with the lower EXTI of the four in the least significant byte.
Finally, connecting a mechanical switch to an interrupt line directly with no hardware debounce circuit is unlikely to work reliably, and detecting a button through interrupts like in this way is not particularly practical. Ways to debounce a switch interrupt include:
The second is simpler, and can be implemented with the Cortex-M SYSCLK rather then using a hardware timer. In either case it is only worth doing in cases where instantaneous response is required - limit switches on a machine or collision detection on a robot perhaps. Otherwise you could simply poll the input periodically (on a timer interrupt if necessary).
Upvotes: 1