diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2015-01-08 06:23:42 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2015-01-08 06:23:42 -0600 |
commit | 3cfb3001c68d449f0b59586bca112bf5a2e226fa (patch) | |
tree | 6b44391374480c4fd0210992945de74f35b85e64 /nuttx/arch/arm/src | |
parent | 982650a1b30076732fee025a63ec151fc0f3dcb1 (diff) | |
download | nuttx-3cfb3001c68d449f0b59586bca112bf5a2e226fa.tar.gz nuttx-3cfb3001c68d449f0b59586bca112bf5a2e226fa.tar.bz2 nuttx-3cfb3001c68d449f0b59586bca112bf5a2e226fa.zip |
MMCSD SDIO: Add support for a new SDWAIT_WRCOMPLETE condition. The previous logic used a busy-wait loop to pool the card R1 start to determine when the card was ready for the next transfer. That busy-wait can be quite long -- hundreds of milliseconds. And alternative is to look the the SD D0 pin which will change state when the card is no longer busy.
This logic implements a change the avoids the busy-wait poll by reconfiguring the SD D0 pin as a GPIO interrupt, then waiting for the card to becom ready without taking up CPU cycles.
This change is conditioned on CONFIG_MMCSD_SDIOWATI_WRCOMPLETE and is currenlty only implemented for the STM32 SDIO driver.
From David Sidrane
Diffstat (limited to 'nuttx/arch/arm/src')
-rwxr-xr-x[-rw-r--r--] | nuttx/arch/arm/src/stm32/stm32_sdio.c | 108 |
1 files changed, 93 insertions, 15 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c index 4cdfe69eb..8d44f8e9b 100644..100755 --- a/nuttx/arch/arm/src/stm32/stm32_sdio.c +++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c @@ -400,6 +400,9 @@ static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupeven /* Interrupt Handling *******************************************************/ static int stm32_interrupt(int irq, void *context); +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE +static int stm32_rdyinterrupt(int irq, void *context); +#endif /* SDIO interface methods ***************************************************/ @@ -619,12 +622,39 @@ static void stm32_configwaitints(struct stm32_dev_s *priv, uint32_t waitmask, sdio_eventset_t wkupevent) { irqstate_t flags; +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + int pinset; +#endif /* Save all of the data and set the new interrupt mask in one, atomic * operation. */ - flags = irqsave(); + +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE + if ((waitmask & SDIOWAIT_WRCOMPLETE) != 0) + { + /* Do not use this in STM32_SDIO_MASK register */ + + waitmask &= !SDIOWAIT_WRCOMPLETE; + + pinset = GPIO_SDIO_D0 & (GPIO_PORT_MASK|GPIO_PIN_MASK); + pinset |= (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI); + + /* Arm the SDIO_D Ready and install Isr */ + + stm32_gpiosetevent(pinset, true, false, false, stm32_rdyinterrupt); + } + + /* Disarm SDIO_D ready */ + + if ((wkupevent & SDIOWAIT_WRCOMPLETE) != 0) + { + stm32_gpiosetevent(GPIO_SDIO_D0, false, false, false , NULL); + stm32_configgpio(GPIO_SDIO_D0); + } +#endif + priv->waitevents = waitevents; priv->wkupevent = wkupevent; priv->waitmask = waitmask; @@ -1235,10 +1265,33 @@ static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupeven } /**************************************************************************** - * Interrrupt Handling + * Interrupt Handling ****************************************************************************/ /**************************************************************************** + * Name: stm32_rdyinterrupt + * + * Description: + * SDIO ready interrupt handler + * + * Input Parameters: + * dev - An instance of the SDIO device interface + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE +static int stm32_rdyinterrupt(int irq, void *context) +{ + struct stm32_dev_s *priv = &g_sdiodev; + stm32_endwait(priv, SDIOWAIT_WRCOMPLETE); + return OK; +} +#endif + +/**************************************************************************** * Name: stm32_interrupt * * Description: @@ -2236,25 +2289,35 @@ static void stm32_waitenable(FAR struct sdio_dev_s *dev, * interrupts. */ - waitmask = 0; - if ((eventset & SDIOWAIT_CMDDONE) != 0) +#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE) + if ((eventset & SDIOWAIT_WRCOMPLETE) != 0) { - waitmask |= SDIO_CMDDONE_MASK; + waitmask = SDIOWAIT_WRCOMPLETE; } - - if ((eventset & SDIOWAIT_RESPONSEDONE) != 0) + else +#endif { - waitmask |= SDIO_RESPDONE_MASK; - } + waitmask = 0; + if ((eventset & SDIOWAIT_CMDDONE) != 0) + { + waitmask |= SDIO_CMDDONE_MASK; + } - if ((eventset & SDIOWAIT_TRANSFERDONE) != 0) - { - waitmask |= SDIO_XFRDONE_MASK; - } + if ((eventset & SDIOWAIT_RESPONSEDONE) != 0) + { + waitmask |= SDIO_RESPDONE_MASK; + } - /* Enable event-related interrupts */ + if ((eventset & SDIOWAIT_TRANSFERDONE) != 0) + { + waitmask |= SDIO_XFRDONE_MASK; + } + + /* Enable event-related interrupts */ + + putreg32(SDIO_WAITALL_ICR, STM32_SDIO_ICR); + } - putreg32(SDIO_WAITALL_ICR, STM32_SDIO_ICR); stm32_configwaitints(priv, waitmask, eventset, 0); } @@ -2324,6 +2387,21 @@ static sdio_eventset_t stm32_eventwait(FAR struct sdio_dev_s *dev, } } +#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE) + if ((priv->waitevents & SDIOWAIT_WRCOMPLETE) != 0) + { + /* Atomically read pin to see if ready (true) and determine if ISR fired + * If Pin is ready and if ISR did NOT fire end the wait here + */ + + if (stm32_gpioread(GPIO_SDIO_D0) && + (priv->wkupevent & SDIOWAIT_WRCOMPLETE) == 0) + { + stm32_endwait(priv, SDIOWAIT_WRCOMPLETE); + } + } +#endif + /* Loop until the event (or the timeout occurs). Race conditions are avoided * by calling stm32_waitenable prior to triggering the logic that will cause * the wait to terminate. Under certain race conditions, the waited-for |