Skip to content

MarcoMiglio/stm32_sdCard

Repository files navigation

Github repository containing informations about the driver for STM32 MCUs interfacing SD cards using FATFs.

The following code is intended for power optimization of the micro SD module. The SD can be power consuming, therefore it is continually switched on and off using an external PNP-BJT driven using a GPIO pin. SPI pins are configured using push-pull configuration + internal pull-ups to avoid parasitic current when the MCU enters a low power state.

This code has been modified to make this tutorial work.

Setup procedure:

  • Include FATFs in "Middleware and Software Packs"

  • Setup SPI peripheral with prescaler 256. This is needed to initialize the SD card in SPI mode (clock must be within 100 kHz - 400 kHz during the initialization procedure). SPI speed can then be increased up to 10 MHz (refer to subsequent guidelines). Other configs: 8 bit, full-duplex mode.

  • Set internal pull-up resistors on MOSI, MISO and SCK lines to avoid parasitic currents when the MCU enters a low power state.

  • Set CS pin in push-pull mode, with GPIO output level HIGH. This ensures that the Micro SD card is immediately under master control.

  • Following the above tutorial link, download this .c file and add it to your FATFS/Target directory. Do the same for the .h file.

  • Follow the tutorial instructions summirized here:

    1. include "user_diskio_spi.h" in "user_diskio.c".
    2. Add "USER_SPI_functioname" (defined in the "user_diskio_spi" files) to each "USER_functioname" defined in the "user_diskio.c" file. As an example:
         DSTATUS USER_initialize (
             BYTE pdrv           /* Physical drive nmuber to identify the drive */
         )
         {
           /* USER CODE BEGIN INIT */
           return USER_SPI_initialize(pdrv); //ADD THIS LINE
           /* USER CODE END INIT */
         }
      
    3. Adjust the SCLK prescaler in the "user_spi_diskio.c" file.
         //(Note that the _256 is used as a mask to clear the prescalar bits as it provides binary 111 in the correct position)
         #define FCLK_SLOW() { MODIFY_REG(SD_SPI_HANDLE.Instance->CR1, SPI_BAUDRATEPRESCALER_256, SPI_BAUDRATEPRESCALER_256); }	/* Set SCLK = slow, approx 280 KBits/s*/
         #define FCLK_FAST() { MODIFY_REG(SD_SPI_HANDLE.Instance->CR1, SPI_BAUDRATEPRESCALER_256, SPI_BAUDRATEPRESCALER_16); }	/* Set SCLK = fast, approx 4.5 MBits/s */
      
    4. In your "main.h" file create the SPI handle that will be used to drive the SD card.
         /* USER CODE BEGIN Private defines */
         #define SD_SPI_HANDLE hspi2 // Add your actual SPI handle here!
         /* USER CODE END Private defines */
      
  • These modifications must be applied to the original code to make it work:

    1. modify "fatfs.c /.h" files by adding the unlink driver capability, necessary to reinitialize the SD after power down. Add this code to the "fatfs.c" file:
         /* USER CODE BEGIN Application */
         void MX_FATFS_close_drv(void) {
           retUSER = FATFS_UnLinkDriver(USERPath);
         }
         /* USER CODE END Application */
      
      And this one to the "fatfs.h" file:
         /* USER CODE BEGIN Prototypes */
         void MX_FATFS_close_drv(void);
         /* USER CODE END Prototypes */
      
      This allows you to unlink the driver after powering off the SD card by using these code lines:
         // Close the file
         f_close(&fil);
      
         //We're done, so de-mount the drive
         f_mount(NULL, "", 0);
      
         // Detach existing driver:
         MX_FATFS_close_drv();
      
         //re-attach new driver for next initialization
         MX_FATFS_Init();
      
    2. Modify "user_diskio_spi.c" file as follows. The "send_cmd" function has to be updated in this way:
         /* Select the card and wait for ready except to stop multiple block read */
       	if (cmd != CMD12) {
       		despiselect();
       
       		// if initializing SPI, then skip wait_ready statement
       		if (cmd == CMD0) {
       		  CS_LOW();   /* Set CS# low */
       		  xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
       		}
       		else {
       		  if (!spiselect()) return 0xFF;
       		}
       	}
      
      This is necessary to skip the "wait_ready" statement while sening CMD0 for module initialization. Indeed in native mode the MISO line is not driven by the slave, therefore no response is received until the SD card is setup to accept SPI commands! In the original code the wait ready statement inside the "spiselect()" function was always terminating with a timeout, resulting in a fmount error while mounting the SD card driver.
    3. Modify "USER_SPI_initialize" function in this way:
         // command to go idle in SPI mode
       	uint8_t CMD0_stat;
       	SPI_Timer_On(1000);
         while ((CMD0_stat = send_cmd(CMD0, 0)) != 1 && SPI_Timer_Status() == 1){
       
         }
      
      This allows to repeat CMD0 sequence until the SD card is actually in idle state! Indeed i observed that something in between 2-3 cycles are needed before the correct response is actually received. (Took inspiration from arduino libraries in doing this).

Useful links:

About

Code for driving SD card memories using stm32 and SPI peripheral

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors