@@ -21,6 +21,9 @@ use crate::{debug, trace, warn};
21
21
// Types and Implementations
22
22
// ****************************************************************************
23
23
24
+ /// The max number of bytes in a command response.
25
+ const COMMAND_RESPONSE_BYTES : usize = 5 ;
26
+
24
27
/// Driver for an SD Card on an SPI bus.
25
28
///
26
29
/// Built from an [`SpiDevice`] implementation and a Chip Select pin.
@@ -254,10 +257,8 @@ where
254
257
self . write_data ( DATA_START_BLOCK , & blocks[ 0 ] . contents )
255
258
. await ?;
256
259
self . wait_not_busy ( Delay :: new_write ( ) ) . await ?;
257
- if self . card_command ( CMD13 , 0 ) . await ? != 0x00 {
258
- return Err ( Error :: WriteError ) ;
259
- }
260
- if self . read_byte ( ) . await ? != 0x00 {
260
+ let response = self . card_command ( CMD13 , 0 ) . await ?;
261
+ if response[ 0 ] != 0x00 || response[ 1 ] != 0x00 {
261
262
return Err ( Error :: WriteError ) ;
262
263
}
263
264
} else {
@@ -317,15 +318,17 @@ where
317
318
match self . card_type {
318
319
Some ( CardType :: SD1 ) => {
319
320
let mut csd = CsdV1 :: new ( ) ;
320
- if self . card_command ( CMD9 , 0 ) . await ? != 0 {
321
+ let cmd_response = self . card_command ( CMD9 , 0 ) . await ?;
322
+ if cmd_response[ 0 ] != 0 {
321
323
return Err ( Error :: RegisterReadError ) ;
322
324
}
323
325
self . read_data ( & mut csd. data ) . await ?;
324
326
Ok ( Csd :: V1 ( csd) )
325
327
}
326
328
Some ( CardType :: SD2 | CardType :: SDHC ) => {
327
329
let mut csd = CsdV2 :: new ( ) ;
328
- if self . card_command ( CMD9 , 0 ) . await ? != 0 {
330
+ let cmd_response = self . card_command ( CMD9 , 0 ) . await ?;
331
+ if cmd_response[ 0 ] != 0 {
329
332
return Err ( Error :: RegisterReadError ) ;
330
333
}
331
334
self . read_data ( & mut csd. data ) . await ?;
@@ -429,12 +432,12 @@ where
429
432
Err ( e) => {
430
433
return Err ( e) ;
431
434
}
432
- Ok ( R1_IDLE_STATE ) => {
435
+ Ok ( [ R1_IDLE_STATE , .. ] ) => {
433
436
break ;
434
437
}
435
438
Ok ( _r) => {
436
439
// Try again
437
- warn ! ( "Got response: {:x}, trying again.." , _r) ;
440
+ warn ! ( "Got response: {:x}, trying again.." , _r[ 0 ] ) ;
438
441
}
439
442
}
440
443
@@ -444,19 +447,18 @@ where
444
447
debug ! ( "Enable CRC: {}" , self . options. use_crc) ;
445
448
// "The SPI interface is initialized in the CRC OFF mode in default"
446
449
// -- SD Part 1 Physical Layer Specification v9.00, Section 7.2.2 Bus Transfer Protection
447
- if self . options . use_crc && self . card_command ( CMD59 , 1 ) . await ? != R1_IDLE_STATE {
450
+ if self . options . use_crc && self . card_command ( CMD59 , 1 ) . await ?[ 0 ] != R1_IDLE_STATE {
448
451
return Err ( Error :: CantEnableCRC ) ;
449
452
}
450
453
// Check card version
451
454
let mut delay = Delay :: new_command ( ) ;
452
455
let arg = loop {
453
- if self . card_command ( CMD8 , 0x1AA ) . await ? == ( R1_ILLEGAL_COMMAND | R1_IDLE_STATE ) {
456
+ let cmd_response = self . card_command ( CMD8 , 0x1AA ) . await ?;
457
+ if cmd_response[ 0 ] == ( R1_ILLEGAL_COMMAND | R1_IDLE_STATE ) {
454
458
card_type = CardType :: SD1 ;
455
459
break 0 ;
456
460
}
457
- let mut buffer = [ 0xFF ; 4 ] ;
458
- self . transfer_bytes ( & mut buffer) . await ?;
459
- let status = buffer[ 3 ] ;
461
+ let status = cmd_response[ 4 ] ;
460
462
if status == 0xAA {
461
463
card_type = CardType :: SD2 ;
462
464
break 0x4000_0000 ;
@@ -474,12 +476,11 @@ where
474
476
}
475
477
476
478
if card_type == CardType :: SD2 {
477
- if self . card_command ( CMD58 , 0 ) . await ? != 0 {
479
+ let cmd_response = self . card_command ( CMD58 , 0 ) . await ?;
480
+ if cmd_response[ 0 ] != 0 {
478
481
return Err ( Error :: Cmd58Error ) ;
479
482
}
480
- let mut buffer = [ 0xFF ; 4 ] ;
481
- self . transfer_bytes ( & mut buffer) . await ?;
482
- if ( buffer[ 0 ] & 0xC0 ) == 0xC0 {
483
+ if ( cmd_response[ 1 ] & 0xC0 ) == 0xC0 {
483
484
card_type = CardType :: SDHC ;
484
485
}
485
486
// Ignore the other three bytes
@@ -496,42 +497,50 @@ where
496
497
/// Perform an application-specific command.
497
498
async fn card_acmd ( & mut self , command : u8 , arg : u32 ) -> Result < u8 , Error > {
498
499
self . card_command ( CMD55 , 0 ) . await ?;
499
- self . card_command ( command, arg) . await
500
+ self . card_command ( command, arg) . await . map ( |r| r [ 0 ] )
500
501
}
501
502
502
503
/// Perform a command.
503
- async fn card_command ( & mut self , command : u8 , arg : u32 ) -> Result < u8 , Error > {
504
+ async fn card_command (
505
+ & mut self ,
506
+ command : u8 ,
507
+ arg : u32 ,
508
+ ) -> Result < [ u8 ; COMMAND_RESPONSE_BYTES ] , Error > {
504
509
if command != CMD0 && command != CMD12 {
505
510
self . wait_not_busy ( Delay :: new_command ( ) ) . await ?;
506
511
}
507
512
508
- let mut buf = [
509
- 0x40 | command,
510
- ( arg >> 24 ) as u8 ,
511
- ( arg >> 16 ) as u8 ,
512
- ( arg >> 8 ) as u8 ,
513
- arg as u8 ,
514
- 0 ,
515
- ] ;
513
+ const COMMAND_BYTES : usize = 6 ;
514
+ // The maximum number of bytes before the card should start sending the response. Based on
515
+ // http://elm-chan.org/docs/mmc/mmc_e.html
516
+ const MAX_WAIT_BYTES : usize = 8 ;
517
+ const TRANSFER_BYTES : usize = COMMAND_BYTES + MAX_WAIT_BYTES + COMMAND_RESPONSE_BYTES ;
518
+
519
+ let mut buf = [ 0xFF ; TRANSFER_BYTES ] ;
520
+ buf[ 0 ] = 0x40 | command;
521
+ buf[ 1 ] = ( arg >> 24 ) as u8 ;
522
+ buf[ 2 ] = ( arg >> 16 ) as u8 ;
523
+ buf[ 3 ] = ( arg >> 8 ) as u8 ;
524
+ buf[ 4 ] = arg as u8 ;
516
525
buf[ 5 ] = crc7 ( & buf[ 0 ..5 ] ) ;
517
526
518
- self . write_bytes ( & buf ) . await ? ;
519
-
520
- // skip stuff byte for stop read
521
- if command == CMD12 {
522
- let _result = self . read_byte ( ) . await ?;
523
- }
524
-
525
- let mut delay = Delay :: new_command ( ) ;
526
- loop {
527
- let result = self . read_byte ( ) . await ? ;
528
- if ( result & 0x80 ) == ERROR_OK {
529
- return Ok ( result ) ;
530
- }
531
- delay
532
- . delay ( & mut self . delayer , Error :: TimeoutCommand ( command ) )
533
- . await ? ;
534
- }
527
+ // Write the command and read the response in a single SPI transfer. In the async case
528
+ // this allows performing the command without CPU attention and it removes the risk of
529
+ // timeouts on the SD card caused by scheduling delays between sending the command and
530
+ // reading the response.
531
+ self . transfer_bytes ( & mut buf ) . await ?;
532
+
533
+ // Find the response in the buffer
534
+ buf . iter ( )
535
+ . skip ( COMMAND_BYTES )
536
+ . position ( | & b| ( b & 0x80 ) == ERROR_OK )
537
+ . and_then ( |pos| {
538
+ let start = pos + COMMAND_BYTES ;
539
+ let end = start + COMMAND_RESPONSE_BYTES ;
540
+ buf . get ( start..end )
541
+ } )
542
+ . and_then ( |bytes| bytes . try_into ( ) . ok ( ) )
543
+ . ok_or ( Error :: UnexpectedResponse ( command ) )
535
544
}
536
545
537
546
/// Receive a byte from the SPI bus by clocking out an 0xFF byte.
@@ -627,6 +636,8 @@ pub enum Error {
627
636
TimeoutWaitNotBusy ,
628
637
/// We didn't get a response when executing this command
629
638
TimeoutCommand ( u8 ) ,
639
+ /// We didn't get the expected response when executing this command
640
+ UnexpectedResponse ( u8 ) ,
630
641
/// We didn't get a response when executing this application-specific command
631
642
TimeoutACommand ( u8 ) ,
632
643
/// We got a bad response from Command 58
0 commit comments