RPi Pico SD Card SPI Connections and FatFs Integration in rpi_pico_wav_player

The rpi_pico_wav_player firmware uses the RP2040's SPI 0 peripheral (GPIO 4-7) to communicate with the micro-SD card and integrates the FatFs filesystem through the pico_fatfs wrapper library.

The rpi_pico_wav_player project by elehobica implements a WAV audio player on the Raspberry Pi Pico, requiring reliable SD card access for media storage. Understanding the SD card SPI connections and FatFs integration is essential for developers modifying the hardware or adapting the filesystem layer to custom boards.

SPI 0 Hardware Connections for the SD Card Interface

The firmware configures SPI 0 as the dedicated communication bus for the micro-SD card, utilizing the RP2040's default pin mapping provided by the pico-sdk.

Default GPIO Pin Assignment

The SPI 0 signals connect to the following GPIO pins as defined by the PIN_SPI0_*_DEFAULT constants referenced in lib/file_menu/file_menu_FatFs.c:

  • GPIO 4 — MISO (Master In Slave Out)
  • GPIO 5 — CS (Chip Select)
  • GPIO 6 — SCK (Serial Clock)
  • GPIO 7 — MOSI (Master Out Slave In)

Physical Wiring and Level Shifting

According to the project schematic in doc/schematic/RPi_Pico_WAV_Player_microsd_Schematic.png, the SD card connects directly to these GPIOs without external level-shifters. The RP2040's 3.3V logic levels are compatible with standard micro-SD card interfaces, allowing a simplified hardware design.

FatFs Integration Architecture

The project integrates the ChaN FatFs library through a custom RP2040 wrapper called pico_fatfs, included as a git submodule at lib/pico_fatfs.

SPI Configuration Structure

In lib/file_menu/file_menu_FatFs.c (lines 353-362), the SPI bus parameters are configured using the pico_fatfs_spi_config_t structure before filesystem initialization:

pico_fatfs_spi_config_t config = {
    spi0,                     // SPI controller instance
    CLK_SLOW_DEFAULT,         // Clock source selection
    40 * MHZ,                 // SPI clock frequency (40 MHz)
    PIN_SPI0_MISO_DEFAULT,    // MISO pin (GPIO 4)
    PIN_SPI0_CS_DEFAULT,      // Chip Select pin (GPIO 5)
    PIN_SPI0_SCK_DEFAULT,     // Serial Clock pin (GPIO 6)
    PIN_SPI0_MOSI_DEFAULT,    // MOSI pin (GPIO 7)
    true                      // Enable internal pull-ups
};
pico_fatfs_set_config(&config);

Filesystem Mounting with Retry Logic

Following configuration, the code attempts to mount the SD card using the standard FatFs f_mount function. As implemented in lib/file_menu/file_menu_FatFs.c (lines 364-373), the system implements a robust retry mechanism:

fr = f_mount(&fs, "", 1);     // Mount the volume immediately

if (fr != FR_OK) {
    // Retry logic: up to 5 attempts with SPI reset between tries
    for (int i = 0; i < 5 && fr != FR_OK; i++) {
        pico_fatfs_reboot_spi();   // Reset SPI0 peripheral
        fr = f_mount(&fs, "", 1);  // Retry mount
    }
}

Practical Implementation Examples

Initializing the SD Card from Application Code

High-level UI code in src/UIMode.cpp (lines 268-270) initializes the storage subsystem through the file_menu wrapper:

uint8_t fs_type;
FRESULT fr = file_menu_init(&fs_type);   // Configures SPI0 and mounts FatFs

if (fr != FR_OK) {
    printf("SD mount failed (code %d)\n", fr);
}

Performing File Operations

Once mounted, the firmware accesses WAV files using standard FatFs APIs. The following pattern demonstrates opening and reading audio data:

FIL fp;
char buffer[512];  // Audio data buffer
FRESULT fr = f_open(&fp, "track01.wav", FA_READ);

if (fr == FR_OK) {
    UINT bytes_read;
    f_read(&fp, buffer, sizeof(buffer), &bytes_read);
    // Process audio data...
    f_close(&fp);
}

Recovering from Communication Errors

When SPI communication fails or the card becomes unresponsive, the driver can reinitialize the bus without a full system reset. The pico_fatfs_reboot_spi() function resets the SPI 0 peripheral to its default state:

pico_fatfs_reboot_spi();   // Reset SPI0 and restore pin configuration
fr = f_mount(&fs, "", 1);  // Attempt remount

Summary

  • The rpi_pico_wav_player uses SPI 0 (GPIO 4-7) for micro-SD card communication, configured in lib/file_menu/file_menu_FatFs.c.
  • FatFs integration occurs through the pico_fatfs submodule, which wraps low-level SPI transactions into standard filesystem APIs.
  • The SPI configuration operates at 40 MHz with internal pull-ups enabled, requiring no external level-shifters for 3.3V operation.
  • Robust error handling includes automatic retry logic with pico_fatfs_reboot_spi() to recover from mount failures.
  • Application code interacts with storage through file_menu_init() and standard FatFs functions like f_open() and f_read().

Frequently Asked Questions

Which SPI bus does the rpi_pico_wav_player use for the SD card?

The firmware uses SPI 0 of the RP2040 microcontroller, configured through the pico_fatfs_set_config() function in lib/file_menu/file_menu_FatFs.c. This peripheral communicates at 40 MHz using the default GPIO pin mapping (GPIO 4-7).

What are the specific GPIO pin numbers for the SD card interface?

The SPI 0 connections map to GPIO 4 (MISO), GPIO 5 (CS), GPIO 6 (SCK), and GPIO 7 (MOSI). These pins are defined by the PIN_SPI0_*_DEFAULT constants from the pico-sdk and are referenced in the SPI configuration structure within file_menu_FatFs.c.

How is the FatFs library integrated into the project?

The project includes the pico_fatfs library as a git submodule at lib/pico_fatfs. This wrapper translates standard FatFs API calls (f_mount, f_open, f_read) into RP2040-specific SPI transactions, handling the low-level hardware communication automatically.

Does the hardware require level-shifters for the SD card connection?

No, the design does not require level-shifters. As shown in the project schematic (doc/schematic/RPi_Pico_WAV_Player_microsd_Schematic.png), the SD card connects directly to the Pico's 3.3V GPIO pins. The RP2040's voltage levels are compatible with standard micro-SD card specifications.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →