With these changes the SDMMC card for LPC4330 is now working properly BUT it needs more testing, especially with different cards etc. This code should be applicable to all members of the lpc43xx family.

In addition to the problems that were previously identified there were a few other bits and pieces outstanding;

  * Timing was dependent on CPU speed rather than absolute time
  * End of transfer handling was a bit mixed up
  * It's possible for data to still be in the FIFO (i.e. not have reached
    the card) when a next write is requested, so we need to wait for that to
    complete
  * Interrupt Status could be carried over from one transfer episode to the
    next, corrupting progress
  * Multi-descriptor DMA writing simply wasn't implemented, but there were no
    indications ... it just failed silently
This commit is contained in:
Dave Marples 2018-10-24 18:06:28 -06:00 committed by Gregory Nutt
parent c28cbdb22f
commit d1c01e1135
2 changed files with 45 additions and 42 deletions

View File

@ -124,10 +124,10 @@
# error "Driver requires CONFIG_SDIO_BLOCKSETUP to be set"
#endif
/* Timing */
/* Timing : 100mS short timeout, 2 seconds for long one */
#define SDCARD_CMDTIMEOUT (10000)
#define SDCARD_LONGTIMEOUT (0x7fffffff)
#define SDCARD_CMDTIMEOUT MSEC2TICK(100)
#define SDCARD_LONGTIMEOUT MSEC2TICK(2000)
/* Type of Card Bus Size */
@ -621,28 +621,36 @@ static inline void lpc43_sdcard_clock(bool enable)
* arg - The argument to use with the command.
*
* Returned Value:
* None
* Returns zero on success. One will be returned on a timeout.
*
****************************************************************************/
static int lpc43_ciu_sendcmd(uint32_t cmd, uint32_t arg)
{
volatile int32_t tmo = SDCARD_CMDTIMEOUT;
clock_t watchtime;
mcinfo("cmd=%04lx arg=%04lx\n", (unsigned long)cmd, (unsigned long)arg);
DEBUGASSERT((lpc43_getreg(LPC43_SDMMC_CMD) & SDMMC_CMD_STARTCMD) == 0);
/* Set command arg reg */
lpc43_putreg(arg, LPC43_SDMMC_CMDARG);
lpc43_putreg(SDMMC_CMD_STARTCMD | cmd, LPC43_SDMMC_CMD);
/* Poll until command is accepted by the CIU */
/* Poll until command is accepted by the CIU, or we timeout */
while (--tmo > 0 && (lpc43_getreg(LPC43_SDMMC_CMD) & SDMMC_CMD_STARTCMD) != 0)
watchtime = clock_systimer();
while ((lpc43_getreg(LPC43_SDMMC_CMD) & SDMMC_CMD_STARTCMD) != 0)
{
if (watchtime - clock_systimer() > SDCARD_CMDTIMEOUT)
{
mcerr("TMO Timed out (%08X)\n",lpc43_getreg(LPC43_SDMMC_CMD));
return 1;
}
}
return (tmo < 1) ? 1 : 0;
return 0;
}
/****************************************************************************
@ -1031,7 +1039,6 @@ static int lpc43_sdmmc_interrupt(int irq, void *context, FAR void *arg)
/* Transfer data to the TX FIFO */
mcinfo("Write FIFO\n");
DEBUGASSERT(priv->wrdir);
for (status = lpc43_getreg(LPC43_SDMMC_STATUS);
@ -1043,20 +1050,6 @@ static int lpc43_sdmmc_interrupt(int irq, void *context, FAR void *arg)
priv->buffer++;
priv->remaining -= 4;
}
/* If all of the data has been transferred to the FIFO, then
* disable further TX data requests and wait for the data end
* event.
*/
if (priv->remaining <= 0)
{
uint32_t intmask = lpc43_getreg(LPC43_SDMMC_INTMASK);
intmask &= ~SDMMC_INT_TXDR;
lpc43_putreg(intmask, LPC43_SDMMC_INTMASK);
priv->xfrmask &= ~SDMMC_INT_TXDR;
}
}
else if ((pending & SDMMC_INT_RXDR) != 0)
{
@ -1064,7 +1057,6 @@ static int lpc43_sdmmc_interrupt(int irq, void *context, FAR void *arg)
/* Transfer data from the RX FIFO */
mcinfo("Read from FIFO\n");
DEBUGASSERT(!priv->wrdir);
for (status = lpc43_getreg(LPC43_SDMMC_STATUS);
@ -1076,18 +1068,6 @@ static int lpc43_sdmmc_interrupt(int irq, void *context, FAR void *arg)
priv->buffer++;
priv->remaining -= 4;
}
/* If all of the data has been transferred to the FIFO, then
* just force DTO event processing (the DTO interrupt is not
* actually even enabled in this use case).
*/
if (priv->remaining <= 0)
{
/* Force the DTO event */
pending |= SDMMC_INT_DTO;
}
}
/* Check for transfer errors */
@ -1348,7 +1328,7 @@ static void lpc43_reset(FAR struct sdio_dev_s *dev)
/* Define MAX Timeout */
lpc43_putreg(SDCARD_LONGTIMEOUT, LPC43_SDMMC_TMOUT);
lpc43_putreg(0x7fffffff, LPC43_SDMMC_TMOUT);
/* Disable clock to CIU (needs latch) */
@ -1763,6 +1743,10 @@ static int lpc43_recvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
lpc43_putreg(regval, LPC43_SDMMC_CTRL);
#endif
/* Flush ints before we start */
lpc43_putreg(SDCARD_TRANSFER_ALL, LPC43_SDMMC_RINTSTS);
/* Configure the transfer interrupts */
lpc43_config_xfrints(priv, SDCARD_RECV_MASK);
@ -1827,6 +1811,10 @@ static int lpc43_sendsetup(FAR struct sdio_dev_s *dev, FAR const uint8_t *buffer
lpc43_putreg(regval, LPC43_SDMMC_CTRL);
#endif
/* Flush ints before we start */
lpc43_putreg(SDCARD_TRANSFER_ALL, LPC43_SDMMC_RINTSTS);
/* Configure the transfer interrupts */
lpc43_config_xfrints(priv, SDCARD_SEND_MASK);
@ -1894,6 +1882,7 @@ static int lpc43_cancel(FAR struct sdio_dev_s *dev)
static int lpc43_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
{
volatile int32_t timeout;
clock_t watchtime;
uint32_t events;
mcinfo("cmd=%04x\n", cmd);
@ -1933,13 +1922,15 @@ static int lpc43_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
/* Then wait for the response (or timeout or error) */
watchtime = clock_systimer();
while ((lpc43_getreg(LPC43_SDMMC_RINTSTS) & events) != events)
{
if (--timeout <= 0)
if (clock_systimer() - watchtime > timeout)
{
mcerr("ERROR: Timeout cmd: %04x events: %04x STA: %08x RINTSTS: %08x\n",
cmd, events, lpc43_getreg(LPC43_SDMMC_STATUS),
lpc43_getreg(LPC43_SDMMC_RINTSTS));
return -ETIMEDOUT;
}
else if ((lpc43_getreg(LPC43_SDMMC_RINTSTS) & SDCARD_INT_RESPERR) != 0)
@ -1947,6 +1938,7 @@ static int lpc43_waitresponse(FAR struct sdio_dev_s *dev, uint32_t cmd)
mcerr("ERROR: SDMMC failure cmd: %04x events: %04x STA: %08x RINTSTS: %08x\n",
cmd, events, lpc43_getreg(LPC43_SDMMC_STATUS),
lpc43_getreg(LPC43_SDMMC_RINTSTS));
return -EIO;
}
}
@ -2545,7 +2537,11 @@ static int lpc43_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
lpc43_putreg((uint32_t)&g_sdmmc_dmadd[0], LPC43_SDMMC_DBADDR);
/* Enable internal DMA, burst size of 4, fixed burst */
/* Flush ints before we start */
lpc43_putreg(SDCARD_TRANSFER_ALL, LPC43_SDMMC_RINTSTS);
/* Enable internal DMA, burst size of 4, fixed burst */
regval = lpc43_getreg(LPC43_SDMMC_CTRL);
regval |= SDMMC_CTRL_INTDMA;
@ -2691,7 +2687,11 @@ static int lpc43_dmasendsetup(FAR struct sdio_dev_s *dev,
lpc43_putreg((uint32_t) &g_sdmmc_dmadd[0], LPC43_SDMMC_DBADDR);
/* Enable internal DMA, burst size of 4, fixed burst */
/* Flush ints before we start */
lpc43_putreg(SDCARD_TRANSFER_ALL, LPC43_SDMMC_RINTSTS);
/* Enable internal DMA, burst size of 4, fixed burst */
regval = lpc43_getreg(LPC43_SDMMC_CTRL);
regval |= SDMMC_CTRL_INTDMA;

View File

@ -1196,10 +1196,13 @@ static int mmcsd_transferready(FAR struct mmcsd_state_s *priv)
}
/* Check for the programming state. This is not an error. It means
* that the card is still busy from the last (write) transfer.
* that the card is still busy from the last (write) transfer. The
* card can also still be receiving data, for example, if hardware
* receive FIFOs are not yet empty.
*/
else if (!IS_STATE(r1, MMCSD_R1_STATE_PRG))
else if (!IS_STATE(r1, MMCSD_R1_STATE_PRG) &&
!IS_STATE(r1, MMCSD_R1_STATE_RCV))
{
/* Any other state would be an error in this context. There is
* a possibility that the card is not selected. In this case,