STM32F427 SDIO Block Write with DMA not responding properly



I don't use libraries.
My SD card interface is set up with an SDIO clock of 16.67 mhz using the 4-bit interface.
My block write (SD command 24) works properly if I poll the data into the FIFO. The problem with that is the timing to push data into the FIFO and not get an TX underrun is very tight. An RTOS time tic can cause enough of a delay produce the error. I had to disable all interrupts before pushing the 512 bytes (128 32-bit writes) into the FIFO to remove all possibilities of the fault.
So -- use DMA.
The STM32F427 manual outlines the requirements for Master Write with DMA which I believe I have implemented properly.
The DMA fires at the end of the transaction but the SDIO does not reply with an SDIO_STA_DBCKEND flag and my timeout process aborts the write.
I'm using DMA2 Stream 6 channel 4.
Upon receiving the DMA Stream interrupt with flag DMA_HISR_TCIF6 set I wait (poll) for the SDIO_STA_DBCKEND which never arrives.
Here is were I'm puzzled because the following are register values for the Stream and SDIO
- Stream6 NDTR is 0xff82 which suggests to me it pushed more data than the 128 transactions it was instructed to transfer (I'm of the belief that DMA_HISR_TCIF6 fires when NDTR == 0) -- see picture below
- SDIO DCOUNT is 0x000c - which says it expects 12 more bytes. It's loaded based on the Block size of 512 and then counts down as data is transferred.-- see picture below
- SDIO FIFOCNT is zero so all data has been transferred. -- see picture below
My code is posted below. If someone can help identify what I'm doing incorrectly I would appreciate it. I also have pictures below of the DMA and SDIO register states and a trace of the SDIO CLK, CMD and Dat0 lines for the write process listed. The trace shows 2 commands. the first is a SDIO CMD 13 for status followed by SDIO CMD 24.
Thanks for and help/comments.
byte SDHC_WriteBlock(dword *pData, word Count)
{
dword r = 0;
volatile dword S;
dword TimeOut = H_GetTime() + (20000 / portTICK_PERIOD_MS);
dword TM;
DMA2->HIFCR = DMA_HIFCR_CFEIF6 | DMA_HIFCR_CDMEIF6 | DMA_HIFCR_CTEIF6 | DMA_HIFCR_CHTIF6 | DMA_HIFCR_CTCIF6;
DMA2_Stream6->CR = DMA_SxCR_TEIE | DMA_SxCR_TCIE | (1 << DMA_SxCR_DIR_Pos) | DMA_SxCR_MINC | DMA_SxCR_PFCTRL | (2 << DMA_SxCR_PSIZE_Pos) | (2 << DMA_SxCR_MSIZE_Pos) | (2 << DMA_SxCR_PL_Pos) | (1 << DMA_SxCR_MBURST_Pos) | (1 << DMA_SxCR_PBURST_Pos) | (4 << DMA_SxCR_CHSEL_Pos);
DMA2_Stream6->M0AR = (dword)pData;
DMA2_Stream6->PAR = (dword)&SDIO->FIFO;
DMA2_Stream6->NDTR = Count; // count is 128 ... 128 32bit words = 512 bytes
SDIO->DCTRL |= SDIO_DCTRL_DMAEN; // enable dma
SDHC_DMA_Complete_or_Error = 0; // flag from DMA IRQ
DMA2_Stream6->CR |= DMA_SxCR_EN; // start transfer
while(SDHC_DMA_Complete_or_Error == 0)
{
TM = H_GetTime();
if(TM >= TimeOut) //SD_Timeout_Event)
{
DMA2_Stream6->CR = 0; // kill dma
r = SDHC_Error_Timed_Out;
goto bye;
}
}
if(SDHC_DMA_Complete_or_Error == 2)
{
r = SDHC_DMA_Write_Error;
goto bye;
}
if(SDHC_DMA_SD_Status & (SDIO_STA_TXUNDERR | SDIO_STA_STBITERR | SDIO_STA_DCRCFAIL))
{
r = SDHC_Error_Write_Block_A;
goto bye;
}
bye:
// get here when DMA transaction complete if r == 0. If r then error
while(r == 0)
{
S = SDIO->STA;
if(S & (SDIO_STA_STBITERR | SDIO_STA_DCRCFAIL))
{
r = SDHC_Error_Write_Block_B;
break;
}
if(S & SDIO_STA_DBCKEND) //data end and valid checksum
{
r = 0;
break;
}
TM = H_GetTime();
if(TM >= TimeOut) //SD_Timeout_Event)
{
r = SDHC_Error_Timed_Out; // !!!!!!!!!!!!!!!!!!!!!!!! this is were I currently exit with error
break;
}
}
return r;
}