AnsweredAssumed Answered

How to setup MQX to respond to 2 GPIO ISRs on the same port

Question asked by Wayne Taylor on Jan 15, 2015

I recently experience a nasty bite in the butt from a misunderstanding I had regarding how MQX handles GPIO and ISR callback functions.

 

You see after watching this Embedded Access video, MQX RTOS Part 6: MQX Interrupts|Freescale, reading the MQXRM & MQXIOUG, and working the lab I discovered that it doesn't work if more than one pin is assigned from the same port.

 

Here is the problem, the tutorial shows how each pin can have its own ISR callback assigned. From InputTask.c:

 

void sw1_isr(void * param){

    LWGPIO_STRUCT_PTR sw = (LWGPIO_STRUCT_PTR) param;

    APPLICATION_MESSAGE * msg;

    lwgpio_int_clear_flag(sw);

    msg = _msg_alloc_system(sizeof(*msg));

    if (msg != NULL) {

        msg->HEADER.TARGET_QID =  _msgq_get_id(0, HEALTH_QUEUE);

        msg->MESSAGE_TYPE = SW1_MESSAGE;

        msg->DATA = 0;

        _msgq_send(msg);

    }

}

 

void sw2_isr(void * param){

    LWGPIO_STRUCT_PTR sw = (LWGPIO_STRUCT_PTR) param;

    APPLICATION_MESSAGE * msg;

    lwgpio_int_clear_flag(sw);   

    msg = _msg_alloc_system(sizeof(*msg));

    if (msg != NULL) {

        msg->HEADER.TARGET_QID =  _msgq_get_id(0, HEALTH_QUEUE);

        msg->MESSAGE_TYPE = SW2_MESSAGE;

        msg->DATA = 0;        

        _msgq_send(msg);

    }

}

 

void init_switch( LWGPIO_STRUCT_PTR sw, LWGPIO_PIN_ID pin, uint32_t mux, INT_ISR_FPTR sw_isr){

    lwgpio_init(sw, pin, LWGPIO_DIR_INPUT, LWGPIO_VALUE_NOCHANGE);

    lwgpio_set_functionality(sw, mux );   

    lwgpio_set_attribute( sw, LWGPIO_ATTR_PULL_UP, LWGPIO_AVAL_ENABLE);   

    lwgpio_int_init( sw, LWGPIO_INT_MODE_FALLING);   

    _int_install_isr( lwgpio_int_get_vector(sw), sw_isr, sw);   

    lwgpio_int_enable(sw, TRUE);   

    _bsp_int_init(lwgpio_int_get_vector(sw), 4, 0, TRUE);

}

 

void Input_task(uint32_t initial_data){

    init_switch( &sw1, BSP_SW1, BSP_SW1_MUX_GPIO, sw1_isr);

    init_switch( &sw2, BSP_SW2, BSP_SW2_MUX_GPIO, sw2_isr);

}

 

The previous example clearly shows how each pin can have its own ISR callback, namely sw1_isr() and sw2_isr(). But in truth, if both of these pins, BSP_SW1 & BSP_SW2 were on the same port, then only the last pin's ISR would be added into the user defined ISR call backs by _int_install_isr(). If five pins were all on the same port, 2 would replace 1, 3 would replace 2 and so forth until only ISR for pin 5 would remain.

 

On the Kinetis chip, the right way to make this work is to have one master ISR per port. If there are two possible sources for the IRQ, then it should read the PORTx_PCRn register for each possible pin and take action based on the ISF bit. MQX makes this easy. Just call lwgpio_int_get_flag() with the LWGPIO_STRUCT pin.

 

The master port ISR could look like the following example, but there are some things that don't quite work right. The param sent to PortxISR will always be a pointer to the last pin struct that was installed, not the pin that actually creates the IRQ. This means that clearing the IRQ must be done manually, and that param is virtually useless. The previous sw1_isr() and sw2_isr() will need to have the line that clears the ISF bit removed as it is now done manually in PortxISR(). Also, "void* param" should be removed with the new function declarations being: sw1_isr(void) and sw2_isr(void).

 

void PortxISR(void* param){

    if (lwgpio_int_get_flag(&sw1)){

         sw1_isr();

         lwgpio_int_clear_flag(&sw1);

    }

 

    if (lwgpio_int_get_flag(&sw2)){

         sw2_isr();

         lwgpio_int_clear_flag(&sw);

    }

}

 

I hope this save some of you the week it took me to figure out this pitfall. If it is documented somewhere in the MQX manuals, I didn't find it.

 

Wayne

 

Original Attachment has been moved to: InputTask.c.txt.zip

Outcomes