BGM111 button press detection with interrupts - C project

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac ‎12-12-2016 09:37 AM - edited ‎05-04-2017 08:24 AM

 

This example project demonstrates how to use interrupts to detect button presses. The example is written for BGM111 development kit in C language with Bluetooth SDK v2.0.1. The BGScript version of this project can be found at:

http://community.silabs.com/t5/Bluetooth-Wi-Fi-Knowledge-Base/BGScript-BGM111-button-press-detection...

 

The example differentiates 3 kind of button presses:

  • short (press and release within a defined short interval)
  • long (press and release over a defined short interval)
  • double click (two presses within a defined short interval)

 

The button presses generate external stack events (gecko_evt_system_external_signal), which can be handled by the user on demand. In the example log messages are sent to UART using UARTDRV.

 

Since UARTDRV uses interrupts as well, an interrupt dispatcher is used instead of writing interrupt handlers. This is implemented in gpiointerrupt.c (${StudioSdkPath}/platform/emdrv/gpiointerrupt/src/gpiointerrupt.c)

 

The interrupts are enabled for both rising and falling edges by:

 

GPIOINT_Init();
GPIO_ExtIntConfig(gpioPortF,6,6,true,true,true);
GPIO_ExtIntConfig(gpioPortF,7,7,true,true,true);

 

And the callback functions are set by 

 

GPIOINT_CallbackRegister(6,handle_button_change);
GPIOINT_CallbackRegister(7,handle_button_change);

Note, that the dispatcher uses pin numbers, no interrupt handler numbers, so in this case the 3rd parameter of GPIO_ExtIntConfig(...) is practically not used.

 

The rising/falling edge can be differentiated by reading the state of the GPIO pins in the interrupt handler.

Comments
by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Ninja</font></font> </a> klangdon79
on ‎01-25-2017 04:13 PM

One issue with this approach is that you lose any timestamp of when the interrupt happened inside the handling of the external_signal. If you instead configure the interrupts with gecko_config and use bgapi_hardware_init, you can get the interrupts with timestamp into the hardware_interrupt event.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV
on ‎03-13-2017 08:45 AM

@klangdon79 the event evt_hardware_interrupt is deprecated starting from SDK v2.3.0. Most of the HW related BGAPI calls are marked deprecated (ADC, GPIO, interrupts). It is better to handle the HW peripherals directly using emlib or emdrv. 

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-03-2017 09:35 AM

@JaakkoV for SDK v2.3.1 should GPIO interrupts be configured using functions from em_gpio.c OR should they be configured using the gpios and gpio_exti members of the gecko_configuration_t struct?

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV
on ‎05-03-2017 10:06 AM

@Mooneyj it is recommended to NOT use the gecko_configuration_t struct for GPIO interrupts but to use either em_gpio.c or GPIOINT driver from emdrv (like in the code that is published in this article)

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-03-2017 01:39 PM

I set mine up just like the code in this post, but I still haven't been able to get the IRQ handlers to hit.  My code is below.  Am I missing a step?

 

#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_rtcc.h"

 

void GPIO_EVEN_IRQHandler(void)
{
    uint32_t flags = GPIO_IntGet();
}

void GPIO_ODD_IRQHandler(void)
{
    uint32_t flags = GPIO_IntGet();
}

 

void main(void)
{
#ifdef FEATURE_SPI_FLASH
/* Put the SPI flash into Deep Power Down mode for those radio boards where it is available */
MX25_init();
MX25_DP();
/* We must disable SPI communication */
USART_Reset(USART1);
#endif /* FEATURE_SPI_FLASH */

/* Initialize peripherals */
enter_DefaultMode_from_RESET();

// Interrupts
NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
NVIC_EnableIRQ(GPIO_ODD_IRQn);
NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
NVIC_EnableIRQ(GPIO_EVEN_IRQn);
GPIO_PinModeSet(gpioPortF,6,gpioModeInput,0);
GPIO_PinModeSet(gpioPortF,7,gpioModeInput,0);
GPIO_ExtIntConfig(gpioPortF,6,0,true,true,true);
GPIO_ExtIntConfig(gpioPortF,7,1,true,true,true);

/* Initialize stack */
gecko_init(&config);

 

while(1);

}

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-03-2017 01:40 PM

@JaakkoV 

 

I set mine up just like the code in this post, but I still haven't been able to get the IRQ handlers to hit.  My code is below.  Am I missing a step?

 

#include "em_emu.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_rtcc.h"

 

void GPIO_EVEN_IRQHandler(void)
{
    uint32_t flags = GPIO_IntGet();
}

void GPIO_ODD_IRQHandler(void)
{
    uint32_t flags = GPIO_IntGet();
}

 

void main(void)
{
#ifdef FEATURE_SPI_FLASH
/* Put the SPI flash into Deep Power Down mode for those radio boards where it is available */
MX25_init();
MX25_DP();
/* We must disable SPI communication */
USART_Reset(USART1);
#endif /* FEATURE_SPI_FLASH */

/* Initialize peripherals */
enter_DefaultMode_from_RESET();

// Interrupts
NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
NVIC_EnableIRQ(GPIO_ODD_IRQn);
NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
NVIC_EnableIRQ(GPIO_EVEN_IRQn);
GPIO_PinModeSet(gpioPortF,6,gpioModeInput,0);
GPIO_PinModeSet(gpioPortF,7,gpioModeInput,0);
GPIO_ExtIntConfig(gpioPortF,6,0,true,true,true);
GPIO_ExtIntConfig(gpioPortF,7,1,true,true,true);

/* Initialize stack */
gecko_init(&config);

 

while(1);

}

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV
on ‎05-03-2017 02:04 PM

How are you testing this and with which toolchain (IAR or GCC)? I noticed in some of my tests that GCC & breakpoints set inside IRQ handler like in this case do not work (breakpoint is never hit) unless I turn optimization level to "none" in build settings.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-03-2017 02:41 PM

I'm using IAR 8.10 toolchain.  I know Simplicity Studio recommends using nothing newer than IAR 7.30.  Could this be the issue?

 

I changed my IRQ handlers to send an external signal to the stacks, and I set a breakpoint on the gecko_external_signal event, but I'm not hitting that breakpoint either.  My optimization is set to "none."

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV
on ‎05-03-2017 03:01 PM

Don't know if IAR 8.x is the reason (I know there are some issues with 8.x version but don't know exactly what). Why not test with GCC? That worked fine in my tests. GCC toolchain (4.9.3) should be available in Studio without any extra hassle, just pick that toolchain instead of IAR when creating one of the example projects.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-03-2017 04:33 PM

I created a new project using IAR 7.30 and got the same results.  Then I created another new project with GCC 4.9.3 and got the same results.  I'm starting to wonder if there's an issue with the hardware.

 

Do you have any other ideas?

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Legend Employee</font></font> </a> JaakkoV
on ‎05-04-2017 03:26 AM

@Mooneyj are you testing with BGM111 (BRD4300A) or some other radio board?

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac
on ‎05-04-2017 03:57 AM

 

If you are testing with a WSTK, you should define the inputs as

  GPIO_PinModeSet(gpioPortF,6,gpioModeInputPullFilter,1);

  GPIO_PinModeSet(gpioPortF,7,gpioModeInputPullFilter,1);

since the pushbutton need a pullup resistor to work.

 

Why don't you use gpiointerrupt.c as in the attached example? It is part of the SDK and can be found under

${StudioSdkPath}/platform/emdrv/gpiointerrupt/src

 

 

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Hero Employee</font></font> </a> arkalvac
‎05-04-2017 08:12 AM - edited ‎05-04-2017 08:13 AM

 

OK, turned out, that the problem is with the mapping of pins to interrupt numbers. In earlier SDK version this was disregarded, but with the latest SDK the interrupt number should be in the same group as the pin number. Pins and interrups are handled in groups of four. That is, you can use INT0,1,2,3 for pin numbers 0,1,2,3; INT4,5,6,7 for pin numbers 4,5,6,7 etc.

 

Change

  GPIO_ExtIntConfig(gpioPortF,6,0,true,true,true);
  GPIO_ExtIntConfig(gpioPortF,7,1,true,true,true);

to

  GPIO_ExtIntConfig(gpioPortF,6,6,true,true,true);
  GPIO_ExtIntConfig(gpioPortF,7,7,true,true,true);

 

I will correct this in the article, too.

by <a href="http://community.silabs.com/t5/Welcome-and-Announcements/Community-Ranking-System-and-Recognition-Program/m-p/140490#U140490"><font color="#000000"><font size="2">Super Star</font></font> </a> Mooneyj
on ‎05-04-2017 08:17 AM

@arkalvac That did the trick.  Thanks for looking into this.  I appreciate the prompt support.  Same goes to you @JaakkoV.