Repository navigation
CHSd: send 8 idle clocks before each command, so more microSD cards work and it follows the specification - #21
Merged
bateske merged 3 commits intoOct 9, 2026
Conversation
…ork and it follows the specification
tests/test_spi.cpp's card model is now strict about N_RC: a command that starts on the byte right after a response's last byte counts as a failure. Without the previous commit's idle byte every init case fails (11 or 12 commands per init); with it all 7 pass. platform/README.md records the change (CLAUDE.md rule 6): +8 B in each of CHWords, CHWordWheel, CHCrossword and CHStlView, RAM unchanged, both save pages kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CHSd's cmd() (libraries/CHSd/src/SdSpi.cpp) sends a command right after the previous response. The SD Physical Layer Simplified Specification requires at least 8 clock cycles between the end of a response and the start of the next command. In SPI mode that's N_RC, at least one byte of idle clocks; see the SPI timing values in section 7.5. Many cards tolerate the missing gap, but strict ones don't. Adding one idle byte makes CHSd follow the spec, so it supports more cards, at practically no cost.
What happens
With a SanDisk 32 GB microSD (CID maker 3, product "SK32G"), FAT32, CHStlView from board package 0.3.0 says no card on a rev0 board. The SD menu bootloader and CHSDtoUSB read the same card fine.
Logged on the device during identification at 187.5 kHz, right after a power cycle:
the first CMD0 answers 01, as it should;
the next CMD0, sent right after that response, comes back as C1 7F: the card is still finishing its previous answer, so the new command arrives misaligned;
from then on every answer is shifted by 6 bits (7F, then 3F for ACMD41);
after a few commands the card stops answering entirely, until its power is cycled.
The bootloader's sd.c sends x(0xFF) at the start of every command, and CHSDtoUSB's sdfatlib driver calls waitNotBusy() first, which also clocks idle bytes. That's why both work with this card.
The fix
One line at the start of cmd():
Tested on the device (rev0, same card):
CHStlView from the 0.3.0 board package, as released: no card.
The same CHStlView source built with only this line added: it reads the card.
With a test sketch on the patched CHSd: the card initialises at the first try, FAT32 mounts, files are found, and single-block reads and 24 MHz stream() reads (200 runs of 17 blocks) complete with no failures.
Cost: one byte per command, not per data byte. Measured in a cycle-accurate emulator: about +0.2% on a 17-block stream at 24 MHz.
Affected: every sketch using CHSd, in board package 0.3.0 and the current main: CHStlView, and CHWords, CHCrossword and CHWordWheel for their card files.