diff --git a/arch/arm/src/lpc54xx/lpc54_gpio.h b/arch/arm/src/lpc54xx/lpc54_gpio.h index 19243742731..8f44f82c86a 100644 --- a/arch/arm/src/lpc54xx/lpc54_gpio.h +++ b/arch/arm/src/lpc54xx/lpc54_gpio.h @@ -148,10 +148,10 @@ #define GPIO_IS_INTR(ps) (((uint32_t)(ps) & GPIO_INTR_MASK) == GPIO_INTR_CODE) #define GPIO_TRIG_MASK (0x18 << GPIO_FUNC_SHIFT) /* 111xx */ -#define GPIO_TRIG_LEVEL_CODE (0x08 << GPIO_FUNC_SHIFT) /* 010xx */ -#define GPIO_TRIG_EDGE_CODE (0x0c << GPIO_FUNC_SHIFT) /* 011xx */ -#define GPIO_IS_INTLEVEL(ps) (((uint32_t)(ps) & GPIO_TRIG_MASK) == GPIO_TRIG_LEVEL_CODE) +#define GPIO_TRIG_EDGE_CODE (0x08 << GPIO_FUNC_SHIFT) /* 010xx */ +#define GPIO_TRIG_LEVEL_CODE (0x0c << GPIO_FUNC_SHIFT) /* 011xx */ #define GPIO_IS_INTEDGE(ps) (((uint32_t)(ps) & GPIO_TRIG_MASK) == GPIO_TRIG_EDGE_CODE) +#define GPIO_IS_INTLEVEL(ps) (((uint32_t)(ps) & GPIO_TRIG_MASK) == GPIO_TRIG_LEVEL_CODE) #define GPIO_ALT_MASK (0x18 << GPIO_FUNC_SHIFT) /* 11xxx */ #define GPIO_ALT_CODE (0x10 << GPIO_FUNC_SHIFT) /* 10xxx */ @@ -308,6 +308,20 @@ int lpc54_gpio_interrupt(lpc54_pinset_t pinset); int lpc54_gpio_irqno(lpc54_pinset_t pinset); #endif +/************************************************************************************ + * Name: lpc54_gpio_ackedge + * + * Description: + * Acknowledge edge interrupts by clearing the associated bits in the rising and + * falling registers. This acknowledgemment is, of course, not needed for level + * interupts. + * + ************************************************************************************/ + +#ifdef CONFIG_LPC54_GPIOIRQ +int lpc54_gpio_ackedge(int irq); +#endif + /************************************************************************************ * Name: lpc54_gpio_write * diff --git a/arch/arm/src/lpc54xx/lpc54_gpioirq.c b/arch/arm/src/lpc54xx/lpc54_gpioirq.c index d38050d5b27..8a0a9749c9c 100644 --- a/arch/arm/src/lpc54xx/lpc54_gpioirq.c +++ b/arch/arm/src/lpc54xx/lpc54_gpioirq.c @@ -243,7 +243,7 @@ int lpc54_gpio_interrupt(lpc54_pinset_t pinset) /* Write to CIENR to disable rising-edge or level interrupts */ case GPIO_INTFE: /* GPIO interrupt falling edge */ - putreg32(mask, LPC54_PINT_SIENR); + putreg32(mask, LPC54_PINT_CIENR); break; default: @@ -260,7 +260,7 @@ int lpc54_gpio_interrupt(lpc54_pinset_t pinset) case GPIO_INTFE: /* GPIO interrupt falling edge */ case GPIO_INTBOTH: /* GPIO interrupt both edges */ case GPIO_INTHIGH: /* GPIO interrupt high level */ - putreg32(mask, LPC54_PINT_SIENR); + putreg32(mask, LPC54_PINT_SIENF); break; /* Write to CIENF to disable falling-edge or enable active-low level @@ -269,7 +269,7 @@ int lpc54_gpio_interrupt(lpc54_pinset_t pinset) case GPIO_INTRE: /* GPIO interrupt rising edge */ case GPIO_INTLOW: /* GPIO interrupt low level */ - putreg32(mask, LPC54_PINT_SIENR); + putreg32(mask, LPC54_PINT_CIENF); break; default: @@ -317,4 +317,46 @@ int lpc54_gpio_irqno(lpc54_pinset_t pinset) return -ENOENT; } +/************************************************************************************ + * Name: lpc54_gpio_ackedge + * + * Description: + * Acknowledge edge interrupts by clearing the associated bits in the rising and + * falling registers. This acknowledgemment is, of course, not needed for level + * interupts. + * + ************************************************************************************/ + +int lpc54_gpio_ackedge(int irq) +{ + uint32_t regval; + uint32_t mask; + unsigned int pinint; + + /* Map the IRQ number to a pin interrupt number */ + + if (irq >= LPC54_IRQ_PININT0 && irq <= LPC54_IRQ_PININT3) + { + pinint = irq - LPC54_IRQ_PININT0; + } + else if (irq >= LPC54_IRQ_PININT4 && irq <= LPC54_IRQ_PININT7) + { + pinint = irq - LPC54_IRQ_PININT4 + 4; + } + else + { + return -EINVAL; + } + + /* Acknowledge the pin interrupt */ + + mask = (1 << pinint); + regval = getreg32(LPC54_PINT_RISE) & mask; + putreg32(regval, LPC54_PINT_RISE); + + regval = getreg32(LPC54_PINT_FALL) & mask; + putreg32(regval, LPC54_PINT_FALL); + return OK; +} + #endif /* CONFIG_LPC54_GPIOIRQ */ diff --git a/configs/lpcxpresso-lpc54628/README.txt b/configs/lpcxpresso-lpc54628/README.txt index 9c48c38490a..baaa7ddcb18 100644 --- a/configs/lpcxpresso-lpc54628/README.txt +++ b/configs/lpcxpresso-lpc54628/README.txt @@ -51,8 +51,12 @@ STATUS The I2C driver appears to be functional but is not yet well-tested. 2017-12-16: Added support for LPC54xx GPIO interrupts; added button support (with interrupts) to the NSH configuration. The button - test is partially functional but appears to miss a lot of button- - related events. More testing is needed. + test appears to functional functional. There are noticeable delays + in receiving the button events, especially when the button is + released. But if you do not press the buttons too quickly all events + are processed. This, I suspect, is a consequence of the strong glitch + filtering that is enbled in the pin configuration. Snappier + response my be obtainble with filtering off. Configurations ============== @@ -226,3 +230,26 @@ Configurations 4. Support for the on-board USER button is included as well as the button test program at apps/examples/buttons. This test is useful for verifying the functionality of GPIO interrupts. + + NuttShell (NSH) NuttX-7.23 + nsh> buttons + buttons_main: Starting the button_daemon + buttons_main: button_daemon started + button_daemon: Running + button_daemon: Opening /dev/buttons + button_daemon: Supported BUTTONs 0x01 + nsh> Sample = 1 + Sample = 0 + Sample = 1 + Sample = 0 + Sample = 1 + Sample = 0 + Sample = 1 + etc. + + There are noticeable delays in receiving the button events, + especially when the button is released. But if you do not press the + buttons too quickly all events are processed. This, I suspect, is a + consequence of the strong glitch filtering that is enbled in the pin + configuration. Snappier response my be obtainble with filtering off + if desired. diff --git a/configs/lpcxpresso-lpc54628/src/lpc54_buttons.c b/configs/lpcxpresso-lpc54628/src/lpc54_buttons.c index 98b9db4db67..556347ee151 100644 --- a/configs/lpcxpresso-lpc54628/src/lpc54_buttons.c +++ b/configs/lpcxpresso-lpc54628/src/lpc54_buttons.c @@ -55,6 +55,46 @@ #ifdef CONFIG_ARCH_BUTTONS +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#if defined(CONFIG_LPC54_GPIOIRQ) && defined(CONFIG_ARCH_IRQBUTTONS) +static uint8_t g_button_irq; +static xcpt_t g_button_handler; +static void *g_button_arg; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_button_interrupt + * + * Description: + * This function intermediates the interrupt provided to the application + * logic that attached the interrupt. This is necessary to properly + * clear the pending button interrupts. + * + ****************************************************************************/ + +static int board_button_interrupt(int irq, FAR void *context, FAR void *arg) +{ + /* Acknowledge the button interrupt */ + + (void)lpc54_gpio_ackedge(irq); + + /* Transfer control to the attached interrupt handler */ + + if (g_button_handler != NULL) + { + return g_button_handler(irq, context, arg); + } + + return OK; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -72,7 +112,22 @@ void board_button_initialize(void) { - (void)lpc54_gpio_config(GPIO_BUTTON_USER); + int ret; + + /* Configure the button GPIO interrupt */ + + ret = lpc54_gpio_config(GPIO_BUTTON_USER); + if (ret >= 0) + { +#if defined(CONFIG_LPC54_GPIOIRQ) && defined(CONFIG_ARCH_IRQBUTTONS) + /* Get the IRQ that is associated with the PIN interrupt and attach the + * intermediate button interrupt handler to that interrupt. + */ + + g_button_irq = lpc54_gpio_irqno(GPIO_BUTTON_USER); + (void)irq_attach(g_button_irq, board_button_interrupt, NULL); +#endif + } } /**************************************************************************** @@ -115,35 +170,26 @@ int board_button_irq(int id, xcpt_t irqhandler, FAR void *arg) if (id == BUTTON_USER) { - int irq; - - /* Get the IRQ number assigned to the port/pin when it was condfigured. */ - - irq = lpc54_gpio_irqno(GPIO_BUTTON_USER); - if (irq < 0) - { - return irq; - } - /* Are we attaching or detaching? */ if (irqhandler != NULL) { /* Yes.. Attach and enable the interrupt */ - ret = irq_attach(irq, irqhandler, arg); - if (ret >= 0) - { - up_enable_irq(irq); - } + g_button_handler = irqhandler; + g_button_arg = arg; + up_enable_irq(g_button_irq); } else { /* No.. Disable and detach the interrupt */ - up_disable_irq(irq); - ret = irq_detach(irq); + up_disable_irq(g_button_irq); + g_button_handler = NULL; + g_button_arg = NULL; } + + ret = OK; } return ret;