LPC17xx GPIO interrupt fixes: lpc17_setintedge() must be atomic. Can't disable interrupts from interrupt handlers because they are automatically re-enabled. Try re-configuring pin instead.

This commit is contained in:
Gregory Nutt 2013-04-07 13:46:05 -06:00
parent a3906f2f72
commit 141fb6a32b
7 changed files with 94 additions and 32 deletions

View File

@ -4523,4 +4523,10 @@
* arch/arm/src/lpc17_gpiodbg.c: Updated so that it correctly * arch/arm/src/lpc17_gpiodbg.c: Updated so that it correctly
reports LPC177x/8x GPIO registers when GPIO debug is enabled reports LPC177x/8x GPIO registers when GPIO debug is enabled
(2013-4-05). (2013-4-05).
* arch/arm/src/Makefile: The variable NUTTX already includes
the extension $(EXEEXT). So remove the second extension
$(NUTTX)$(EXEEXT) in two places (2013-4-7).
* arch/arm/src/lpc17xx/lpc17_gpioint.c: Disable interrrupts in
lpc17_setintedge(). This logic must be atomic because it can be
re-entered before it completes enabled interrupts, sometimes
leaving the interrupts in a strange state (2013-4-7).

2
TODO
View File

@ -364,8 +364,6 @@ o Kernel Build
A similar issue exists in NSH that uses some internal OS A similar issue exists in NSH that uses some internal OS
interfaces that would not be available in a kernel build interfaces that would not be available in a kernel build
(such as foreach_task, foreach_mountpoint, etc.). (such as foreach_task, foreach_mountpoint, etc.).
See also "Memory Management" for another kernel build issue.
Status: Open Status: Open
Priority: Low -- the kernel build configuration is not fully fielded Priority: Low -- the kernel build configuration is not fully fielded
yet. yet.

View File

@ -99,7 +99,7 @@
#define GPIO_SSP1_MISO_1 (GPIO_ALT2 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN8) #define GPIO_SSP1_MISO_1 (GPIO_ALT2 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN8)
#define GPIO_MAT2p2_1 (GPIO_ALT3 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN8) #define GPIO_MAT2p2_1 (GPIO_ALT3 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN8)
#define GPIO_RTC_EV1_1 (GPIO_ALT4 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN8) #define GPIO_RTC_EV1_1 (GPIO_ALT4 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN8)
#define GPIO_LCD_VD16 (GPIO_ALT7 | GPIO_FLOA | GPIO_HYSTERESIST | GPIO_PORT0 | GPIO_PIN8) #define GPIO_LCD_VD16 (GPIO_ALT7 | GPIO_FLOAT | GPIO_HYSTERESIS | GPIO_PORT0 | GPIO_PIN8)
#define GPIO_I2S_TXSDA_1 (GPIO_ALT1 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN9) #define GPIO_I2S_TXSDA_1 (GPIO_ALT1 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN9)
#define GPIO_SSP1_MOSI_1 (GPIO_ALT2 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN9) #define GPIO_SSP1_MOSI_1 (GPIO_ALT2 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN9)

View File

@ -116,8 +116,13 @@ static unsigned int lpc17_getintedge(unsigned int port, unsigned int pin)
static void lpc17_setintedge(uint32_t intbase, unsigned int pin, static void lpc17_setintedge(uint32_t intbase, unsigned int pin,
unsigned int edges) unsigned int edges)
{ {
irqstate_t flags;
int regval; int regval;
/* These must be atomic */
flags = irqsave();
/* Set/clear the rising edge enable bit */ /* Set/clear the rising edge enable bit */
regval = getreg32(intbase + LPC17_GPIOINT_INTENR_OFFSET); regval = getreg32(intbase + LPC17_GPIOINT_INTENR_OFFSET);
@ -145,6 +150,7 @@ static void lpc17_setintedge(uint32_t intbase, unsigned int pin,
} }
putreg32(regval, intbase + LPC17_GPIOINT_INTENF_OFFSET); putreg32(regval, intbase + LPC17_GPIOINT_INTENF_OFFSET);
irqrestore(flags);
} }
/**************************************************************************** /****************************************************************************
@ -389,9 +395,10 @@ static void lpc17_gpiodemux(uint32_t intbase, uint32_t intmask,
* Name: lpc17_gpiointerrupt * Name: lpc17_gpiointerrupt
* *
* Description: * Description:
* Handle the EINT3 interrupt that also indicates that a GPIO interrupt has * Handle the GPIO interrupt. For the LPC176x family, that interrupt could
* occurred. NOTE: This logic will have to be extended if EINT3 is * also that also indicates that an EINT3 interrupt has occurred. NOTE:
* actually used for External Interrupt 3. * This logic would have to be extended if EINT3 is actually used for
* External Interrupt 3 on an LPC176x platform.
* *
****************************************************************************/ ****************************************************************************/

View File

@ -12,6 +12,7 @@ CONTENTS
o Buttons o Buttons
o FPU o FPU
o Using OpenOCD with the Olimex ARM-USB-OCD o Using OpenOCD with the Olimex ARM-USB-OCD
o Loading Code with the ISP Board
o Configuration o Configuration
LEDs LEDs
@ -245,27 +246,53 @@ Using OpenOCD with the Olimex ARM-USB-OCD
(gdb) monitor halt (gdb) monitor halt
NOTES: NOTES:
1. The MCU must be halted using 'monitor halt' prior to loading code. 1. The MCU must be halted using 'monitor halt' prior to loading code.
2. 'monitor reset' will restart the processor after loading code. 2. 'monitor reset' will restart the processor after loading code.
3. The 'monitor' command can be abbreviated as just 'mon'. 3. The 'monitor' command can be abbreviated as just 'mon'.
After starting GDB, you can load the NuttX ELF file: After starting GDB, you can load the NuttX ELF file like this:
(gdb) mon halt (gdb) mon halt
(gdb) load nuttx (gdb) load nuttx
NOTES: NOTES:
1. NuttX should have been built so that it has debugging symbols 1. NuttX should have been built so that it has debugging symbols
(by setting CONFIG_DEBUG_SYMBOLS=y in the .config file). (by setting CONFIG_DEBUG_SYMBOLS=y in the .config file).
2. The MCU must be halted prior to loading code. 2. The MCU must be halted prior to loading code.
3. I find that there are often undetected write failures. I usually
load nuttx twice to assure good FLASH contents: 3. I find that there are often undetected write failures when using
the Olimex ARM-USB-OCD debugber and that if you start the program
with a bad FLASH failure, it will lock up OpenOCD. I usually
oad nuttx twice, restarting OpenOCD in between in order to assure
good FLASH contents:
(gdb) mon halt (gdb) mon halt
(gdb) load nuttx (gdb) load nuttx
(gdb) mon reset (gdb) mon reset
Exit GDB, kill the OpenOCD server, recycle power on the board,
restart the OpenOCD server and GDB, then:
(gdb) mon halt (gdb) mon halt
(gdb) load nuttx (gdb) load nuttx
(gdb) mon reset
Other debuggers may not have these issues and such drastic steps may
not be necessary.
Loading Code with the ISP Board
===============================
Use can also load code onto the board using the WaveShare and the UART0
ISP/VCOM board. I use the FlashMagic program for Windows available here:
http://www.flashmagictool.com/ . It is so easy to use that no further
explanation should be necessary: Just select the LPC1788, the ISP COM
port, and the NuttX .hex file and program it.
CONFIGURATION CONFIGURATION
============= =============
@ -452,15 +479,20 @@ CONFIGURATION
on the 4.3" LCD module by modifying the configuration in the on the 4.3" LCD module by modifying the configuration in the
following ways: following ways:
CONFIG_INPUT=y : Enable support for input devices Drivers:
CONFIG_INPUT_ADS7843E=y : Enable support for the XPT2048 CONFIG_INPUT=y : Enable support for input devices
CONFIG_ADS7843E_SPIDEV=1 : Use SSP1 for communication CONFIG_INPUT_ADS7843E=y : Enable support for the XPT2048
CONFIG_SPI=y : Enable SPI support CONFIG_ADS7843E_SPIDEV=1 : Use SSP1 for communication
CONFIG_SPI_EXCHANGE=n : exchange() method is not supported CONFIG_SPI=y : Enable SPI support
CONFIG_GPIO_IRQ=y : GPIO interrupt support CONFIG_SPI_EXCHANGE=n : exchange() method is not supported
CONFIG_LPC17_SSP1=y : Enable support for SSP1
CONFIG_EXAMPLES_TOUCHSCREEN=y : Enable the touchscreen built-int test System Type:
CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN=y CONFIG_GPIO_IRQ=y : GPIO interrupt support
CONFIG_LPC17_SSP1=y : Enable support for SSP1
Applicaton Configuration:
CONFIG_EXAMPLES_TOUCHSCREEN=y : Enable the touchscreen built-int test
CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN=y
Defaults should be okay for related touchscreen settings. Defaults should be okay for related touchscreen settings.
@ -470,18 +502,24 @@ CONFIGURATION
There is a jumper on board that enables the CD pin. OR, you can simply There is a jumper on board that enables the CD pin. OR, you can simply
remove the SD module so that it does not drive the CD pin. remove the SD module so that it does not drive the CD pin.
CONFIG_LPC17_GPDMA=n : No DMA Drivers:
CONFIG_ARCH_DMA=n CONFIG_MMCSD=n : No MMC/SD driver support
CONFIG_LPC17_SDCARD=n : No SD card driver
CONFIG_SDIO_DMA=n : No SD card DMA System Type:
CONFIG_MMCSD=n : No MMC/SD driver support CONFIG_LPC17_GPDMA=n : No DMA
CONFIG_FS_FAT=n : No FAT file system support CONFIG_LPC17_SDCARD=n : No SD card driver
CONFIG_SDIO_DMA=n : No SD card DMA
CONFIG_ARCH_DMA=n
File Systems:
CONFIG_FS_FAT=n : No FAT file system support
For touchscreen debug output: For touchscreen debug output:
CONFIG_DEBUG=y Build Setup:
CONFIG_DEBUG_VERBOSE=y CONFIG_DEBUG=y
CONFIG_DEBUG_INPUT=y CONFIG_DEBUG_VERBOSE=y
CONFIG_DEBUG_INPUT=y
nxlines nxlines
------- -------

View File

@ -178,11 +178,21 @@ static void tsc_enable(FAR struct ads7843e_config_s *state, bool enable)
ivdbg("enable:%d\n", enable); ivdbg("enable:%d\n", enable);
if (enable) if (enable)
{ {
/* Configure the PENIRQ GPIO as an interrupting enable and enable the interrupt */
(void)lpc17_configgpio(GPIO_TC_PENIRQ);
up_enable_irq(LPC17_IRQ_PENIRQ); up_enable_irq(LPC17_IRQ_PENIRQ);
} }
else else
{ {
/* Disable PENIRQ interrupts and reconfigure the pin as a normal input pin.
* We have to do this because the PENIRQ interrupt will be disabled from
* interrupt handling logic and, in that case, will be automatically re-enabled
* when the interrupt returns.
*/
up_disable_irq(LPC17_IRQ_PENIRQ); up_disable_irq(LPC17_IRQ_PENIRQ);
(void)lpc17_configgpio(GPIO_TC_PEN);
} }
} }
@ -278,9 +288,12 @@ int arch_tcinitialize(int minor)
if (!initialized) if (!initialized)
{ {
/* Configure and enable the XPT2046 PENIRQ pin as an interrupting input. */ /* Configure and enable the XPT2046 PENIRQ pin as a normal input. It
* will be reconfigured as an interrupting input when tsc_enable is
* called to enable the PENIRQ interrupt.
*/
(void)lpc17_configgpio(GPIO_TC_PENIRQ); (void)lpc17_configgpio(GPIO_TC_PEN);
/* Configure the XPT2046 BUSY pin as a normal input. */ /* Configure the XPT2046 BUSY pin as a normal input. */
@ -304,7 +317,7 @@ int arch_tcinitialize(int minor)
{ {
idbg("Failed to register touchscreen device minor=%d\n", idbg("Failed to register touchscreen device minor=%d\n",
CONFIG_ADS7843E_DEVMINOR); CONFIG_ADS7843E_DEVMINOR);
/* up_spiuninitialize(dev); */ /* up_spiuninitialize(dev); */
return -ENODEV; return -ENODEV;
} }
@ -336,4 +349,3 @@ void arch_tcuninitialize(void)
} }
#endif /* CONFIG_INPUT_ADS7843E */ #endif /* CONFIG_INPUT_ADS7843E */

View File

@ -132,6 +132,7 @@
* Pins are configured as floating because there are pullups on the module. * Pins are configured as floating because there are pullups on the module.
*/ */
#define GPIO_TC_PEN (GPIO_INPUT | GPIO_FLOAT | GPIO_PORT2 | GPIO_PIN15)
#define GPIO_TC_PENIRQ (GPIO_INTBOTH | GPIO_FLOAT | GPIO_PORT2 | GPIO_PIN15) #define GPIO_TC_PENIRQ (GPIO_INTBOTH | GPIO_FLOAT | GPIO_PORT2 | GPIO_PIN15)
#define GPIO_TC_BUSY (GPIO_INPUT | GPIO_FLOAT | GPIO_PORT2 | GPIO_PIN14) #define GPIO_TC_BUSY (GPIO_INPUT | GPIO_FLOAT | GPIO_PORT2 | GPIO_PIN14)
#define GPIO_TC_CS (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT1 | GPIO_PIN8) #define GPIO_TC_CS (GPIO_OUTPUT | GPIO_VALUE_ONE | GPIO_PORT1 | GPIO_PIN8)