cancel
Showing results for 
Search instead for 
Did you mean: 

Bug in stm32_adafruit_sd.c (SPI SD CARD)

Posted on February 02, 2018 at 21:28

\STM32Cube_FW_L4_V1.0\Drivers\BSP\Adafruit_Shield\stm32_adafruit_sd.c

Issue with ReadBlocks/WriteBlocks on SDHC cards, offset advances in BlockSize!!! ReadAddr should increment by 1. The current routine delivers junk for multi-sector reads/writes. Please, please, test these things, wasted a lot of time chasing this to ground.

Original code

...

response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, (ReadAddr + offset) * (flag_SDHC == 1 ? 1: BlockSize), 0xFF, SD_ANSWER_R1_EXPECTED);

...

/* Set next read address*/

offset += BlockSize;

Suggested fix (I'd probably refactor completely)

...

response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, ReadAddr * ((flag_SDHC == 1) ? 1: BlockSize), 0xFF, SD_ANSWER_R1_EXPECTED);

...

/* Set next read address*/

ReadAddr++; // Block Address

offset += BlockSize;

Original code formatted

/**
 * @brief Reads block(s) from a specified address in the SD card, in polling mode.
 * @param pData: Pointer to the buffer that will contain the data to transmit
 * @param ReadAddr: Address from where data is to be read. The address is counted
 * in blocks of 512bytes
 * @param NumOfBlocks: Number of SD blocks to read
 * @param Timeout: This parameter is used for compatibility with BSP implementation
 * @retval SD status
 */
uint8_t BSP_SD_ReadBlocks(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks, uint32_t Timeout)
{
 uint32_t offset = 0;
 uint8_t retr = BSP_SD_ERROR;
 uint8_t *ptr = NULL;
 SD_CmdAnswer_typedef response;
 uint16_t BlockSize = 512;
 /* Send CMD16 (SD_CMD_SET_BLOCKLEN) to set the size of the block and
 Check if the SD acknowledged the set block length command: R1 response (0x00: no errors) */
 response = SD_SendCmd(SD_CMD_SET_BLOCKLEN, BlockSize, 0xFF, SD_ANSWER_R1_EXPECTED);
 SD_IO_CSState(1);
 SD_IO_WriteByte(SD_DUMMY_BYTE);
 if ( response.r1 != SD_R1_NO_ERROR)
 {
 goto error;
 }
 ptr = malloc(sizeof(uint8_t)*BlockSize);
 if( ptr == NULL )
 {
 goto error;
 }
 memset(ptr, SD_DUMMY_BYTE, sizeof(uint8_t)*BlockSize);
 /* Data transfer */
 while (NumOfBlocks--)
 {
 /* Send CMD17 (SD_CMD_READ_SINGLE_BLOCK) to read one block */
 /* Check if the SD acknowledged the read block command: R1 response (0x00: no errors) */
 response = SD_SendCmd(SD_CMD_READ_SINGLE_BLOCK, (ReadAddr + offset) * (flag_SDHC == 1 ? 1: BlockSize), 0xFF, SD_ANSWER_R1_EXPECTED);
 if ( response.r1 != SD_R1_NO_ERROR)
 {
 goto error;
 }
 /* Now look for the data token to signify the start of the data */
 if (SD_WaitData(SD_TOKEN_START_DATA_SINGLE_BLOCK_READ) == BSP_SD_OK)
 {
 /* Read the SD block data : read NumByteToRead data */
 SD_IO_WriteReadData(ptr, (uint8_t*)pData + offset, BlockSize);
 /* Set next read address*/
 offset += BlockSize;
 /* get CRC bytes (not really needed by us, but required by SD) */
 SD_IO_WriteByte(SD_DUMMY_BYTE);
 SD_IO_WriteByte(SD_DUMMY_BYTE);
 }
 else
 {
 goto error;
 }
 /* End the command data read cycle */
 SD_IO_CSState(1);
 SD_IO_WriteByte(SD_DUMMY_BYTE);
 }
 retr = BSP_SD_OK;
error :
 /* Send dummy byte: 8 Clock pulses of delay */
 SD_IO_CSState(1);
 SD_IO_WriteByte(SD_DUMMY_BYTE);
 if(ptr != NULL) free(ptr);
 /* Return the reponse */
 return retr;
}
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Test fixture

0690X00000609aWQAQ.png
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
5 REPLIES 5
Posted on February 04, 2018 at 16:57

Large f_read()/f_write() used against the FatFs library will propagate to the DISKIO layer as reads/writes where count>1

Failure can be observed in a file CRC routine if  >=1024 byte blocks are read vs 512 byte blocks. Different CRC values will be observed in 512, 1024, 4096-bytes/block, etc, passes of the file.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Posted on February 07, 2018 at 03:13

Here is some test code to exercise FatFs. Pick a large file, and have a large enough heap to permit allocations for large block reads.

//******************************************************************************
// CRC File Intergrity Check - sourcer32@gmail.com
//******************************************************************************
uint32_t CRC32(uint32_t Crc, uint32_t Size, uint8_t *Buffer)
{
 while(Size--)
 {
 static const uint32_t CrcTable[] = { // Nibble table for 0xEDB88320 polynomial
 0x00000000,0x1DB71064,0x3B6E20C8,0x26D930AC,0x76DC4190,0x6B6B51F4,0x4DB26158,0x5005713C,
 0xEDB88320,0xF00F9344,0xD6D6A3E8,0xCB61B38C,0x9B64C2B0,0x86D3D2D4,0xA00AE278,0xBDBDF21C };
 Crc = Crc ^ (uint32_t)*Buffer++; // Apply byte
 Crc = (Crc >> 4) ^ CrcTable[Crc & 0x0F]; // Two rounds of 4-bits
 Crc = (Crc >> 4) ^ CrcTable[Crc & 0x0F];
 }
 return(Crc);
}
//******************************************************************************
uint32_t CrcFile(char *Filename, uint32_t BufferSize)
{
 FRESULT res;
 FIL fil;
 uint32_t Crc = 0xFFFFFFFF;
 uint32_t Align = 32;
 uint8_t *p = malloc(BufferSize + Align);
 while((p == NULL) && (BufferSize > Align))
 {
 BufferSize >>= 1;
 p = malloc(BufferSize + Align);
 }
 if (p)
 { // Align IO Buffer
 uint8_t *Buffer = (uint8_t *)(((uint32_t)p + (Align - 1)) & ~(Align - 1));
 res = f_open(&fil, Filename, FA_READ);
 if (res != FR_OK)
 printf('res = %d f_open %s
', res, Filename);
 if (res == FR_OK)
 {
 uint32_t Size = f_size(&fil);
 while(Size) // Process until all consumed
 {
 UINT BytesRead;
 res = f_read(&fil, Buffer, BufferSize, &BytesRead);
 if (res != FR_OK)
 {
 printf('res = %d f_read %s
', res, Filename);
 break;
 }
 Crc = CRC32(Crc, BytesRead, Buffer);
 Size -= BytesRead;
 }
 res = f_close(&fil);
 if (res != FR_OK)
 printf('res = %d f_close %s
', res, Filename);
 }
 printf('CRC32 %08X PKZIP %08X %s
', Crc, ~Crc, Filename);
 free(p);
 }
 return(~Crc);
}
//******************************************************************************
void TestFile(char *Filename)
{
 uint32_t Crc;
 Crc = CrcFile(Filename, 512);
 if (CrcFile(FileName, 1024) != Crc)
 puts('!!FAIL!!');
 if (CrcFile(FileName, 4096) != Crc)
 puts('!!FAIL!!');
 if (CrcFile(FileName, 8192) != Crc)
 puts('!!FAIL!!');
}
//******************************************************************************
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Amel NASRI
ST Employee
Posted on March 15, 2018 at 12:18

Hi Clive,

The issue you highlighted was reported internally and confirmed. The fix will be available in coming versions of the STM32CubeL4 package.

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Amel NASRI
ST Employee

Hi @Community member​ ,

Please note that a fix is applied to BSP_SD_ReadBlocks and BSP_SD_WriteBlocks in order to support SDHC cards. Updated stm32_adafruit_sd.c is available in the last version of STM32CubeL4 package (1.12.0) .

-Amel

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

There is a problem with sd_spi implementation in stm3210c-eval-bsp/stm3210c_eval_sd.c The fix related to thread is applied only on Drivers/BSP/Adafruit_Shield/stm32_adafruit_sd.c not on evalboard BSP. Please fix this.