# microSD card

The card slot on a Kode Dot: 4-bit SDIO straight to the P4, a power switch that lives on the C5, and the code to mount a card and write a file.

## What it is

A microSD slot on the edge of the board, for files: recordings, logs, images,
anything bigger than the flash should hold. The card talks to the P4 over
SDIO with four data lines, the fast interface, not the SPI fallback, and
mounts as a FAT filesystem you read and write with ordinary `fopen` calls.

One thing about it is unlike any other board you have used: the card's power
is switched by the C5, not by the P4. Until the C5 closes that switch the
slot is unpowered, and a card in it is invisible. Kode's C5 firmware closes
it at boot.

## How it is connected

```mermaid
flowchart LR
  p4["ESP32-P4"] -- "SDIO 4-bit, slot 0" --> sd["microSD"]
  c5["ESP32-C5"] -. "IO26 SD_PWR, active low" .-> sw["P-MOSFET"] -. "SD1_VDD" .-> sd
  sd -. "card detect" .-> c5
```

*Data to the P4 over SDIO; power from a switch the C5 controls*

The slot is on the P4's SD/MMC slot 0, `GPIO39` to `GPIO44`, with 47 kΩ
pull-ups to the card's rail. That rail comes through a P-channel MOSFET whose
gate is `IO26` on the C5, pulled high so the card is off until the C5 drives
it low. Card detect is `IO25` on the C5. The P4's own SDIO pins live in an IO
bank fed by its internal LDO channel 4, which the SD driver has to raise to
3.3 V.

## Specifications

| Thing | Value |
| --- | --- |
| Interface | SDIO 4-bit, SD/MMC slot 0 on the P4, no bridge chip |
| Pins | `SD1_D0` to `SD1_D3` on `GPIO39` to `GPIO42`, `SD1_CLK` `GPIO43`, `SD1_CMD` `GPIO44` |
| Card power | C5 `IO26`, active low. Kode's C5 firmware drives it low at boot; from the P4, `esp_hosted_cp_gpio_set_level(26, 0)` |
| Card detect | C5 `IO25` |
| IO bank | P4 LDO channel 4 at 3.3 V, raised through `sd_pwr_ctrl_by_on_chip_ldo` in the mount |
| Filesystem | FAT. exFAT is off in the default build, so a card over 32 GB needs reformatting to FAT32 or exFAT enabled |
| Speed | About 12 MB/s writing and 15 MB/s reading at 4 bits on one card, on a board |
| Kode driver | None yet. **TBD**: a mount call in the `kode` component |
| Validated | `Kode-Dot-Val/06-STORAGE`: mount, write and read on a board |

## Gotchas

> **WARNING**
>
> **The card will not mount.** Nine times in ten it was never powered: the C5
> is running something other than Kode's firmware, or nothing drove `IO26`
> low. The error names the card or the bus and sends you into the SD driver,
> which is the one place the cause is not. A Wi-Fi scan proves the C5 first.

> **WARNING**
>
> **A card mounts, reports four bits, and every write fails.** Some cards lie
> about their bus width. Use a card from a brand you know; the fallback is a
> 1-bit mount, about three times slower, and nothing drops to it on its own.

> **NOTE**
>
> **A new card over 32 GB does not mount either.** It ships as exFAT, which
> the default build does not read. Format it FAT32, which caps a file at
> 4 GiB, or turn exFAT on in your build.

## Apps that use it

On the marketplace, apps that put this part to work. Install one from
`start/first-app` and see it before you write a line.

- https://apps.kode.diy/app/4b6755c2-2b53-459c-a824-2d17c8d26806
- https://apps.kode.diy/app/3dc95a93-1b79-4bd2-bded-67b4d616bd9a
- https://apps.kode.diy/app/328951aa-5eb7-426c-8b29-1e3b0ac57c49

## Example code

Power the card through the C5, mount it, write a line to a file and read it
back. The log shows the line you wrote.

```c
/*
 * sd_roundtrip.c - 2026-09-18 - from Kode with love
 *
 * Mounts the Kode Dot's microSD card, writes one line to a file and reads it
 * back. Asks the C5 to power the slot first, brings the SD/MMC host up with
 * the IO bank at 3.3 V, mounts FAT at /sdcard, and logs the line it wrote.
 * The C5 has to be running Kode's firmware for the power request to land.
 */
#include <stdio.h>
#include "driver/sdmmc_host.h"
#include "esp_hosted.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "sd_pwr_ctrl_by_on_chip_ldo.h"

/* Power from the C5, host with the LDO, mount, write, read. */
void app_main(void)
{
    ESP_ERROR_CHECK(esp_hosted_init());
    ESP_ERROR_CHECK(esp_hosted_cp_gpio_set_level(26, 0));   /* card power on, active low */

    sdmmc_host_t host = SDMMC_HOST_DEFAULT();
    sd_pwr_ctrl_ldo_config_t ldo = { .ldo_chan_id = 4 };     /* the SDIO pins' IO bank */
    ESP_ERROR_CHECK(sd_pwr_ctrl_new_on_chip_ldo(&ldo, &host.pwr_ctrl_handle));
    sdmmc_slot_config_t slot = SDMMC_SLOT_CONFIG_DEFAULT();
    slot.width = 4;
    esp_vfs_fat_sdmmc_mount_config_t mount = { .max_files = 4 };
    sdmmc_card_t *card;
    ESP_ERROR_CHECK(esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot, &mount, &card));

    FILE *f = fopen("/sdcard/hello.txt", "w");
    fprintf(f, "hello from the Kode Dot\n");
    fclose(f);

    char line[64];
    f = fopen("/sdcard/hello.txt", "r");
    fgets(line, sizeof line, f);
    fclose(f);
    ESP_LOGI("sd", "read back: %s", line);
}
```

The calls are the ones `06-STORAGE/microsd` runs on a board. **TBD**: a
compile of this box; it needs the `esp_hosted` component, which is not in the
`kode` component yet.

## In the SDK

- [`kdrv_storage`](https://github.com/kodediy/kode-sdk/tree/main/components/kdrv/kdrv_storage): the card in `kode-sdk`.
