cancel
Showing results for 
Search instead for 
Did you mean: 

SD cards and SPI rabbit hole help!

alex_embedded
Associate III

Hi All,

After a day or so of researching I feel more overwhelmed than anything regarding using SPI to communicate with SD cards!!

There is so much STUFF out there regarding embedded c and SD cards - I don't even know where to begin! I've gone down sooo many rabbit holes trying to find even a basic starting point!

I am having trouble finding documented guides on how to communicate with an SD card using the HAL libraries - nothing simple anyway, I see a lot on SDIO coms and the fatfs library but I am restricted to SPI.

I am using the SD card as flash storage so I don't need to use the FATfs library, I plan on using it basically like SRAM for storing variables etc.

One question I have to begin with I suppose, do I NEED a file system to communicate with an SD card?

My initial plan was to use the HAL library SD card functions listed in the HAL drivers datasheet ( Section 43 in UM1940) but I'm struggling to find papers on how to go about this - especially regarding the commands needed for reading and writing to an SD card.

Any help would be greatly appreciated!!

P.S. Please no more of this -> http://www.lmgtfy.com/?q=SD+Card+SPI+STM32

I came here asking for help not to be given a lesson on how to use google!!! I see this so much on this forum and its super annoying

1 ACCEPTED SOLUTION

Accepted Solutions

It is a block storage device so will act like a hard drive or NAND, not like SRAM.

You don't need to use FATFS, but you will need to read/write block(s). Review the DISKIO.C for the FATFS implementations to see how that happens.

For SPI the best example to start with might be the ADAFRUIT one.

Interfaces via read/write block functions

STM32Cube_FW_F2_V1.7.0\Drivers\BSP\Adafruit_Shield\stm32_adafruit_sd.c

/**
  * @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)

STM32Cube_FW_F2_V1.7.0\Middlewares\Third_Party\FatFs\src\drivers\sd_diskio.c

/**
  * @brief  Reads Sector(s)
  * @param  lun : not used
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
  DRESULT res = RES_ERROR;
  uint32_t timeout = 100000;
 
  if(BSP_SD_ReadBlocks((uint32_t*)buff,
                       (uint32_t) (sector),
                       count, SD_DATATIMEOUT) == MSD_OK)
  {
    while(BSP_SD_GetCardState()!= MSD_OK)
    {
      if (timeout-- == 0)
      {
        return RES_ERROR;
      }
    }
    res = RES_OK;
  }
 
  return res;
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

7 REPLIES 7
alex_embedded
Associate III

I've found this to be super helpful but I would love to read more into this topic before attempting to do it.

https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/

It is a block storage device so will act like a hard drive or NAND, not like SRAM.

You don't need to use FATFS, but you will need to read/write block(s). Review the DISKIO.C for the FATFS implementations to see how that happens.

For SPI the best example to start with might be the ADAFRUIT one.

Interfaces via read/write block functions

STM32Cube_FW_F2_V1.7.0\Drivers\BSP\Adafruit_Shield\stm32_adafruit_sd.c

/**
  * @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)

STM32Cube_FW_F2_V1.7.0\Middlewares\Third_Party\FatFs\src\drivers\sd_diskio.c

/**
  * @brief  Reads Sector(s)
  * @param  lun : not used
  * @param  *buff: Data buffer to store read data
  * @param  sector: Sector address (LBA)
  * @param  count: Number of sectors to read (1..128)
  * @retval DRESULT: Operation result
  */
DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
{
  DRESULT res = RES_ERROR;
  uint32_t timeout = 100000;
 
  if(BSP_SD_ReadBlocks((uint32_t*)buff,
                       (uint32_t) (sector),
                       count, SD_DATATIMEOUT) == MSD_OK)
  {
    while(BSP_SD_GetCardState()!= MSD_OK)
    {
      if (timeout-- == 0)
      {
        return RES_ERROR;
      }
    }
    res = RES_OK;
  }
 
  return res;
}

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thanks @Community member​ !

I found out while doing more research the same as what you said regarding storage blocks - I was mistaken in understanding the way it is accessed.

I will look into these files and see how they're supposed to be used.

Do you have any pointers and tips regarding SPI, like the "Do's and Don'ts" when using SPI?

I'm only really familiar with serial and I've never needed to use anything else. I don't want to have bad habits right from the start when implementing SPI

Don't use SPI, use the SDIO/SDMMC interface, it is significantly faster and manages DMA better.

Read/write multiple sectors/blocks, doing it one at a time has a significant command/response overhead.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Yea I've been organizing a way to be able to get access to the SDIO interface on the project - I have a proposal to put forward which I can only wait and see if it accepted. The more research I've done into this its apparent that SDIO is the better way to go.

Thanks again!!

alex_embedded
Associate III

After more research, one option I have is to switch from the stm32f2 series and move to the stm32f7 series. These offer more UART/USART ports so there are no clashes regarding my project (this is another story).

This question I have now however:

When creating a project for an STM32F2 series, I can see the option for enabling SDIO for SD cards.

On the STM32F7 series, this option is called "SDMMC1". This is for SD MMC cards, but does this still work with the standard cards? When enabling SDMMC1 with SD 1 bit mode it enables the same number of pins with virtually the same name.

I.e.

On STM32F2, SDIO in SD 1 bit mode enables the following:

SDIO_D0

SDIO_CMD

SDIO_CK

On STM32F7, SDMMC1 in SD 1 bit mode enables the following:

SDMMC1_D0

SDMMC1_CMD

SDMMC1_CK

Are these two completely different protocols or can they be "mixed and matched"?

Newer version of the same peripheral

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..