2012-12-20 12:50 PM
I have a number of switches which generate interrupts. When I Flick switch A it goes from High to Low
and the A interrupt occurs(EXTI_PR is now 0x00000200 as expected). I then clear the pending register (EXTI_PR is now 0x00000000). At this time switch A is still at low which is what I require. Now while switch A is still low, I switch B from High to Low. Instead of entering the B interrupt routine, which is what I expect, the processor still enters the A routine. I can understand this because when I check EXTI_PR, its value is 0x00000600. How can I avoid this situation? I need to keep A switched low while B is switched. I would not have expected this as the interrupts are edge triggered. What is keeping the pending registers from being properly cleared? The pending register only changes to 0x00000400 when I switch A on and off. When I activate the switches by flicking them ON and OFF, the interrupts behave accordingly. However, my system doesn't allow this. I appreciate any help. Bob /* Configure PC9 pin as input floating */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, &GPIO_InitStructure); /* Connect EXTI0 Line to PC9 pin */ SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource9); /* Connect EXTI0 Line to PC10 pin */ SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource10); /* Configure EXTI9 line */ EXTI_InitStructure.EXTI_Line = EXTI_Line9; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* Configure EXTI10 line */ EXTI_InitStructure.EXTI_Line = EXTI_Line10; EXTI_Init(&EXTI_InitStructure); /* Enable and set EXTI4_15 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = EXTI4_15_IRQn; NVIC_InitStructure.NVIC_IRQChannelPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); void EXTI4_15_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line9) != RESET) { printf(''\n\r Interrupt A''); EXTI_ClearITPendingBit(EXTI_Line9); } else if (EXTI_GetITStatus(EXTI_Line10) != RESET) { printf(''\n\r Interrupt B''); EXTI_ClearITPendingBit(EXTI_Line10); } }2012-12-21 05:27 AM
Maybe it just works this way, I don't know butI think you can use software filter in the handler to make it work as expected.
Not tested:static uint32_t last_pr = 0;
uint32_t new_pr = (EXTI_PR ^ last_pr) & EXTI_PR;
last_pr = EXTI_PR;
if (new_pr & EXTI_Line9)
{
// interrupt A
}
if (new_pr & EXTI_Line10)
{
// interrupt B
}
2012-12-21 08:46 AM
This almost works perfectly except that if I switch B on so that it jumps into the B routine (works fine), and then switch it off. If I now switch B on again, it no longer jumps into the B routine.
It works if swich A is followed by switch B or vice versa. When there is two consecutive interrupts from the same switch, the second isn't caught. However, this solved it. if (last_pr == EXTI->PR) { new_pr = EXTI->PR; last_pr = new_pr; } else { new_pr = (EXTI->PR ^ last_pr) & EXTI->PR; last_pr = EXTI->PR; } Many thanks for your advice. Bob2012-12-21 12:11 PM
After some more testing with another switch C, this is still not working correctly. If A is left ON, then if C is activated, the A routine is entered. How are interrupts meant to work with switches or are switches expected to be polled instead of using interrupts?
2012-12-21 06:51 PM
I'd expect the device to be able to detect each independently, but mechanical switches tend to be awfully noisy, so if you are edge triggering I wouldn't be surprised if you saw glitches. Consider using debouncing logic.
If you're feeling experimental try driving them with GPIO pins.2012-12-22 12:59 AM
Yes, there may be glitches. Usually you can filter them out with a capacitor.
2012-12-22 04:51 AM
I thought that debouncing was causing the issue. However on this board there is no debounce filters between switch and pin. Is there a way that I can implement some debounce logic between the pin and interrupt mechanism
e.g GPIO_Pin_9 ----> debounce function ----> Debounced_GPIO_Pin9 RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); // Configure PC9 pin as input floating GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOC, &GPIO_InitStructure); // Connect EXTI0 Line to PC9 pin SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, Debounced_GPIO_Pin9); EXTI_InitStructure.EXTI_Line = EXTI_Line9; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure);etc
2012-12-22 05:25 AM
You can use SysTick or timer interrupt to check pin state, e.g. 100 Hz.
logic is something like this:static uint8_t pin1last = 0;
static uint8_t pin1cnt = 0; if ((pin1last != 0) ^ (pin1 != 0)) pin1cnt++; else pin1cnt = 0; if (pin1cnt > thr) // pin1 state changed { pin1cnt = 0; if (pin1) // rising if (!pin1) // falling pin1last = pin1; }2012-12-22 04:25 PM
The debouncing logic isn't a problem. However, you need to connect the debounced pin to the interrupt logic so that there is only one clean edge feeding the interrupt mechanism and thats where I believe the issue is.
The debouncing logic looks to apply only to pin polling, and not interrupts. To me it looks as if the switch must be debounced before being connected to the input ports. Would this be a fair assumption? Bob2012-12-23 02:12 AM
Yes, you can use hardware debouncing and it may work well.
I was talking about software debouncing, you need to enable some periodic irq, e.g. SysTick or timer, about 100 per second should be ok, I think.In the handler you poll the switches and you can debounce it in software.