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"
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
151170static 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
211225static 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
215229static 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
224240static 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
368387static 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.
381402mp_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
429451static 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