Example of using SD card on an ESP32

Hi All…

Here is an example of one way to use the FAT file system on an SD card on an ESP32 device. This example uses an excellent library contributed by Nliviu who is active here. I like this library because, rather than providing functions to manipulate files directly, it allows you to mount the card as a file system and then use standard c/c++ functions/methods to manipulate files.

To run this example, I suggest you use mos to create an empty C application. then, add this line to the libs section of the created mos.yml file:

- origin: https://github.com/nliviu/sdlib

Replace the main.c file with this code:

/*
  This example demonstrates how to read and write an SD card on an ESP32,
  using this library contributed by nliviu:

  https://github.com/nliviu/sdlib


   This example is adapted for ESP32 from this example:
   
   https://github.com/cesanta/esp-idf/blob/master/examples/storage/sd_card/main/sd_card_example_main.c
*/

#include "mgos.h"

#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/sdmmc_host.h"
#include "driver/sdspi_host.h"
#include "sdmmc_cmd.h"


#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK  18
#define PIN_NUM_CS   2


void playWithSd()
{
  LOG(LL_INFO, ("%s", "**************************************"));
  LOG(LL_INFO, ("%s", "**************************************"));

  LOG(LL_INFO, ("%s", "Playing with SD!!!!!"));

  sdmmc_host_t host = SDSPI_HOST_DEFAULT();
  sdspi_slot_config_t slot_config = SDSPI_SLOT_CONFIG_DEFAULT();
  slot_config.gpio_miso = PIN_NUM_MISO;
  slot_config.gpio_mosi = PIN_NUM_MOSI;
  slot_config.gpio_sck  = PIN_NUM_CLK;
  slot_config.gpio_cs   = PIN_NUM_CS;

  // Options for mounting the filesystem.
  // If format_if_mount_failed is set to true, SD card will be partitioned and
  // formatted in case when mounting fails.
  esp_vfs_fat_sdmmc_mount_config_t mount_config = {
    .format_if_mount_failed = false,
    .max_files = 5,
    .allocation_unit_size = 16 * 1024
  };


  // Use settings defined above to initialize SD card and mount FAT filesystem.
  // Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
  // Please check its source code and implement error recovery when developing
  // production applications.
  sdmmc_card_t* card;
  esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);

  if (ret != ESP_OK)
  {
    if (ret == ESP_FAIL)
    {
      LOG(LL_INFO, ("%s", "Failed to mount filesystem.  If you want the card to be formatted, set format_if_mount_failed = true."));
    }
    else
    {
      LOG(LL_INFO, ("Failed to initialize the card (%s). ", esp_err_to_name(ret)));
    }
    return;
  }

  // Card has been initialized, print its properties
  sdmmc_card_print_info(stdout, card);


  // Use POSIX and C standard library functions to work with files.
  // First create a file.
  LOG(LL_INFO, ("%s", "Opening file"));
  FILE* f = fopen("/sdcard/hello.txt", "w");
  if (f == NULL)
  {
    LOG(LL_INFO, ("%s","Failed to open file for writing"));
    return;
  }
  fprintf(f, "Hello %s!\n", card->cid.name);
  fclose(f);
  LOG(LL_INFO, ("%s","File written"));


  // Check if destination file exists before renaming
  struct stat st;
  if (stat("/sdcard/foo.txt", &st) == 0)
  {
    // Delete it if it exists
    unlink("/sdcard/foo.txt");
  }

  // Rename original file
  LOG(LL_INFO, ("%s","Renaming file"));
  if (rename("/sdcard/hello.txt", "/sdcard/foo.txt") != 0)
  {
    LOG(LL_INFO, ("%s","Rename failed"));
    return;
  }

  // Open renamed file for reading
  LOG(LL_INFO, ("%s","Reading file"));
  f = fopen("/sdcard/foo.txt", "r");
  if (f == NULL)
  {
    LOG(LL_INFO, ("%s","Failed to open file for reading"));
    return;
  }
  char line[64];
  fgets(line, sizeof(line), f);
  fclose(f);
  // strip newline
  char* pos = strchr(line, '\n');
  if (pos)
  {
    *pos = '\0';
  }
  LOG(LL_INFO, ("Read from file: %s", line));

  // All done, unmount partition and disable SDMMC or SPI peripheral
  esp_vfs_fat_sdmmc_unmount();
  LOG(LL_INFO, ("%s", "Card unmounted"));

  LOG(LL_INFO, ("%s", "**************************************"));
  LOG(LL_INFO, ("%s", "**************************************"));
}


enum mgos_app_init_result mgos_app_init(void)
{
  LOG(LL_INFO, ("%s", "We are in the Entry point!!!!!"));

  playWithSd();

  return MGOS_APP_INIT_SUCCESS;
}

The library is based on the same example code you provide here :slight_smile:

I’m sorry for reviving an old thread and asking a possibly stupid question, but I am trying to use an sd card and can’t figure out how. I am using an Olimex esp32 POE board (ESP32-POE - Open Source Hardware Board) which does not support spi mode. I need to use 1-bit sd mode. Is this possible using the sdlib? If so, How am I supposed to set up the pins. The configurations for the lib seem to be only for spi.