hi there,
i have a custom board using a kinetis k60 and i don't seem to get my lwgpio isr properly working... 2 buttons (PortC14, PortC15) trigger interrupts on either edge, enter the same isr to set a lwevent depending on which button has been pressed...
if i setup only one button to use interrupts (doesn't matter which one) everything works fine (except for the second interrupt)...
what happens now is that, if i press the second button first (the one where the isr is registerd later) it works fine... if i then press the first button the isr gets called over and over again with the wrong pin as parameter passed to the isr (the second pin instead of the first)...
any idea anyone?
thx,
joe
sry about posting the code, couldn't attach the files...
ISR
// callback for PortC, interrupts coming from HMI (2 pins)
void PortC_int_callback(void *pin) {
uint_32 pinmask = ((LWGPIO_STRUCT_PTR)pin)->pinmask;
switch(pinmask) {
case(HMI_BUTTON1_MASK):
printf("\n PortC_int_callback entered, source: HMI_BUTTON1, pinmask: %x", pinmask);
if (_lwevent_set(&BUTTON1_LWEVENT, INT_EVENT_MASK) != MQX_OK) {
printf("\nSet Event BUTTON1_LWEVENT failed");
_mqx_exit(0);
}
break;
case(HMI_BUTTON2_MASK):
printf("\n PortC_int_callback entered, source: HMI_BUTTON2, pinmask: %x", pinmask);
if (_lwevent_set(&BUTTON2_LWEVENT, INT_EVENT_MASK) != MQX_OK) {
printf("\nSet Event BUTTON2_LWEVENT failed");
_mqx_exit(0);
}
break;
default:
printf("\n PortC_int_callback entered, unknown int source");
break;
}
lwgpio_int_clear_flag((LWGPIO_STRUCT_PTR) pin);
}
BUTTON SETUP
// opening pin button1 as input
if (!lwgpio_init(&btn1, HMI_BUTTON1, LWGPIO_DIR_INPUT, LWGPIO_VALUE_NOCHANGE)) {
printf("Initializing button GPIO as input failed.\n");
_task_block();
}
lwgpio_set_functionality(&btn1, HMI_BUTTON1_MUX_GPIO);
lwgpio_set_attribute(&btn1, LWGPIO_ATTR_PULL_UP, LWGPIO_AVAL_ENABLE);
// install interrupt service routine for button1
if (!lwgpio_int_init(&btn1, LWGPIO_INT_MODE_FALLING | LWGPIO_INT_MODE_RISING)) {
printf("Initializing button1 GPIO for interrupt failed.\n");
_task_block();
}
printf("\nButton1 configured for interrupt.");
_int_install_isr(lwgpio_int_get_vector(&btn1), PortC_int_callback, (void *) &btn1);
_bsp_int_init(lwgpio_int_get_vector(&btn1), 3, 0, TRUE);
lwgpio_int_enable(&btn1, TRUE);
// opening pin button2 as input
if (!lwgpio_init(&btn2, HMI_BUTTON2, LWGPIO_DIR_INPUT, LWGPIO_VALUE_NOCHANGE)) {
printf("Initializing button GPIO as input failed.\n");
_task_block();
}
lwgpio_set_functionality(&btn2, HMI_BUTTON2_MUX_GPIO);
lwgpio_set_attribute(&btn2, LWGPIO_ATTR_PULL_UP, LWGPIO_AVAL_ENABLE);
// install interrupt service routine for button2
if (!lwgpio_int_init(&btn2, LWGPIO_INT_MODE_FALLING | LWGPIO_INT_MODE_RISING)) {
printf("Initializing button2 GPIO for interrupt failed.\n");
_task_block();
}
printf("\nButton2 configured for interrupt.");
_int_install_isr(lwgpio_int_get_vector(&btn2), PortC_int_callback, (void *) &btn2);
_bsp_int_init(lwgpio_int_get_vector(&btn2), 3, 0, TRUE);
lwgpio_int_enable(&btn2, TRUE);
Hi,
This looks like the data pointer set at the first _int_install_isr() is overwritten by the second _int_install_isr() so in the ISR you always get the second data pointer (&btn2).
Try to use different int level/sublevel for both pins (at least a diferent sublevel). For example 3,0 and 3,1
Also check that the vector is different (should be) by doing a printf on lwgpio_int_get_vector(&btn1) and lwgpio_int_get_vector(&btn2).
Also take care about printf in the "callback" function : as this is not a callback function but a real ISR (called from interrupt context), any printf will hang your system until completed. For test this is acceptable but not for a real application.
Hi,
I think the problem comes from the vector that is the same for both pins.
I add a look to the code of _int_install_isr() in mqx/source/kernel/int_iisr.c and ony one ISR function and data pointer can be supplied by vector. I you call _int_install_isr() more than one, the last one will be used.
But you can assign the same ISR function to different vectors; that's were the data pointer is usefull to help the function determine which vector caused the interrupt.
In your case, all port C has the same vector, so you could probably do as follows as a workaround :
- call ._int_install_isr() only once with a null data pointer
- in your ISR function, just set an event or semaphore to notice that the port has changed (without knowing which pin)
- in a task (or main task), wakeup on the event or semaphore and read level of each pin to check which one has changed
hi, thanks again for your effort... i built a demo project based on the code i posted above which illustrates the problem... i have it running on a custom board, the BSP is an adaption of the one for the tower K60 and the pins are defined at the top of main.c... greets, j
somehow i'm unable to attach a c-file directly... changed the name to .c.txt...
one more interesting thing i discovered concerning the problem that the ISR gets entered over and over again:
i tried the approach trailman suggested, i read out all pins in the ISR, compare them to their previous value and set an lwevent depending on the pin and clear its interrupt flag, which works very fine.
the problem i found now is that clearing the interrupt flag of the corresponding pin also only works for the pin initialized latest, meaning that i have to clear the isr flag of btn2 and btn1 of i press button 1, otherwise the isr gets entered all over and over again....
generally i don't mind clearing flags and flags till none of them is left... it's not nice, but it helps
void PortC_int_callback(void *pin) {
btn1_val = lwgpio_get_value(&btn1);
btn2_val = lwgpio_get_value(&btn2);
if(btn1_val != btn1_prev_val) {
printf("\n PortC_int_callback entered, source: HMI_BUTTON1, %i %i", btn1_val, btn2_val);
if (_lwevent_set(&BUTTON_LWEVENT, INT_EVENT_MASK) != MQX_OK) {
printf("\nSet Event BUTTON_LWEVENT failed");
_mqx_exit(0);
}
lwgpio_int_clear_flag((LWGPIO_STRUCT_PTR)&btn1);
// clearing of btn2 interrupt flag required aswell! weird...
lwgpio_int_clear_flag((LWGPIO_STRUCT_PTR)&btn2);
}
if(btn2_val != btn2_prev_val) {
printf("\n PortC_int_callback entered, source: HMI_BUTTON2, %i %i", btn1_val, btn2_val);
if (_lwevent_set(&BUTTON_LWEVENT, INT_EVENT_MASK) != MQX_OK) {
printf("\nSet Event BUTTON_LWEVENT failed");
_mqx_exit(0);
}
lwgpio_int_clear_flag((LWGPIO_STRUCT_PTR)&btn2);
}
btn1_prev_val = btn1_val;
btn2_prev_val = btn2_val;
}
I ran into this same problem. The easiest way to solve it is using lwgpio_int_get_flag() to see which pin caused the interrupt.
if(lwgpio_int_get_flag(&btn1)) //Button 1 caused interrupt{ lwgpio_int_clear_flag(&btn1); //Clear interrupt flag}if(lwgpio_int_get_flag(&btn2)) //Button 2 caused interrupt{ lwgpio_int_clear_flag(&btn2); //Clear interrupt flag}
Hi All,
I am also having same issue. Can anyone please confirm what is the correct fix for this? If I we use the following method (just to service interrupt from 1 pin at a time ) , does the the interrupt occurs until the flag is cleared ?
ISR(){
if(lwgpio_int_get_flag(&btn1)) //Button 1 caused interrupt
{
lwgpio_int_clear_flag(&btn1); //Clear interrupt flag
}
else if(lwgpio_int_get_flag(&btn2)) //Button 2 caused interrupt
{
lwgpio_int_clear_flag(&btn2); //Clear interrupt flag
}
}
I have added "else if" in the above code to service interrupt from one pin at a time.
Mohsin
Hi joker441,
it might be more helpfull and easier if you attach your entire code, i will take a look or when i get a time i'll try replicate your scenario with the snapshot you provided.
Regards,
MartinK