cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f4 sdio ACMD22 write block check

felipe2
Associate III
Posted on November 20, 2014 at 12:53

Hi,

I'm working on a datalogging device which needs to stream data into an SD card. I need the data to be intact, that is, no missing blocks and at the moment the way I'm doing this is by reading back from the SD card the block sent and comparing it with the original block. Unfortunately this is very unefficient and causes me issues when I try to speed things up (recording at higher sampling rate). To try and overcome this I'm trying to use the ACMD 22 command which should return the number of sectors written correctly, however it is not working as it should. Below are the functions that I'm using to achieve this:

uint32_t SD_BlockWritten(uint8_t num_blocks)
{
uint32_t blocks=0;
SD_Error errorstatus = SD_OK;
/*!< 
To
improve performance */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) (RCA << 16);
SDIO_CmdInitStructure.SDIO_CmdIndex
= 
SD_CMD_APP_CMD
;
SDIO_CmdInitStructure.SDIO_Response
= 
SDIO_Response_Short
;
SDIO_CmdInitStructure.SDIO_Wait
= 
SDIO_Wait_No
;
SDIO_CmdInitStructure.SDIO_CPSM
= 
SDIO_CPSM_Enable
;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus
= 
CmdResp1Error
(SD_CMD_APP_CMD);
/*!< Send ACMD22 GET BLOCK ERRORS */
SDIO_CmdInitStructure.SDIO_Argument
= 
0x0
;
SDIO_CmdInitStructure.SDIO_CmdIndex
= 
SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS
;
SDIO_CmdInitStructure.SDIO_Response
= 
SDIO_Response_Short
;
SDIO_CmdInitStructure.SDIO_Wait
= 
SDIO_Wait_No
;
SDIO_CmdInitStructure.SDIO_CPSM
= 
SDIO_CPSM_Enable
;
SDIO_SendCommand(&SDIO_CmdInitStructure);
blocks
= 
BlockWrittenError
(SD_CMD_SD_APP_SEND_NUM_WRITE_BLOCKS);
/*if(blocks!=num_blocks)
{
while(1);
}*/
return(0);
}
uint32_t BlockWrittenError(uint8_t cmd)
{
SD_Error 
errorstatus
= 
SD_OK
;
uint32_t status;
uint32_t response_r1;
status
= 
SDIO
->STA;
while (!(status & (SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT)))
{
status = SDIO->STA;
}
if (status & SDIO_FLAG_CTIMEOUT)
{
errorstatus = SD_CMD_RSP_TIMEOUT;
SDIO_ClearFlag(SDIO_FLAG_CTIMEOUT);
return(errorstatus);
}
else if (status & SDIO_FLAG_CCRCFAIL)
{
errorstatus = SD_CMD_CRC_FAIL;
SDIO_ClearFlag(SDIO_FLAG_CCRCFAIL);
return(errorstatus);
}
/*!< Check response received is of desired command */
if (SDIO_GetCommandResponse() != cmd)
{
errorstatus = SD_ILLEGAL_CMD;
return(errorstatus);
}
/*!< Clear all the static flags */
SDIO_ClearFlag(SDIO_STATIC_FLAGS);
/*!< We have received response, retrieve it for analysis */
response_r1 = SDIO_GetResponse(SDIO_RESP1);
return(response_r1);
}

I have tried calling these functions right before stop_transfer command is sent AND also right after. no difference. I have also tried calling these functions after card is in free_state, that is, is ready for new data transfer. This also didn't work. I checked that I'm reading the right register for the response but no luck also. The way I have tested this was by sending blocks with different sizes (4,8,16,32 sectors) to see if the value of the response would change accordingly, needles to say that it didn't happen. Looking at the SD card specifications I can't find any special conditions or commands needed prior to ACMD22 command. Has anyone implemented this type of check and got it working properly? Am I missing something really trivial or is this an issue with the MCU or SD card? Any help/advice/opinion is most welcomed.
1 REPLY 1
gfuehrer
Associate II

What you (probably not the OP, since that was 2014) are missing, which also didn't click for me right away, is that ACMD22 gives an R1 response (available in SDIO_RESP1), not one that gives a 32bit count of blocks (there is no such kind of response). So your function BlockWrittenError() is returning (either one of your error codes or) the card status. Furthermore, and this was the reason I was googling around for how to use ACMD22, it moves the state of the card from 'tran' into 'data' and begins sending a 4byte block of data on the data lines that you need to capture in the same way that one does with CMD6 (or ACMD13, but only 32 bits instead of 512). I presume that all 32 bits arrive high to low like any non-usual (8-bit width) sequence.