mirror of
https://github.com/apache/nuttx.git
synced 2026-06-04 06:42:32 +08:00
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:
@@ -148,10 +148,10 @@
|
|||||||
#define GPIO_IS_INTR(ps) (((uint32_t)(ps) & GPIO_INTR_MASK) == GPIO_INTR_CODE)
|
#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_MASK (0x18 << GPIO_FUNC_SHIFT) /* 111xx */
|
||||||
#define GPIO_TRIG_LEVEL_CODE (0x08 << GPIO_FUNC_SHIFT) /* 010xx */
|
#define GPIO_TRIG_EDGE_CODE (0x08 << GPIO_FUNC_SHIFT) /* 010xx */
|
||||||
#define GPIO_TRIG_EDGE_CODE (0x0c << GPIO_FUNC_SHIFT) /* 011xx */
|
#define GPIO_TRIG_LEVEL_CODE (0x0c << GPIO_FUNC_SHIFT) /* 011xx */
|
||||||
#define GPIO_IS_INTLEVEL(ps) (((uint32_t)(ps) & GPIO_TRIG_MASK) == GPIO_TRIG_LEVEL_CODE)
|
|
||||||
#define GPIO_IS_INTEDGE(ps) (((uint32_t)(ps) & GPIO_TRIG_MASK) == GPIO_TRIG_EDGE_CODE)
|
#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_MASK (0x18 << GPIO_FUNC_SHIFT) /* 11xxx */
|
||||||
#define GPIO_ALT_CODE (0x10 << GPIO_FUNC_SHIFT) /* 10xxx */
|
#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);
|
int lpc54_gpio_irqno(lpc54_pinset_t pinset);
|
||||||
#endif
|
#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
|
* Name: lpc54_gpio_write
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ int lpc54_gpio_interrupt(lpc54_pinset_t pinset)
|
|||||||
/* Write to CIENR to disable rising-edge or level interrupts */
|
/* Write to CIENR to disable rising-edge or level interrupts */
|
||||||
|
|
||||||
case GPIO_INTFE: /* GPIO interrupt falling edge */
|
case GPIO_INTFE: /* GPIO interrupt falling edge */
|
||||||
putreg32(mask, LPC54_PINT_SIENR);
|
putreg32(mask, LPC54_PINT_CIENR);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -260,7 +260,7 @@ int lpc54_gpio_interrupt(lpc54_pinset_t pinset)
|
|||||||
case GPIO_INTFE: /* GPIO interrupt falling edge */
|
case GPIO_INTFE: /* GPIO interrupt falling edge */
|
||||||
case GPIO_INTBOTH: /* GPIO interrupt both edges */
|
case GPIO_INTBOTH: /* GPIO interrupt both edges */
|
||||||
case GPIO_INTHIGH: /* GPIO interrupt high level */
|
case GPIO_INTHIGH: /* GPIO interrupt high level */
|
||||||
putreg32(mask, LPC54_PINT_SIENR);
|
putreg32(mask, LPC54_PINT_SIENF);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Write to CIENF to disable falling-edge or enable active-low level
|
/* 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_INTRE: /* GPIO interrupt rising edge */
|
||||||
case GPIO_INTLOW: /* GPIO interrupt low level */
|
case GPIO_INTLOW: /* GPIO interrupt low level */
|
||||||
putreg32(mask, LPC54_PINT_SIENR);
|
putreg32(mask, LPC54_PINT_CIENF);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -317,4 +317,46 @@ int lpc54_gpio_irqno(lpc54_pinset_t pinset)
|
|||||||
return -ENOENT;
|
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 */
|
#endif /* CONFIG_LPC54_GPIOIRQ */
|
||||||
|
|||||||
@@ -51,8 +51,12 @@ STATUS
|
|||||||
The I2C driver appears to be functional but is not yet well-tested.
|
The I2C driver appears to be functional but is not yet well-tested.
|
||||||
2017-12-16: Added support for LPC54xx GPIO interrupts; added button
|
2017-12-16: Added support for LPC54xx GPIO interrupts; added button
|
||||||
support (with interrupts) to the NSH configuration. The button
|
support (with interrupts) to the NSH configuration. The button
|
||||||
test is partially functional but appears to miss a lot of button-
|
test appears to functional functional. There are noticeable delays
|
||||||
related events. More testing is needed.
|
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
|
Configurations
|
||||||
==============
|
==============
|
||||||
@@ -226,3 +230,26 @@ Configurations
|
|||||||
4. Support for the on-board USER button is included as well as the
|
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
|
button test program at apps/examples/buttons. This test is useful
|
||||||
for verifying the functionality of GPIO interrupts.
|
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.
|
||||||
|
|||||||
@@ -55,6 +55,46 @@
|
|||||||
|
|
||||||
#ifdef CONFIG_ARCH_BUTTONS
|
#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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -72,7 +112,22 @@
|
|||||||
|
|
||||||
void board_button_initialize(void)
|
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)
|
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? */
|
/* Are we attaching or detaching? */
|
||||||
|
|
||||||
if (irqhandler != NULL)
|
if (irqhandler != NULL)
|
||||||
{
|
{
|
||||||
/* Yes.. Attach and enable the interrupt */
|
/* Yes.. Attach and enable the interrupt */
|
||||||
|
|
||||||
ret = irq_attach(irq, irqhandler, arg);
|
g_button_handler = irqhandler;
|
||||||
if (ret >= 0)
|
g_button_arg = arg;
|
||||||
{
|
up_enable_irq(g_button_irq);
|
||||||
up_enable_irq(irq);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* No.. Disable and detach the interrupt */
|
/* No.. Disable and detach the interrupt */
|
||||||
|
|
||||||
up_disable_irq(irq);
|
up_disable_irq(g_button_irq);
|
||||||
ret = irq_detach(irq);
|
g_button_handler = NULL;
|
||||||
|
g_button_arg = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
Reference in New Issue
Block a user