arch/arm/src/lpc54xx: Fix some GPIO interrupt configuration errors. Add logic to acknowledge rising/falling edge events. config/lpcxpresso-lpc545628: Add an intermediate interrupt handler to support acknowledgement of rising and falling edge interrupts.

This commit is contained in:
Gregory Nutt 2017-12-16 15:34:41 -06:00
parent 5a12079e53
commit de4fc5864f
4 changed files with 155 additions and 26 deletions

View File

@ -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
*

View File

@ -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 */

View File

@ -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.

View File

@ -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;