AnsweredAssumed Answered

Bug in stm32_adafruit_sd.c (SPI SD CARD)

Question asked by Clive One on Feb 2, 2018
Latest reply on Mar 15, 2018 by Amel N

\STM32Cube_FW_L4_V1.11.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

Outcomes