summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2015-01-08 06:23:42 -0600
committerGregory Nutt <gnutt@nuttx.org>2015-01-08 06:23:42 -0600
commit3cfb3001c68d449f0b59586bca112bf5a2e226fa (patch)
tree6b44391374480c4fd0210992945de74f35b85e64
parent982650a1b30076732fee025a63ec151fc0f3dcb1 (diff)
downloadnuttx-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
-rwxr-xr-x[-rw-r--r--]nuttx/arch/arm/src/stm32/stm32_sdio.c108
-rwxr-xr-x[-rw-r--r--]nuttx/drivers/mmcsd/Kconfig17
-rwxr-xr-x[-rw-r--r--]nuttx/drivers/mmcsd/mmcsd_sdio.c15
-rwxr-xr-x[-rw-r--r--]nuttx/include/nuttx/sdio.h22
4 files changed, 146 insertions, 16 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
diff --git a/nuttx/drivers/mmcsd/Kconfig b/nuttx/drivers/mmcsd/Kconfig
index 4949cee1f..f78232ebb 100644..100755
--- a/nuttx/drivers/mmcsd/Kconfig
+++ b/nuttx/drivers/mmcsd/Kconfig
@@ -38,6 +38,23 @@ config MMCSD_HAVECARDDETECT
SDIO driver card detection is
100% accurate
+config MMCSD_SDIOWAIT_WRCOMPLETE
+ bool "Use SDIO_D Busy to detect Write Complete"
+ default n
+ ---help---
+ SDIO driver will use SDIO_D Busy signalling to detect Write Complete.
+ This option when selected, will enable the MMCSD driver to use the
+ underlying (stm32_sdio only) drivers implementation of the SD specs
+ SDIO_D Busy signalling to detect Write Complete. This will avoid
+ potentially very long (600Ms+) busy waiting in the MMCSD driver.
+
+ To implement SDIO_D Busy signalling, the underlying driver must
+ be capable of switching the GPIO_SDIO_D0 to be a rising edge sensitive
+ interrupt pin. It must then, condition that pin to detect the rising edge
+ on receipt of SDWAIT_WRCOMPLETE in the SDIO_WAITENABLE call and
+ return it back to regular SDIO mode, when either the ISR fires or pin is
+ found to be high in the SDIO_EVENTWAIT call.
+
config MMCSD_SPI
bool "MMC/SD SPI transfer support"
default y
diff --git a/nuttx/drivers/mmcsd/mmcsd_sdio.c b/nuttx/drivers/mmcsd/mmcsd_sdio.c
index e208a8aca..3c1fd9bdc 100644..100755
--- a/nuttx/drivers/mmcsd/mmcsd_sdio.c
+++ b/nuttx/drivers/mmcsd/mmcsd_sdio.c
@@ -1150,6 +1150,15 @@ static int mmcsd_transferready(FAR struct mmcsd_state_s *priv)
* the TRANSFER state when the card completes the WRITE operation.
*/
+#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE)
+ ret = mmcsd_eventwait(priv, SDIOWAIT_TIMEOUT|SDIOWAIT_ERROR,
+ MMCSD_BLOCK_WDATADELAY);
+ if (ret != OK)
+ {
+ fdbg("ERROR: mmcsd_eventwait for transfer ready failed: %d\n", ret);
+ }
+#endif
+
starttime = clock_systimer();
do
{
@@ -1721,6 +1730,12 @@ static ssize_t mmcsd_writesingle(FAR struct mmcsd_state_s *priv,
return ret;
}
+#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE)
+ /* Arm the write complete detection with timeout */
+
+ SDIO_WAITENABLE(priv->dev, SDIOWAIT_WRCOMPLETE|SDIOWAIT_TIMEOUT);
+#endif
+
/* On success, return the number of blocks written */
return 1;
diff --git a/nuttx/include/nuttx/sdio.h b/nuttx/include/nuttx/sdio.h
index 5bd80329c..258fe14c8 100644..100755
--- a/nuttx/include/nuttx/sdio.h
+++ b/nuttx/include/nuttx/sdio.h
@@ -63,7 +63,27 @@
#define SDIOWAIT_TIMEOUT (1 << 3) /* Bit 3: Timeout */
#define SDIOWAIT_ERROR (1 << 4) /* Bit 4: Some other error occurred */
-#define SDIOWAIT_ALLEVENTS 0x1f
+/* SDIOWAIT_WRCOMPLETE (optional) : SDIO driver will use SDIO_D Busy
+ * signalling to detect Write Complete. This option when selected, will
+ * enable the MMCSD driver to use the underlying (stm32_sdio only) drivers
+ * implementation of the SD specs SDIO_D Busy signalling to detect Write
+ * Complete. This will avoid potentially very long (600Ms+) busy waiting
+ * in the MMCSD driver.
+ *
+ * To implement SDIO_D Busy signalling, the underlying driver must be
+ * capable of switching the GPIO_SDIO_D0 to be a rising edge sensitive
+ * interrupt pin. It must then, condition that pin to detect the rising
+ * edge on receipt of SDWAIT_WRCOMPLETE in the SDIO_WAITENABLE call and
+ * return it back to regular SDIO mode, when either the ISR fires or pin
+ * is found to be high in the SDIO_EVENTWAIT call.
+ */
+
+#if defined(CONFIG_MMCSD_SDIOWAIT_WRCOMPLETE)
+# define SDIOWAIT_WRCOMPLETE (1 << 5) /* Bit 5: Hardware Write Completion */
+# define SDIOWAIT_ALLEVENTS 0x3f
+#else
+# define SDIOWAIT_ALLEVENTS 0x1f
+#endif
/* Media events are used for enable/disable registered event callbacks */