Difference between revisions of "STM32 SD card with FatFs"

From Stm32World Wiki
Jump to navigation Jump to search
 
(16 intermediate revisions by the same user not shown)
Line 1: Line 1:
 
[[Category:STM32]][[Category:STM32 Development]][[Category:STM32 HAL]][[Category:C]]{{metadesc|STM32 SD Card Interface}}
 
[[Category:STM32]][[Category:STM32 Development]][[Category:STM32 HAL]][[Category:C]]{{metadesc|STM32 SD Card Interface}}
 
[[File:sd1.jpg|thumb|200px|Micro-SD Adaptor with jumper leads soldered on]]
 
[[File:sd1.jpg|thumb|200px|Micro-SD Adaptor with jumper leads soldered on]]
In this article we will be interfacing a SD-card using [[STM32]].
+
In this article we will be interfacing a [[SD card]] using [[STM32]].
  
 
For this purpose we have modified a SD to Micro-SD adaptor by soldering 9 jumper leads on it (see photo on the right).
 
For this purpose we have modified a SD to Micro-SD adaptor by soldering 9 jumper leads on it (see photo on the right).
 +
 +
We'll be using two different [[SD card]]s throughout these exercises:
 +
 +
{|
 +
|-
 +
| [[File:SD card.jpg|540px]]
 +
| [[File:16 GB SD.jpg|300px]]
 +
|}
 +
 +
In general (not to shuffle cards around) I will be using the 64 GB card with [[#SDIO|SDIO]] and the 16 GB one with [[#SPI|SPI]].
 +
 
{{clear}}
 
{{clear}}
== SD-Card Pinout ==
+
== SD Card Pinout ==
  
The pinout of a SD-card and a MicroSD-card are as follows:
+
The pinout of a [[SD card]] and a MicroSD-card are as follows:
  
 
[[File:sd-card-pinout.png|500px]]
 
[[File:sd-card-pinout.png|500px]]
Line 16: Line 27:
 
# [[#SPI|SPI]]
 
# [[#SPI|SPI]]
  
== DIY SD-card Adaptor ==
+
== DIY SD card Adaptor ==
  
A quick way to hook up a SD-card to a [[STM32]] is to use one of those SD to Micro-SD adaptors that come with most Micro-SD's when you buy them.  I made one looking like this:
+
A quick way to hook up a [[SD card]] to a [[STM32]] is to use one of those SD to Micro-SD adaptors that come with most Micro-SD's when you buy them.  I made one looking like this:
  
 
[[File:Sd4.jpg|350px]]
 
[[File:Sd4.jpg|350px]]
Line 78: Line 89:
  
 
As per the SD-card specification in both the case of SPI and SDIO, all signals except the clock should be pulled up.  Our DIY adaptor does not include pull-up resistors, so we will have to rely on the internal ones, which are really quite weak but as long as the leads are not too long it should work ok.
 
As per the SD-card specification in both the case of SPI and SDIO, all signals except the clock should be pulled up.  Our DIY adaptor does not include pull-up resistors, so we will have to rely on the internal ones, which are really quite weak but as long as the leads are not too long it should work ok.
 
== SPI ==
 
 
NOTICE!  While it is supported by most, some SD-cards do not support SPI access.  If this fails for you, try with another card.  Older cards are more likely to work.
 
  
 
== SDIO ==
 
== SDIO ==
Line 98: Line 105:
  
 
[[File:STM32 v. SDIO SD.jpg|800px]]
 
[[File:STM32 v. SDIO SD.jpg|800px]]
 +
 +
The [[SDIO]] can be configured using [[STM32CubeMX]] like this:
 +
 +
<div class="res-img">
 +
[[File:STM32CubeMX SDIO Config for SD card.png|1000px]]
 +
</div>
 +
 +
Using the [[SD card]] with [[SDIO]] with code generated by [[STM32CubeMX]] is relatively straight forward.  A small tweak is required though and this tweak is described in the following sections.
  
 
=== 1-bit ===
 
=== 1-bit ===
 +
 +
<pre>
 +
/**
 +
* @brief SDIO Initialization Function
 +
* @param None
 +
* @retval None
 +
*/
 +
static void MX_SDIO_SD_Init(void)
 +
{
 +
 +
    /* USER CODE BEGIN SDIO_Init 0 */
 +
 +
    /* USER CODE END SDIO_Init 0 */
 +
 +
    /* USER CODE BEGIN SDIO_Init 1 */
 +
 +
    /* USER CODE END SDIO_Init 1 */
 +
    hsd.Instance = SDIO;
 +
    hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
 +
    hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
 +
    hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
 +
    hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
 +
    hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
 +
    hsd.Init.ClockDiv = 0;
 +
    /* USER CODE BEGIN SDIO_Init 2 */
 +
 +
    // Optional init sdio
 +
    if (HAL_SD_Init(&hsd) != HAL_OK) {
 +
        Error_Handler();
 +
    }
 +
 +
    /* USER CODE END SDIO_Init 2 */
 +
 +
}
 +
</pre>
  
 
=== 4-bit ===
 
=== 4-bit ===
 +
 +
For some reason that I am not entirely clear about, SD cards '''must''' be initialized with 1-bit mode only and then switched to 4-bit.  The easiest way to do this is to configure it as 4-bit in [[STM32CubeMX]] and then modify the 'MX_SDIO_SD_Init' function like this:
 +
 +
<pre>
 +
/**
 +
* @brief SDIO Initialization Function
 +
* @param None
 +
* @retval None
 +
*/
 +
static void MX_SDIO_SD_Init(void)
 +
{
 +
 +
    /* USER CODE BEGIN SDIO_Init 0 */
 +
 +
    /* USER CODE END SDIO_Init 0 */
 +
 +
    /* USER CODE BEGIN SDIO_Init 1 */
 +
 +
    /* USER CODE END SDIO_Init 1 */
 +
    hsd.Instance = SDIO;
 +
    hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
 +
    hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
 +
    hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
 +
    hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
 +
    hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
 +
    hsd.Init.ClockDiv = 0;
 +
    /* USER CODE BEGIN SDIO_Init 2 */
 +
 +
    // First init with 1B bus - SD card will not initialize with 4 bits
 +
    hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
 +
    if (HAL_SD_Init(&hsd) != HAL_OK) {
 +
        Error_Handler();
 +
    }
 +
 +
    // Now we can switch to 4 bit mode
 +
    if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) {
 +
        Error_Handler();
 +
    }
 +
 +
    /* USER CODE END SDIO_Init 2 */
 +
 +
}
 +
</pre>
 +
 +
== SPI ==
 +
 +
NOTICE!  While it is supported by most, some SD-cards do not support SPI access.  If this fails for you, try with another card.  Older cards are more likely to work.
  
 
== Gallery ==
 
== Gallery ==

Latest revision as of 03:04, 28 November 2024

Micro-SD Adaptor with jumper leads soldered on

In this article we will be interfacing a SD card using STM32.

For this purpose we have modified a SD to Micro-SD adaptor by soldering 9 jumper leads on it (see photo on the right).

We'll be using two different SD cards throughout these exercises:

SD card.jpg 16 GB SD.jpg

In general (not to shuffle cards around) I will be using the 64 GB card with SDIO and the 16 GB one with SPI.

SD Card Pinout

The pinout of a SD card and a MicroSD-card are as follows:

Sd-card-pinout.png

It is important to notice that all SD-cards can be interfaced in two different ways:

  1. SDIO
  2. SPI

DIY SD card Adaptor

A quick way to hook up a SD card to a STM32 is to use one of those SD to Micro-SD adaptors that come with most Micro-SD's when you buy them. I made one looking like this:

Sd4.jpg

Combining that with the pinout from the previous section, we can make the following table:

Pin Color SDIO SPI
1 White CD/Dat3 CS
2 Grey CMD DI
3 Purple VSS1 VSS1
4 Blue VDD VDD
5 Green CLK SCLK
6 Yellow VSS2 VSS2
7 Orange DAT0 DO
8 Red DAT1
9 Black DAT2

As per the SD-card specification in both the case of SPI and SDIO, all signals except the clock should be pulled up. Our DIY adaptor does not include pull-up resistors, so we will have to rely on the internal ones, which are really quite weak but as long as the leads are not too long it should work ok.

SDIO

Some MCUs - for example the STM32F405 - includes a SDIO peripheral which can be used to drive a SD-card directly. Schematics will look like this:

SDIO MCU.png SDIO SD.png

Notice the pull-up resistors on all lines except the CLK.

On a PCB that could look like this:

STM32 v. SDIO SD.jpg

The SDIO can be configured using STM32CubeMX like this:

STM32CubeMX SDIO Config for SD card.png

Using the SD card with SDIO with code generated by STM32CubeMX is relatively straight forward. A small tweak is required though and this tweak is described in the following sections.

1-bit

/**
 * @brief SDIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_SDIO_SD_Init(void)
{

    /* USER CODE BEGIN SDIO_Init 0 */

    /* USER CODE END SDIO_Init 0 */

    /* USER CODE BEGIN SDIO_Init 1 */

    /* USER CODE END SDIO_Init 1 */
    hsd.Instance = SDIO;
    hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
    hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
    hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
    hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
    hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
    hsd.Init.ClockDiv = 0;
    /* USER CODE BEGIN SDIO_Init 2 */

    // Optional init sdio
    if (HAL_SD_Init(&hsd) != HAL_OK) {
        Error_Handler();
    }

    /* USER CODE END SDIO_Init 2 */

}

4-bit

For some reason that I am not entirely clear about, SD cards must be initialized with 1-bit mode only and then switched to 4-bit. The easiest way to do this is to configure it as 4-bit in STM32CubeMX and then modify the 'MX_SDIO_SD_Init' function like this:

/**
 * @brief SDIO Initialization Function
 * @param None
 * @retval None
 */
static void MX_SDIO_SD_Init(void)
{

    /* USER CODE BEGIN SDIO_Init 0 */

    /* USER CODE END SDIO_Init 0 */

    /* USER CODE BEGIN SDIO_Init 1 */

    /* USER CODE END SDIO_Init 1 */
    hsd.Instance = SDIO;
    hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
    hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_ENABLE;
    hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
    hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
    hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
    hsd.Init.ClockDiv = 0;
    /* USER CODE BEGIN SDIO_Init 2 */

    // First init with 1B bus - SD card will not initialize with 4 bits
    hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
    if (HAL_SD_Init(&hsd) != HAL_OK) {
        Error_Handler();
    }

    // Now we can switch to 4 bit mode
    if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) {
        Error_Handler();
    }

    /* USER CODE END SDIO_Init 2 */

}

SPI

NOTICE! While it is supported by most, some SD-cards do not support SPI access. If this fails for you, try with another card. Older cards are more likely to work.

Gallery

The following quick "hack" was soldered together and it works flawlessly.

Miscellaneous Links