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
This commit is contained in:
Gregory Nutt
2015-01-08 06:23:42 -06:00
parent 5c68f0dd34
commit 1ace391fcf
Regular → Executable
+93 -15
View File
@@ -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,9 +1265,32 @@ 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
*
@@ -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