SD driver: a dummy byte before the ready test; say why a write failed (#21)

The card "refused" a write about once in 2,000 multi-block writes: three
1.7 MB uploads in ten. Measured with a driver that records where it gives
up: every time, all blocks were accepted, and the status check after Stop
Tran came back as 0xFF or 0x1F. The driver tests for ready with the first
byte after selecting the card, which reads 0xFF before the card has
signalled busy, so CMD13 went out mid-programming. A dummy byte first, as
in ChaN's reference driver, and one after Stop Tran.

30 uploads in a row since, each read back by SHA-256, ten with the radio
listening: no fault. 10 MHz made no difference; the card stays at 20 MHz.

`info` shows the driver's write faults; `put` prints the step and the
card's answer when one happens. ADR 0007.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-05 22:55:02 +02:00
co-authored by Claude Opus 5.5
parent 3ee7ae1097
commit 3f2650c56e
8 changed files with 115 additions and 16 deletions
+10
View File
@@ -17,6 +17,7 @@
#include "file_receiver.h"
#include "sha256.h"
#include "platform/console.h"
#include "sd_fault.h"
#include "version.h"
namespace roro {
@@ -232,7 +233,16 @@ void DebugConsole::put(NetworkClient& client, const std::string& args) {
while (r.state() == S::Receiving || r.state() == S::Writing) {
if (r.state() == S::Writing) {
const auto& c = r.chunk();
uint32_t t0 = millis();
bool ok = f.write(c.data(), c.size()) == c.size();
uint32_t took = millis() - t0;
// Why, from our copy of the SD driver (lib/SD, #21): the step that gave up and what
// the card answered. How long it took tells a 500 ms busy timeout from a refusal.
if (!ok) {
SdFault sd = sdLastFault();
console.printf("put: write failed at %u after %u ms: SD step %u, answer 0x%02X, status 0x%04X (%u so far)\n",
(unsigned)r.received(), (unsigned)took, sd.step, sd.token, (unsigned)sd.resp, (unsigned)sd.count);
}
// A card can fail one write and take the next. FATFS keeps a failed file in error,
// so: close, cut back to the last good byte, reopen, try again. Earlier chunks may
// have been lost with the write buffer (M3: 3 KB came back as zeros): never extend
+2 -2
View File
@@ -166,7 +166,7 @@ void StorageService::format() {
mounted_ = false;
bool ok = false;
uint8_t pdrv = sdcard_init(pins::kSdCs, &sharedSpi(), 20000000);
uint8_t pdrv = sdcard_init(pins::kSdCs, &sharedSpi(), kSdHz);
if (pdrv != 0xFF) {
constexpr size_t kWorkSize = 4096; // FF_MAX_SS
std::unique_ptr<uint8_t[]> work(new uint8_t[kWorkSize]);
@@ -182,7 +182,7 @@ void StorageService::format() {
}
bool StorageService::mount() {
return SD.begin(pins::kSdCs, sharedSpi(), 20000000, "/sd", 5, false);
return SD.begin(pins::kSdCs, sharedSpi(), kSdHz, "/sd", 5, false);
}
void StorageService::poll() {
+1
View File
@@ -56,6 +56,7 @@ class StorageService : public Service {
static constexpr uint32_t kWakeMs = 1000;
static constexpr uint32_t kPollEvery = 15; // wake-ups between usage checks
static constexpr size_t kMaxPendingBytes = 16 * 1024;
static constexpr uint32_t kSdHz = 20000000; // the card's SPI clock; 10 MHz changed nothing (ADR 0007)
static void taskEntry(void* self);
void loop();