Answered

Example using GPIO hard-button inputs mapped to standard key board events when running Storyboard on MCUs

We typically leave this code implementation up to customers as the hardware is very board specific however we did not have a great deal of documentation to show how this could be done for an MCU target hence a post on the topic was suggested.
 
By way of illustration however here is technique often used where a physical user button connected to a GPIO pin can be used to emulate a standard keyboard button input to Storyboard.

Below is an outline example based on the NXP MCUXpresso SDK using an iMXRT1050 EVK which has a single user button.  You can port this to other BSP's, SDK platforms and toolchains pretty simply if needed.
 
What this approach does is to configure the pin connected to the button as an input and detect the low-level pin state change via interrupt.  This example then maps that activity to emulate a normal keyboard 'ENTER' key keypress and release event to be passed to the Storyboard model.
 
First you need to setup the low-level hardware on your board (your GPIO mapping may be different):

/*******************************************************************************
* Code
******************************************************************************/

/*! @brief Define the port interrupt number for the board switches */
#ifndef BOARD_USER_BUTTON_GPIO
#define BOARD_USER_BUTTON_GPIO GPIO5
#endif
#ifndef BOARD_USER_BUTTON_GPIO_PIN
#define BOARD_USER_BUTTON_GPIO_PIN (0U)
#endif

/* initialise the IO pins for the input button and User LED */
void BOARD_InitUserGPIO(void)
{
/* Define the init structure for the output LED pin*/
gpio_pin_config_t led_config = {
kGPIO_DigitalOutput, 0, kGPIO_NoIntmode
};

/* Init output LED GPIO. */
GPIO_PinInit(BOARD_USER_LED_GPIO, BOARD_USER_LED_GPIO_PIN, &led_config);

/* initial pin state is high (LED off) */
GPIO_PinWrite(BOARD_USER_LED_GPIO, BOARD_USER_LED_GPIO_PIN, 1U);

/* Define the init structure for the input switch pin */
gpio_pin_config_t sw_config = {
kGPIO_DigitalInput, 0,
kGPIO_IntRisingOrFallingEdge,
};

/* Init input switch GPIO. */
EnableIRQ(BOARD_USER_BUTTON_IRQ);
GPIO_PinInit(BOARD_USER_BUTTON_GPIO, BOARD_USER_BUTTON_GPIO_PIN, &sw_config);

/* Enable GPIO pin interrupt */
GPIO_PortEnableInterrupts(BOARD_USER_BUTTON_GPIO, 1U << BOARD_USER_BUTTON_GPIO_PIN);

}

 
Next we have the interrupt handler which checks for this single IO pin for button press or release but if you have more physical buttons or for example have an I2C IO port expander, rotary encoder or something then then you will code this specifically to your board... hopefully you get the idea?
 
This particular hardware has the user 'SW8' button pin wired on GPIO5:

#define BOARD_USER_BUTTON_IRQ             GPIO5_Combined_0_15_IRQn 
#define BOARD_USER_BUTTON_IRQ_HANDLER GPIO5_Combined_0_15_IRQHandler
#define BOARD_USER_BUTTON_NAME "SW8"

/* Whether the SW interrupt is triggered */
volatile bool g_KeyInputEvent = false;
/* The user button state */
volatile uint32_t g_btnPressed = 0; // released

/*!
* @brief Interrupt service function of switch.
*/
void BOARD_USER_BUTTON_IRQ_HANDLER(void)
{
/* Sample the USER BUTTON GPIO state on entry to determine press/release state, pin active low with a pull-up.
* interrupt is falling and rising edge triggered
* if we were triggered by falling edge ^^\__ = button pressed
* if we were triggered by rising edge __/^^ = button released
*/
if( GPIO_PinRead(BOARD_USER_BUTTON_GPIO, BOARD_USER_BUTTON_GPIO_PIN) == 1 )
{
g_btnPressed = 0;
}else
{
g_btnPressed = 1;
}

/* clear the interrupt status */
GPIO_PortClearInterruptFlags(BOARD_USER_BUTTON_GPIO, 1U << BOARD_USER_BUTTON_GPIO_PIN);
/* Change state of switch. */
g_KeyInputEvent = true;

/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
exception return operation might vector to incorrect interrupt */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}

Now instead of scanning for a touch screen input as we would if there was a touch screen driver we now have the Storyboard input task scanning for and decoding physical button presses into an associated standard keyboard press / release event for the 'ENTER' key:

void
sbengine_input_task(void *arg) {
const int sleep_msec = 100;
greal_timespec_t sleep_time = {
.tv_sec = 0,
.tv_nsec = sleep_msec * 1000000
};

gr_key_event_t key_event = { 0, GR_KEY_ENTER, 0}; // create the template key event pre-filled with 'ENTER' key

/* initialise GPIO for USER LED and Button */
BOARD_InitUserGPIO();

while (1) {
/* GPIO USER BUTTON interrupt key event is both falling and rising edge triggered
*
*  We will send an ENTER key emulation
*/
if( g_KeyInputEvent == true )
{
if(g_btnPressed)
{
// button pressed (was a high to low transition)
gr_application_send_event(app, NULL, GR_EVENT_KEY_DOWN, GR_EVENT_KEY_FMT, &key_event, sizeof(key_event));
}else
{
// button released (was a low to high transition)
gr_application_send_event(app, NULL, GR_EVENT_KEY_UP, GR_EVENT_KEY_FMT, &key_event, sizeof(key_event));
}
g_KeyInputEvent = false;
}
greal_nanosleep(&sleep_time, NULL);
}
}

You can see our standard event definitions and keyboard codes in the gre/iodefs.h header file supplied with Storyboard:

/**
* KEY EVENTS
*/

#define GR_KEYMODBIT_SHIFT 0
#define GR_KEYMODBIT_CTRL 1
#define GR_KEYMODBIT_ALT 2

#define GR_KEYMOD_SHIFT (1 << GR_KEYMODBIT_SHIFT)
#define GR_KEYMOD_CTRL (1 << GR_KEYMODBIT_CTRL)
#define GR_KEYMOD_ALT (1 << GR_KEYMODBIT_ALT)

typedef enum gr_key {
GR_KEY_INVALID = 0,

GR_KEY_BACKSPACE = 0x08,
GR_KEY_TAB = 0x09,

GR_KEY_CLEAR = 0X0C,
GR_KEY_ENTER = 0x0D,

GR_KEY_PAUSE = 0x13,
GR_KEY_CAPS_LOCK = 0x14,

GR_KEY_ESCAPE = 0x1B,
:

This technique works well for mapping standard hard-buttons to preset keyboard key presses and allows you to test and simulate the application easily in the Storyboard Designer environment on the desktop.

For other non-standard input devices such as jog wheels or rotary encoders, sensors and other asynchronous inputs you can simply create a custom event instead and post that with gr_application_send_event(...)

0

Comments

0 comments

Please sign in to leave a comment.

Didn't find what you were looking for?

New post