Skip to main content
Graduate II
February 2, 2018
Question

Bug in stm32_adafruit_sd.c (SPI SD CARD)

  • February 2, 2018
  • 4 replies
  • 2057 views
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
    This topic has been closed for replies.

    4 replies

    Graduate II
    February 4, 2018
    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.

    Graduate II
    February 7, 2018
    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!!');
    }
    //******************************************************************************
    �?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

    Visitor II
    June 4, 2024

    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.

    Technical Moderator
    March 15, 2018
    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

    Technical Moderator
    July 26, 2018

    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