@@ -33,6 +33,8 @@ class SdCard {
3333 bool crcOn;
3434 // Access to diagnostic logging.
3535 Log *log;
36+ // Does this SPI controller have the ability to control the idle state of the COPI line?
37+ bool idleControl;
3638
3739 // We need to clock the device repeatedly at startup; this test pattern is used to ensure that
3840 // we keep the COPI line high and it cannot be misinterpreted as a command.
@@ -94,6 +96,11 @@ class SdCard {
9496 // Every card tried seems to be more than capable of keeping up with 20Mbps.
9597 constexpr unsigned kSpiSpeed = 0u ;
9698 spi->init (false , false , true , kSpiSpeed );
99+ // Can we control the idle state of the COPI line?
100+ // - keeping it high when not transmitting saves us the additional work of transmitting '0xff'
101+ // bytes
102+ spi->configuration |= (1U << 28 );
103+ idleControl = ((spi->configuration & (1U << 28 )) != 0u );
97104
98105 // Apparently we're required to send at least 74 SD CLK cycles with
99106 // the device _not_ selected before talking to it.
@@ -337,9 +344,13 @@ class SdCard {
337344 volatile uint8_t rd2;
338345 (void )get_response_R1 ();
339346 for (int r = 0 ; r < 4 ; ++r) {
340- spi->transmitFifo = 0xffu ;
341- spi->control = SonataSpi::ControlTransmitEnable | SonataSpi::ControlReceiveEnable;
342- spi->start = 1u ;
347+ if (idleControl) {
348+ spi->control = SonataSpi::ControlReceiveEnable;
349+ } else {
350+ spi->transmitFifo = 0xffu ;
351+ spi->control = SonataSpi::ControlTransmitEnable | SonataSpi::ControlReceiveEnable;
352+ }
353+ spi->start = 1u ;
343354 spi->wait_idle ();
344355 while ((spi->status & SonataSpi::StatusRxFifoLevel) == 0 ) {
345356 }
@@ -441,28 +452,45 @@ class SdCard {
441452 spi->wait_idle ();
442453 // Do not attempt a zero-byte transfer; not supported by the controller.
443454 if (len) {
444- spi->control = SonataSpi::ControlReceiveEnable | SonataSpi::ControlTransmitEnable;
445- spi->start = len;
446-
447- // In addition to keeping the COPI line high to avoid inducing failures we want
448- // to keep the Tx FIFO populated so that the SPI controller remains active despite
449- // having double the traffic between CPU and SPI (Tx and Rx).
450- //
451- // This expression of the code very nearly keeps the SPI controller running at
452- // SysClkFreq/2 Mbps whilst reading data, so that the data block is retrieved as
453- // quickly as possible.
454- //
455- // Prompt the retrieval of the first byte.
456- spi->transmitFifo = 0xffu ; // Keep COPI high, staying one byte ahead of reception.
457- const uint8_t *end = data + len - 1 ;
458- while (data < end) {
459- // Prompt the retrieval of the next byte.
460- spi->transmitFifo = 0xffu ; // COPI high for the next byte.
461- // Wait until it's available, and quickly capture it.
462- while (spi->status & SonataSpi::StatusRxFifoEmpty) {
455+ if (idleControl) {
456+ // We need only be concerned with data reception since this controller can keep the
457+ // COPI line high when only reception is enabled.
458+ spi->control = SonataSpi::ControlReceiveEnable;
459+ spi->start = len;
460+ // Prompt the retrieval of the first byte.
461+ const uint8_t *end = data + len - 1 ;
462+ while (data < end) {
463+ // Wait until it's available, and quickly capture it.
464+ while (spi->status & SonataSpi::StatusRxFifoEmpty) {
465+ }
466+ *data++ = static_cast <uint8_t >(spi->receiveFifo );
467+ }
468+ } else {
469+ // Older SPI controllers cannot keep the COPI line high when not actively transmitting.
470+ spi->control = SonataSpi::ControlReceiveEnable | SonataSpi::ControlTransmitEnable;
471+ spi->start = len;
472+
473+ // In addition to keeping the COPI line high to avoid inducing failures we want
474+ // to keep the Tx FIFO populated so that the SPI controller remains active despite
475+ // having double the traffic between CPU and SPI (Tx and Rx).
476+ //
477+ // This expression of the code very nearly keeps the SPI controller running at
478+ // SysClkFreq/2 Mbps whilst reading data, so that the data block is retrieved as
479+ // quickly as possible.
480+ //
481+ // Prompt the retrieval of the first byte.
482+ spi->transmitFifo = 0xffu ; // Keep COPI high, staying one byte ahead of reception.
483+ const uint8_t *end = data + len - 1 ;
484+ while (data < end) {
485+ // Prompt the retrieval of the next byte.
486+ spi->transmitFifo = 0xffu ; // COPI high for the next byte.
487+ // Wait until it's available, and quickly capture it.
488+ while (spi->status & SonataSpi::StatusRxFifoEmpty) {
489+ }
490+ *data++ = static_cast <uint8_t >(spi->receiveFifo );
463491 }
464- *data++ = static_cast <uint8_t >(spi->receiveFifo );
465492 }
493+
466494 // Collect the final byte.
467495 while (spi->status & SonataSpi::StatusRxFifoEmpty) {
468496 }
0 commit comments