how to identify GPIO interrupt source pin?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Hi,

I'm going to use several GPIO pin as Data Input with interrupt by register handler in following function.

gpio_registerForInterrupt(interrupt_handler_mask, application_gpio_interrupt_handler);

Then, in the application_gpio_interrupt_handler(), as the document example is:

void application_gpio_interrupt_handler(void* parameter)

Question 1:

Can the "parameter" be used to identify the pin which trigger an interrupt? and identify that is triggered at falling edge or rising edge?

Or is there any API to identify it? I found gpio_getPortInterruptStatus but not sure this is. 

Question 2:

Do the handler need to clear interrupt by gpio_clearPortInterruptStatus before exit the handler?

Thank you!

0 Likes
1 Solution

You are correct on usage with SDK 2.0.1. But with SDK 1.1.0, there are two ways to ensure that handler recognizes the right GPIO:

1. Use a unique interrupt handler callback for each GPIO (interrupt) you want to handle. For instance, if you want to handle interrupts from P0 and from P15, then use two interrupt handlers, something like this:

UINT16 masks[3] = {(1 << 0), 0, 0};    /// interrupt mask for P0

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler_for_p0, NULL);

masks[0] = 1 << 15;

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler_for_p15, NULL);

// Now configure interrupts for P0 and P15.

So, application_gpio_interrupt_handler_for_p0 will be invoked only if P0 was the interrupt source.

2. Use the same interrupt handler callback for all GPIOs, but use the userdata parameter for demultiplexing.

UINT16 masks[3] = {(1 << 0), 0, 0};    /// interrupt mask for P0

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler, (void*)0);

masks[0] = 1 << 15;

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler, (void*)15);

void application_gpio_interrupt_handler(void* userdata)

{

    UINT32 gpio = (UINT32)userdata;

    switch(gpio)

    {

        case 0:                 /// P0

              break;

        case 15:               /// P15

              break;

    }

}

> in my application I've configure GPIO by bleprofile_GPIOInit(bleprofile_gpio_p_cfg);Will this conflict to  gpio_registerForInterrupt()

This should not in this case, but I recommend that if you use bleprofile_* to configure a GPIO, you should use corresponding bleprofile_* API (mainly because some of these like buttons run state machines underneath). For interrupts from GPIOs, use gpio_*

View solution in original post

5 Replies
asridharan
Employee
Employee
10 comments on KBA 5 comments on KBA First comment on KBA

> Can the "parameter" be used to identify the pin which trigger an interrupt? and identify that is triggered at falling edge or rising edge?

This depends on which SDK version you are using.

With SDK 1.1.0, you register a callback function that takes one parameter, which is the same as the same as one you provided to gpio_registerForInterrupt as the third parameter. This allows you to add any context formation the application may need when handling multiple interrupts with the same handler function. For instance, you could use the same callback function to handle interrupts on different GPIOs by invoking gpio_registerForInterrupt() with different masks and userdata parameters and then demultiplex based on userdata in the callback.

With SDK 2.0.1, you register a callback that takes two parameters. The first one works exactly like in SDK 1.1.0 and the second one is a UINT8 with bits 7:5 for the port number and bits 4:0 for the pin number in that port that caused the interrupt [remember that Port = P# / 16 and Pin_of_port = P# % 16].

> and identify that is triggered at falling edge or rising edge?

No, there isn't any API to check if the interrupt is a rising edge or falling edge.

> Or is there any API to identify it? I found gpio_getPortInterruptStatus but not sure this is.

You can use gpio_getPortInterruptStatus(), but this is the asynchronous interrupt status of the entire port and you have to mask off pins that are not configured for interrupt by the application (so bits of only those pins that are configured as an interrupt source are valid, the value of others is not defined).

> Do the handler need to clear interrupt by gpio_clearPortInterruptStatus before exit the handler?

No, the underlying driver will clear the interrupt status. There is a slight difference in the order in which SDK 1.1.0 and SDK 2.0 clear the status. With SDK 1.1.0, the callback you registered is called first and then the interrupt status is cleared while with SDK 2.0.1, the interrupt status is cleared first and then the application's callback is invoked.

0 Likes
Anonymous
Not applicable

Thanks Arvinds,

may i summarize:

To identify GPIO interrupt source pin

using SDK 1.1.0

  • gpio_registerForInterrupt with 3 parameters, and I can pass the parameter via 3rd parameter to interrupt handler. The interrupt handler is called by pass 1 parameter, i.e. the 3rd parameter of gpio_registerForInterrupt.
  • The interrupt handler accept 1 parameter.
  • To check interrupt source, I have to use gpio_getPortInterruptStatus() with mask out pins those are not care as GPIO interrupt.

using SDK 2.0.1

  • gpio_registerForInterrupt() with 3 parameters. The interrupt handler receives 2 parameters.
  • check interrupt source pin by checking the BITs 7:5 and  4:0 in 2nd parameter that is passed when interrupt handler is called.

by the way, in my application I've configure GPIO by bleprofile_GPIOInit(bleprofile_gpio_p_cfg);

Will this conflict to  gpio_registerForInterrupt() ?

0 Likes

You are correct on usage with SDK 2.0.1. But with SDK 1.1.0, there are two ways to ensure that handler recognizes the right GPIO:

1. Use a unique interrupt handler callback for each GPIO (interrupt) you want to handle. For instance, if you want to handle interrupts from P0 and from P15, then use two interrupt handlers, something like this:

UINT16 masks[3] = {(1 << 0), 0, 0};    /// interrupt mask for P0

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler_for_p0, NULL);

masks[0] = 1 << 15;

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler_for_p15, NULL);

// Now configure interrupts for P0 and P15.

So, application_gpio_interrupt_handler_for_p0 will be invoked only if P0 was the interrupt source.

2. Use the same interrupt handler callback for all GPIOs, but use the userdata parameter for demultiplexing.

UINT16 masks[3] = {(1 << 0), 0, 0};    /// interrupt mask for P0

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler, (void*)0);

masks[0] = 1 << 15;

gpio_registerForInterrupt(masks, application_gpio_interrupt_handler, (void*)15);

void application_gpio_interrupt_handler(void* userdata)

{

    UINT32 gpio = (UINT32)userdata;

    switch(gpio)

    {

        case 0:                 /// P0

              break;

        case 15:               /// P15

              break;

    }

}

> in my application I've configure GPIO by bleprofile_GPIOInit(bleprofile_gpio_p_cfg);Will this conflict to  gpio_registerForInterrupt()

This should not in this case, but I recommend that if you use bleprofile_* to configure a GPIO, you should use corresponding bleprofile_* API (mainly because some of these like buttons run state machines underneath). For interrupts from GPIOs, use gpio_*

Anonymous
Not applicable

Very helpful. Thank you,

by the way, i use gpio_getPinInput to check the interrupt is caused by rising edge or falling edge trigger. it seems workable now.

0 Likes
Anonymous
Not applicable

Be careful with this.  The level may have changed by the time your interrupt handler is called, especially if the cpu is sleeping.  Your 'interrupt handler' is just a function that's called by the stack and not a true ISR like you may be used to dealing with. I've seen latencies of up to 5 (yes 5!) milliseconds.

by the way, i use gpio_getPinInput to check the interrupt is caused by rising edge or falling edge trigger. it seems workable now.