Skip to content

sd-read/sd-write throughput: one SD command per 512 bytes, and a link that idles during writes #1

Description

@joeferner

sd-read and sd-write are slow enough that the README documents it as
a limitation. Two independent causes, and neither is a missing driver
feature in rpi-hal.

1. Every transfer is one block per SD command

rpi-hal already does multi-block transfers (CMD18/CMD25 with an
auto-CMD12 stop), and its embedded-sdmmc adapter dispatches to them
whenever it is handed more than one block:

// rpi-hal, impl embedded_sdmmc::BlockDevice for SdCard
let count = checked_block_count(blocks.len())?;
self.sd.read_blocks_pio(start_block_idx.0, count, ..)

It never is. embedded_sdmmc::BlockCache holds a single block:

// embedded-sdmmc 0.9.0, src/blockdevice.rs
pub struct BlockCache<D> {
    block: [Block; 1],
    ...
}

so every read and write through the filesystem costs a full command
round trip per 512 bytes, and the multi-block path is dead code from the
loader's point of view.

Options, roughly in increasing order of work:

  • Bypass the FAT layer for bulk file data: walk the cluster chain once,
    then issue multi-block reads/writes against rpi-hal's Sd directly
    for the contiguous runs, keeping embedded-sdmmc for directory
    traversal and metadata. Most of the win, all of the complexity.
  • Take it upstream — a multi-block-aware cache in embedded-sdmmc
    benefits every consumer, not just this one.

Note that the DMA path (read_blocks_dma) stays unavailable either way
while blocks arrive as separate embedded_sdmmc::Blocks, since it wants
one contiguous buffer.

2. The link idles during every SD write

The device defers each chunk's OK until it has finished writing that
chunk. That is deliberate and must stay in some form: there is no
hardware flow control, the host sends the next ~4KB the instant it sees
OK, and the PL011's 16-byte RX FIFO overflows in ~85µs at 1.5Mbaud.
Acknowledging before a slow file.write dropped bytes and desynced the
framing — multi-chunk sd-write failed deterministically at the second
chunk while single-chunk files appeared to work.

The fix is to overlap rather than remove it: double-buffer, so the
device receives chunk N while writing chunk N-1, and the OK for N-1
goes out as soon as there is somewhere to put N. Two 4KB buffers is the
whole cost.

Worth measuring first

No throughput numbers have ever been taken, so the split between these
two causes is unknown, as is whether either matters next to the card's
own write latency. A measurement — bytes/second for a large sd-write
at a fixed baud — should come before either change, and is the only way
to tell whether the second one is worth the buffer.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions