cancel
Showing results for 
Search instead for 
Did you mean: 

SDIO Error when use SD NAND chip

Danish1
Lead II

I have been using microSD chips reliably for many years with stm32f4, stm32h7 and stm32l4.

But for one of my products, where space is at a premium, I am trying to use a SD-NAND chip XTSD04G, and I am running into occasional errors where an SDIO R1 command fails with SDMMC_STA gives the error CTIMEOUT

This only happens when I am running my system at maximum capacity (writing at 80kbits/s, with occasional reads interleaved). To reduce loading on the memory-chip, the majority of writes use SD_CMD_WRITE_MULT_BLOCK, writing 8kbytes i.e. 16 sectors of 512 bytes in each hit.

The data-sheet for XTSD04G claims it is up to class 8, so that implies it should support 8MB/s (even if that were 8mbit/s I would be well within that limit). And it claims to support up to 50 MHz clock frequency, so the stm32l4's 48MHz clock should be fine. And for reference, yes I do use it in 4-bit mode.

As I am not a paid-up member of SDIO, I only have access to their simplified specifications.

Is there any guidance for how to recover from CTIMEOUT without having to go through the long process of resetting the memory-card? (At the moment I reset the memory-chip, re-identify it at 1-bit and then switch to 4-bit mode).

My code is

uint32_t SDIO_bulkWriteSector(const uint8_t *buffer, uint32_t sector) {	/* writes a single sector but using CMD25 = WRITE_MULTIPLE_BLOCK */
	unsigned int reply;
	static uint32_t lastBulkSector;	/* this must be 1 less than address to continue with current bulk write if one is active */
	ctl_events_wait(CTL_EVENT_WAIT_ALL_EVENTS_WITH_AUTO_CLEAR, &sdio_es, SDIO_ES_COMMAND, CTL_TIMEOUT_NONE, 0);
	showStatus(eDfsLowCommand, 1);
	if ((sdio_es & SDIO_ES_SD_BULK_WRITING) && (lastBulkSector + 1 != sector)) {
		SDIO_innerEndBulkWriteSector();
	}
	lastBulkSector = sector;
	if (loadedCard.CardType != eSDIO_HIGH_CAPACITY_SD_CARD)
		sector *= 512;
/* Wait till card is ready for data Added */
	if (sdio_es & SDIO_ES_POLL_FOR_READY_DUE) {
		reply = sdio_pollForReady();
		ctl_events_set_clear(&sdio_es, 0, SDIO_ES_POLL_FOR_READY_DUE);
		if (reply) {
			showStatus(eDfsLowCommand, 0);
			ctl_events_set_clear(&sdio_es, SDIO_ES_COMMAND, 0);	 
			return reply;
		}
	}
	if (!(sdio_es & SDIO_ES_SD_BULK_WRITING)) {
		reply = SDIO_R1_Command(SD_CMD_WRITE_MULT_BLOCK, sector);
		if (reply) {
			showStatus(eDfsLowCommand, 0);
			ctl_events_set_clear(&sdio_es, SDIO_ES_COMMAND, 0);	 
			return reply;
		}
	}
/* SDIO_DataConfig */
	SDIO->DTIMER = SD_DATATIMEOUT;	/* very long time */
	SDIO->DLEN = PREFERRED_BLOCK_SIZE;
	peripheral_bitband_write(&DMAm_Streamn(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER)->dmaCR, 0, 0);
	DMAm_Streamn(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER)->dmaCR = 0//(SDIO_DMA_CHANNEL_NUMBER * DMA_SxCR_CHSEL_0)
        /* | double-buffer - not yet */
        | DMA_SxCR_PFCTRL   /* let the SDIO peripheral say when everything is transferred */
        | DMA_SxCR_MBURST_0 | DMA_SxCR_PBURST_0     /* bursts of 4 transfers */
        | (SDIO_DMA_PRIORITY * DMA_SxCR_PL_0)
        | DMA_SxCR_MSIZE_1 | DMA_SxCR_PSIZE_1 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_TCIE | DMA_SxCR_TEIE;
    DMA_SET_CHANNEL(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER, SDIO_DMA_CHANNEL_NUMBER);
	DMAm_Streamn(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER)->dmaNDTR = 512 / 4;
	DMAm_Streamn(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER)->dmaPAR = (unsigned long)&SDIO->FIFO;
	DMAm_Streamn(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER)->dmaM0AR = (unsigned long)buffer;
	peripheral_bitband_write(&DMAm_Streamn(SDIO_DMA_n, SDIO_DMA_STREAM_NUMBER)->dmaCR, 0, 1);DELAY;
	SDIO->DCTRL = SDIO_DCTRL_DTEN | SDIO_DataBlockSize_512b | SDIO_TransferDir_ToCard | SDIO_TransferMode_Block | SDIO_DCTRL_DMAEN | (SDIO->DCTRL & ~0xFFF);
	reply = ctl_events_wait(CTL_EVENT_WAIT_ANY_EVENTS_WITH_AUTO_CLEAR, &sdio_es, SDIO_ES_DMA_INT, CTL_TIMEOUT_DELAY, SDIO_TIMEOUT_DURATION_TICKS);
	if (!reply)	{ /* timeout */
		showStatus(eDfsLowCommand, 0);
		ctl_events_set_clear(&sdio_es, SDIO_ES_COMMAND, 0);	 
		return 1;
	}
	reply = SDIO->STA & (SDIO_STA_TXUNDERR | SDIO_STA_DCRCFAIL | SDIO_STA_DTIMEOUT | SDIO_STA_STBITERR);
	showStatus(eDfsLowCommand, 0);
	ctl_events_set_clear(&sdio_es, SDIO_ES_COMMAND | SDIO_ES_POLL_FOR_READY_DUE | SDIO_ES_SD_BULK_WRITING, 0);	 
	return reply;
}
unsigned SDIO_R1_Command(unsigned int cmdIndex, unsigned int argument) {	/* returns 0 on no error */
	unsigned wait_reply;
//    while (SDIO->STA & (SDIO_STA_CMDACT/* | SDIO_STA_TXACT | SDIO_STA_RXACT*/))
//        { ; }
	SDIO->ICR = SDIO->STA;	/* clear all pending status bits */
	SDIO->ARG = argument;
	SDIO->MASK = SDIO_MASK_CCRCFAILIE | SDIO_MASK_CMDRENDIE | SDIO_MASK_CTIMEOUTIE;
    DELAY;
	SDIO->CMD = cmdIndex
			 | SDIO_Response_Short
			 | 0	/* SDIO_Wait_No */
			 | SDIO_CMD_CPSMEN;	/* SDIO_CPSM_Enable */
    uint32_t sta = 0;
	wait_reply = ctl_events_wait(CTL_EVENT_WAIT_ANY_EVENTS_WITH_AUTO_CLEAR, &sdio_es, SDIO_ES_PERIPHERAL_INT, CTL_TIMEOUT_DELAY, SDIO_TIMEOUT_DURATION_TICKS);
	if (!wait_reply || !((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CCRCFAIL))) {
		logString("R1 fail, STA=");
		logX(sta);
		logString("\n");
		return SDIO->STA | SDIO_R1_COMMAND_STA_FAIL;
	}
	if (SDIO->RESPCMD != cmdIndex) {
		logString("R1 fail RESPCMD=");
		logX(SDIO->RESPCMD);
		logString(" should be ");
		logX(cmdIndex);
		logString("\n");
		return SDIO->RESPCMD | SDIO_R1_COMMAND_BAD_COMMAND;
	}
	if (SDIO->RESP1 & SD_OCR_ERRORBITS) {
		logString("R1 fail errorBits, SDIO->RESP1=");
		logX(SDIO->RESP1);
		logString("\n");
		return (SDIO->RESP1 >> 3) | SDIO_R1_COMMAND_R1_FAIL;
	}
	return 0;
}

And it fails with R1 fail, STA=4. DELAY is __dsb(); followed by 6 NOPs.

Any thoughts or suggestions?

0 REPLIES 0