SD Storage

Provides Storage Management support for SD cards.

This code is ported from the SD Card library.

Currently uses only SPI communication, which offers only a limited interface and is not supported by SDUC cards.

SD Card connections

../../../../_images/mmc.jpg

See https://en.wikipedia.org/wiki/SD_card

MMC pin

SD pin

miniSD pin

microSD pin

Name

I/O

Logic

Description

1

1

1

2

nCS

I

PP

SPI Card Select [CS] (Negative logic)

2

2

2

3

DI

I

PP

SPI Serial Data In [MOSI]

3

3

3

VSS

S

S

Ground

4

4

4

4

VDD

S

S

Power

5

5

5

5

CLK

I

PP

SPI Serial Clock [SCLK]

6

6

6

6

VSS

S

S

Ground

7

7

7

7

DO

O

PP

SPI Serial Data Out [MISO]

8

8

8

NC nIRQ

O

OD

Unused (memory cards) Interrupt (SDIO cards) (negative logic)

9

9

1

NC

Unused

10

NC

Reserved

11

NC

Reserved

Usage

  • Code should be built with ENABLE_STORAGE_SIZE64 =1 unless using a very small card (1 or 2GB):

  • Add required libraries to your project’s component.mk file:

    COMPONENT_DEPENDS := SdStorage FatIFS
    
  • Create and initialise a Card Device instance:

    #include <Storage/SD/Card.h>
    
    // GPIO used for Chip Select (Esp8266)
    #define PIN_CARD_CS 5
    
    // Create the SD card Device and register with the Storage library
    auto card = new Storage::SD::Card("card1", SPI);
    Storage::registerDevice(card);
    
    if(!card->begin(PIN_CARD_CS)) {
        // Handle error here
        return;
    }
    
    // Display some information
    Serial << "CSD" << endl << card->csd << endl;
    Serial << "CID" << endl << card->cid;
    

At this point, the card can be accessed directly using Storage::Device methods. If the card has been formatted then the partitions can be accessed using the standard Storage API. For example:

Storage::Partition part;

// Find the first FAT partition on the card
part = *card->partitions().find(Storage::Partition::SubType::Data::fat);

// Get the first partition (of any type)
part = *card->partitions().begin();

// Iterate through all partitions
for(part: card->partitions()) {
    Serial << part << endl;
}
  • To create a partition table on the card:

    #include <Storage/Disk/GPT.h>
    
    Storage::Disk::GPT::PartitionTable table;
    // Create one partition using 100% of all available space
    table.add("My FAT partition", 0, 100);
    auto err = Storage::Disk::formatDisk(*card, table);
    Serial << "formatDisk: " << err << endl;
    if(!!err) {
        // If formatting fails, the disk will left in an indeterminate state!
        ...
        return;
    }
    
    // Fetch the first (and only) partition
    auto part = card->partitions().begin();
    

Note

To use the entire card as a single partition, it is not necessary to pre-format the disk. Instead, construct a partition spanning the entire disk:

auto part = card->editablePartitions().add("My Partition",
  Storage::Partition::SubType::Data::fat, 0, card->getSize());

This approach is sometimes referred to as an SFD (Single Filing-system Device).

The partition can now be formatted with the required filing system (FAT):

int res = IFS::FAT::formatVolume(part);
Serial << "formatVolume : " << IFS::Error::toString(res) << endl;

Once formatted, the partition can be mounted as usual:

auto fatfs = IFS::createFatFilesystem(part);
if(fatfs != nullptr) {
    if(fatfs->mount() == FS_OK) {
        // OK, access the filing system
        Serial << fatfs->getContent("My file.txt") << endl;
    } else {
        // Mount failed, destroy the objects
        delete fs;
        delete card; // Also de-registers the card with the Storage API
    }
}

API Documentation

namespace SD
class Card : public Storage::Disk::BlockDevice
#include <Card.h>

Public Functions

bool begin(uint8_t chipSelect, uint32_t freq = 0)

Initialise the card.

Parameters:
  • chipSelect

  • freq – SPI frequency in Hz, use 0 for maximum supported frequency

inline virtual String getName() const override

Obtain unique device name.

inline virtual uint32_t getId() const

Obtain device ID.

Return values:

uint32_t – typically flash chip ID

inline virtual Type getType() const

Obtain device type.

inline virtual size_t getBlockSize() const override

Obtain smallest allocation unit for erase operations.

struct CID
#include <CID.h>

Public Members

uint8_t mid

Manufacturer ID.

char oid[2]

OEM / Application ID.

char pnm[5]

Product name.

uint8_t prv

Product revision.

uint32_t psn

Product serial number.

uint16_t mdt

Manufacturing date.

uint8_t not_used

Always 1.

uint8_t crc

7-bit checksum

struct CSD
#include <CSD.h>

Subclassed by Storage::SD::CSD1, Storage::SD::CSD2, Storage::SD::CSD3

struct CSD1 : public Storage::SD::CSD
#include <CSD.h>
struct CSD2 : public Storage::SD::CSD
#include <CSD.h>
struct CSD3 : public Storage::SD::CSD
#include <CSD.h>

References

SoC support

  • esp32

  • esp32c2

  • esp32c3

  • esp32s2

  • esp32s3

  • esp8266

  • host

  • rp2040