Bare-Metal Ada on the ESP32-S3 A step-by-step guide to running Ada on the ESP32-S3 with no ESP-IDF, no FreeRTOS, and no Python.

Step 28 of 56

SD cards: two hosts, one API shape

The universal SPI transport and the native SD bus — different speeds, different profile requirements, and the same 512-byte logical block interface.

Two routes to the same card

SD_SPISDMMC
Bus The SPI master, 4 lines The real SD bus: clock, bidirectional command line, 1 or 4 data lines
Data path Through SPI (and its GDMA) PIO/FIFO — the CPU pushes each 512-byte block through the controller's FIFO
Speed Lower Faster; how you reach an SDHC/SDXC card at speed
Profile embedded / full only (uses the SPI Session's finalization) every profile, light-tasking included

That last row is the surprise, and it falls out of the implementation: because SDMMC moves data in PIO with no GDMA and no descriptors, it needs no finalization — a library-level protected object serialises the single shared controller. So the faster host is also the one available on the lean runtime.

The shared API shape

type Block         is array (0 .. 511) of Interfaces.Unsigned_8;
type Block_Address is new Interfaces.Unsigned_32;

Both are addressed in 512-byte logical blocks (LBA), always. SDHC and SDXC cards use block addressing while older SDSC cards use byte addressing; that difference is resolved inside the driver, so it never reaches your code. Both also initialise the card at ≤400 kHz as the SD specification requires, then switch to Data_Clock_Hz — which is precisely what SPI's Set_Clock mid-hold exists for.

Why SD-over-SPI needs a GPIO chip select

The chip select is driven as a plain GPIO, not the SPI peripheral's hardware CS. The SD protocol needs CS held asserted across a whole command / response / data sequence, and the peripheral's own CS pulses per transfer — which the protocol cannot use. This is the concrete case behind the CS_Pin option on SPI's Acquire.

SD_SPI layers the SD "SPI mode" command protocol on top of the task-safe SPI master: CMD0, CMD8, CMD58, ACMD41, CMD17, CMD24 and CRC7. Every operation takes the SPI host's session for the whole transaction, so concurrent callers serialise.

type Card_Kind is (Unknown, SD_V1, SD_V2_SC, SD_V2_HC);

SDMMC has two slots (Slot1, Slot2), one card each, and a selectable Bus_Width of Width_1 or Width_4. Its lines route through the GPIO matrix, so any free pins will do.

Both drivers are marked in the repository's testing table as compiles, no-card smoke test only. They are the ones to verify against a real card before relying on them — see step 11.