Skip to content

Commit 4f015ee

Browse files
committed
wip
1 parent d2d6094 commit 4f015ee

2 files changed

Lines changed: 85 additions & 53 deletions

File tree

ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ CIRCUITPY_ESP_FLASH_SIZE = 16MB
1212
CIRCUITPY_ESP_PSRAM_MODE = opi
1313
CIRCUITPY_ESP_PSRAM_FREQ = 80m
1414
CIRCUITPY_ESP_PSRAM_SIZE = 8MB
15+
16+
CIRCUITPY_ULAB = 0

shared-module/sdcardio/SDCard.c

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// This implementation largely follows the structure of adafruit_sdcard.py
88

99
#include "extmod/vfs.h"
10-
10+
#include "esp_log.h"
1111
#include "shared-bindings/busio/SPI.h"
1212
#include "shared-bindings/digitalio/DigitalInOut.h"
1313
#include "shared-bindings/sdcardio/SDCard.h"
@@ -23,7 +23,12 @@
2323
#define DEBUG_PRINT(...) ((void)0)
2424
#endif
2525

26-
#define CMD_TIMEOUT (200)
26+
// https://www.taterli.com/wp-content/uploads/2017/05/Physical-Layer-Simplified-SpecificationV6.0.pdf
27+
// specifies timeouts for read (100 ms), write (250 ms), erase (depends on size), and other operations.
28+
// But the document also suggests allowing 500 ms even if a shorter timeout is specified.
29+
// So let's allow a nice long time, but don't wait in a tight loop: allow background tasks to run.
30+
#define CMD_TIMEOUT_MS (500)
31+
#define TIMEOUT_MS (500)
2732

2833
#define R1_IDLE_STATE (1 << 0)
2934
#define R1_ILLEGAL_COMMAND (1 << 2)
@@ -106,39 +111,53 @@ static uint8_t CRC7(const uint8_t *data, uint8_t n) {
106111
return (crc << 1) | 1;
107112
}
108113

109-
#define READY_TIMEOUT_NS (300 * 1000 * 1000) // 300ms
110-
static int wait_for_ready(sdcardio_sdcard_obj_t *self) {
111-
uint64_t deadline = common_hal_time_monotonic_ns() + READY_TIMEOUT_NS;
112-
while (common_hal_time_monotonic_ns() < deadline) {
114+
// Assumes that the spi lock has been acquired.
115+
//
116+
// Mask the incoming value with mask. Use 0xff to not mask.
117+
// if not_match is true, wait for something NOT matching the value.
118+
// Return the response as an int32_t (which is always >= 0), or -1 if timed out.
119+
static int32_t wait_for_masked_response(sdcardio_sdcard_obj_t *self, uint8_t mask, uint8_t response, bool not_match, uint32_t timeout_ms) {
120+
uint64_t deadline = supervisor_ticks_ms64() + timeout_ms;
121+
while (supervisor_ticks_ms64() < deadline) {
113122
uint8_t b;
114123
common_hal_busio_spi_read(self->bus, &b, 1, 0xff);
115-
if (b == 0xff) {
116-
return 0;
124+
if (((b & mask) == response) ^ not_match) {
125+
return b;
117126
}
127+
RUN_BACKGROUND_TASKS;
118128
}
119-
return -ETIMEDOUT;
129+
return -1;
130+
}
131+
132+
// Wait for the given response byte.
133+
static bool wait_for_response(sdcardio_sdcard_obj_t *self, uint8_t response) {
134+
return wait_for_masked_response(self, 0xff, response, false, TIMEOUT_MS) != -1;
135+
}
136+
137+
#define READY_TIMEOUT_MS (300)
138+
139+
// Wait for 0xff, with a shorter timeout.
140+
static bool wait_for_ready(sdcardio_sdcard_obj_t *self) {
141+
return wait_for_masked_response(self, 0xff, 0xff, false, READY_TIMEOUT_MS) != -1;
120142
}
121143

122144
// Note: this is never called while "in cmd25" (in fact, it's only used by `exit_cmd25`)
123-
static int cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) {
145+
static mp_negative_errno_t cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) {
124146
uint8_t cmdbuf[2] = {cmd, 0xff};
125147

126148
assert(!self->in_cmd25);
127149

128150
common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf));
129151

130152
// Wait for the response (response[7] == response)
131-
for (int i = 0; i < CMD_TIMEOUT; i++) {
132-
common_hal_busio_spi_read(self->bus, cmdbuf, 1, 0xff);
133-
if (cmdbuf[0] == response) {
134-
return 0;
135-
}
153+
if (wait_for_response(self, response)) {
154+
return 0;
136155
}
137156
return -MP_EIO;
138157
}
139158

140159

141-
static int exit_cmd25(sdcardio_sdcard_obj_t *self) {
160+
static mp_negative_errno_t exit_cmd25(sdcardio_sdcard_obj_t *self) {
142161
if (self->in_cmd25) {
143162
DEBUG_PRINT("exit cmd25\n");
144163
self->in_cmd25 = false;
@@ -149,7 +168,7 @@ static int exit_cmd25(sdcardio_sdcard_obj_t *self) {
149168

150169
// In Python API, defaults are response=None, data_block=True, wait=True
151170
static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf, size_t response_len, bool data_block, bool wait) {
152-
int r = exit_cmd25(self);
171+
mp_negative_errno_t r = exit_cmd25(self);
153172
if (r < 0) {
154173
return r;
155174
}
@@ -164,65 +183,63 @@ static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf
164183
cmdbuf[5] = CRC7(cmdbuf, 5);
165184

166185
if (wait) {
167-
r = wait_for_ready(self);
168-
if (r < 0) {
169-
return r;
186+
if (!wait_for_ready(self)) {
187+
return -MP_ETIMEDOUT;
170188
}
171189
}
172190

173191
common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf));
174192

175193
// Wait for the response (response[7] == 0)
176-
bool response_received = false;
177-
for (int i = 0; i < CMD_TIMEOUT; i++) {
178-
common_hal_busio_spi_read(self->bus, cmdbuf, 1, 0xff);
179-
if ((cmdbuf[0] & 0x80) == 0) {
180-
response_received = true;
181-
break;
182-
}
183-
}
184-
185-
if (!response_received) {
194+
// Now wait for cmd response, which is the high bit being 0.
195+
int32_t response = wait_for_masked_response(self, 0x80, 0, false, CMD_TIMEOUT_MS);
196+
if (response == -1) {
186197
return -MP_EIO;
187198
}
188199

189200
if (response_buf) {
190201

191202
if (data_block) {
192203
cmdbuf[1] = 0xff;
193-
do {
194-
// Wait for the start block byte
195-
common_hal_busio_spi_read(self->bus, cmdbuf + 1, 1, 0xff);
196-
} while (cmdbuf[1] != 0xfe);
204+
if (!wait_for_response(self, 0xfe)) {
205+
return -MP_EIO;
206+
}
197207
}
198208

199-
common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff);
209+
if (!common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff)) {
210+
return -MP_EIO;
211+
}
200212

201213
if (data_block) {
202214
// Read and discard the CRC-CCITT checksum
203-
common_hal_busio_spi_read(self->bus, cmdbuf + 1, 2, 0xff);
215+
if (!common_hal_busio_spi_read(self->bus, cmdbuf + 1, 2, 0xff)) {
216+
return -MP_EIO;
217+
}
204218
}
205219

206220
}
207221

208-
return cmdbuf[0];
222+
return response;
209223
}
210224

211225
static int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *response_buf, size_t response_len, bool data_block, bool wait) {
212226
return cmd(self, cmd_, block * self->cdv, response_buf, response_len, true, true);
213227
}
214228

215229
static mp_rom_error_text_t init_card_v1(sdcardio_sdcard_obj_t *self) {
216-
for (int i = 0; i < CMD_TIMEOUT; i++) {
230+
uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS;
231+
while (supervisor_ticks_ms64() < deadline) {
217232
if (cmd(self, 41, 0, NULL, 0, true, true) == 0) {
218233
return NULL;
219234
}
235+
RUN_BACKGROUND_TASKS;
220236
}
221237
return MP_ERROR_TEXT("timeout waiting for v1 card");
222238
}
223239

224240
static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) {
225-
for (int i = 0; i < CMD_TIMEOUT; i++) {
241+
uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS;
242+
while (supervisor_ticks_ms64() < deadline) {
226243
uint8_t ocr[4];
227244
common_hal_time_delay_ms(50);
228245
cmd(self, 58, 0, ocr, sizeof(ocr), false, true);
@@ -234,6 +251,7 @@ static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) {
234251
}
235252
return NULL;
236253
}
254+
RUN_BACKGROUND_TASKS;
237255
}
238256
return MP_ERROR_TEXT("timeout waiting for v2 card");
239257
}
@@ -250,6 +268,7 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) {
250268
{
251269
bool reached_idle_state = false;
252270
for (int i = 0; i < 5; i++) {
271+
ESP_LOGW("init_card", "loop: %d", i);
253272
// do not call cmd with wait=true, because that will return
254273
// prematurely if the idle state is not reached. we can't depend on
255274
// this when the card is not yet in SPI mode
@@ -366,23 +385,25 @@ int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) {
366385
}
367386

368387
static int readinto(sdcardio_sdcard_obj_t *self, void *buf, size_t size) {
369-
uint8_t aux[2] = {0, 0};
370-
while (aux[0] != 0xfe) {
371-
common_hal_busio_spi_read(self->bus, aux, 1, 0xff);
388+
389+
if (!wait_for_response(self, 0xfe)) {
390+
return -MP_EIO;
372391
}
373392

374393
common_hal_busio_spi_read(self->bus, buf, size, 0xff);
375394

376395
// Read checksum and throw it away
377-
common_hal_busio_spi_read(self->bus, aux, sizeof(aux), 0xff);
396+
uint8_t checksum[2];
397+
common_hal_busio_spi_read(self->bus, checksum, sizeof(checksum), 0xff);
378398
return 0;
379399
}
380400

401+
// The mp_uint_t is misleading; negative errors can be returned.
381402
mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t nblocks) {
382403
// deinit check is in lock_and_configure_bus()
383404
sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
384405
if (!lock_and_configure_bus(self)) {
385-
return MP_EAGAIN;
406+
return -MP_EAGAIN;
386407
}
387408
int r = 0;
388409
size_t buflen = 512 * nblocks;
@@ -415,6 +436,7 @@ mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t st
415436
}
416437
}
417438
extraclock_and_unlock_bus(self);
439+
// No caller actually uses this value.
418440
return r;
419441
}
420442

@@ -427,7 +449,9 @@ int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t
427449
}
428450

429451
static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) {
430-
wait_for_ready(self);
452+
if (!wait_for_ready(self)) {
453+
return -MP_ETIMEDOUT;
454+
}
431455

432456
uint8_t cmd[2];
433457
cmd[0] = token;
@@ -450,7 +474,8 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t
450474
// with STATUS 010 indicating "data accepted", and other status bit
451475
// combinations indicating failure.
452476
// In practice, I was seeing cmd[0] as 0xe5, indicating success
453-
for (int i = 0; i < CMD_TIMEOUT; i++) {
477+
uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS;
478+
while (supervisor_ticks_ms64() < deadline) {
454479
common_hal_busio_spi_read(self->bus, cmd, 1, 0xff);
455480
DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]);
456481
if ((cmd[0] & 0b00010001) == 0b00000001) {
@@ -460,12 +485,15 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t
460485
break;
461486
}
462487
}
488+
RUN_BACKGROUND_TASKS;
463489
}
464490

465491
// Wait for the write to finish
466-
do {
467-
common_hal_busio_spi_read(self->bus, cmd, 1, 0xff);
468-
} while (cmd[0] == 0);
492+
493+
// Wait for a non-zero value.
494+
if (wait_for_masked_response(self, 0xff /*mask*/, 0, true /*not_match*/, TIMEOUT_MS) == -1) {
495+
return -MP_EIO;
496+
}
469497

470498
// Success
471499
return 0;
@@ -475,7 +503,7 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s
475503
// deinit check is in lock_and_configure_bus()
476504
sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in);
477505
if (!lock_and_configure_bus(self)) {
478-
return MP_EAGAIN;
506+
return -MP_EAGAIN;
479507
}
480508

481509
if (!self->in_cmd25 || start_block != self->next_block) {
@@ -507,15 +535,17 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s
507535
return 0;
508536
}
509537

510-
int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) {
538+
mp_negative_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) {
511539
// deinit check is in lock_and_configure_bus()
512-
lock_and_configure_bus(self);
540+
if (!lock_and_configure_bus(self)) {
541+
return -MP_EAGAIN;
542+
}
513543
int r = exit_cmd25(self);
514544
extraclock_and_unlock_bus(self);
515545
return r;
516546
}
517547

518-
int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) {
548+
mp_negative_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) {
519549
if (buf->len % 512 != 0) {
520550
mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512);
521551
}

0 commit comments

Comments
 (0)