Skip to main content
alex_embedded
Associate III
November 15, 2018
Solved

SD cards and SPI rabbit hole help!

  • November 15, 2018
  • 7 replies
  • 1438 views

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

This topic has been closed for replies.
Best answer by Tesla DeLorean

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;
}

7 replies

alex_embedded
Associate III
November 15, 2018

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/

Tesla DeLorean
Tesla DeLoreanBest answer
Guru
November 15, 2018

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
alex_embedded
Associate III
November 15, 2018

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

Tesla DeLorean
Guru
November 15, 2018

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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
alex_embedded
Associate III
November 16, 2018

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"?

Tesla DeLorean
Guru
November 16, 2018

Newer version of the same peripheral

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