lwgpio interrupt problem

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

lwgpio interrupt problem

2,463 Views
joker441
Contributor I

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);

 

0 Kudos
Reply
8 Replies

1,212 Views
trailman
Contributor V

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.

 

0 Kudos
Reply

1,212 Views
joker441
Contributor I
hi, thanks very much for your reply... i tried different priorities and subpriorities already (5,2 & 4,1) but the result stays the same... also when i do a printf on the two interrupt vectors i get the same result (0x69 for both), which is the vector for the port C interrupt.... i suppose you are right that something gets overwritten somewhere, but i have no clue where and how i should fix that... the lwgpio driver is also quite new if i remember correctly, maybe it still has a bug somewhere... any chance that somebody experienced the same problem already? cheers, j
0 Kudos
Reply

1,212 Views
trailman
Contributor V

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

 

0 Kudos
Reply

1,212 Views
joker441
Contributor I

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...

0 Kudos
Reply

1,212 Views
joker441
Contributor I

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 :smileyhappy:

 

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;
}   

0 Kudos
Reply

1,212 Views
anthony_huereca
NXP Employee
NXP Employee

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}

 

 

0 Kudos
Reply

1,212 Views
Mohsin455
Contributor IV

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


0 Kudos
Reply

1,212 Views
c0170
Senior Contributor III

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

0 Kudos
Reply