@@ -21,34 +21,74 @@ use crate::{debug, warn};
21
21
// Types and Implementations
22
22
// ****************************************************************************
23
23
24
+ /// A dummy "CS pin" that does nothing when set high or low.
25
+ ///
26
+ /// Should be used when constructing an [`SpiDevice`] implementation for use with [`SdCard`].
27
+ ///
28
+ /// Let the [`SpiDevice`] use this dummy CS pin that does not actually do anything, and pass the
29
+ /// card's real CS pin to [`SdCard`]'s constructor. This allows the driver to have more
30
+ /// fine-grained control of how the CS pin is managed than is allowed by default using the
31
+ /// [`SpiDevice`] trait, which is needed to implement the SD/MMC SPI communication spec correctly.
32
+ ///
33
+ /// If you're not sure how to get a [`SpiDevice`], you may use one of the implementations
34
+ /// in the [`embedded-hal-bus`] crate, providing a wrapped version of your platform's HAL-provided
35
+ /// [`SpiBus`] and [`DelayNs`] as well as our [`DummyCsPin`] in the constructor.
36
+ ///
37
+ /// [`SpiDevice`]: embedded_hal::spi::SpiDevice
38
+ /// [`SpiBus`]: embedded_hal::spi::SpiBus
39
+ /// [`DelayNs`]: embedded_hal::delay::DelayNs
40
+ /// [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus
41
+ pub struct DummyCsPin ;
42
+
43
+ impl embedded_hal:: digital:: ErrorType for DummyCsPin {
44
+ type Error = core:: convert:: Infallible ;
45
+ }
46
+
47
+ impl embedded_hal:: digital:: OutputPin for DummyCsPin {
48
+ #[ inline( always) ]
49
+ fn set_low ( & mut self ) -> Result < ( ) , Self :: Error > {
50
+ Ok ( ( ) )
51
+ }
52
+
53
+ #[ inline( always) ]
54
+ fn set_high ( & mut self ) -> Result < ( ) , Self :: Error > {
55
+ Ok ( ( ) )
56
+ }
57
+ }
58
+
24
59
/// Represents an SD Card on an SPI bus.
25
60
///
26
- /// Built from an SPI peripheral and a Chip Select pin. We need Chip Select to
27
- /// be separate so we can clock out some bytes without Chip Select asserted
28
- /// (which "flushes the SD cards registers" according to the spec).
61
+ /// Built from an [`SpiDevice`] implementation and a Chip Select pin.
62
+ /// Unfortunately, We need control of the chip select pin separately from the [`SpiDevice`]
63
+ /// implementation so we can clock out some bytes without Chip Select asserted
64
+ /// (which is necessary to make the SD card actually release the Spi bus after performing
65
+ /// operations on it, according to the spec). To support this, we provide [`DummyCsPin`]
66
+ /// which should be provided to your chosen [`SpiDevice`] implementation rather than the card's
67
+ /// actual CS pin. Then provide the actual CS pin to [`SdCard`]'s constructor.
29
68
///
30
69
/// All the APIs take `&self` - mutability is handled using an inner `RefCell`.
70
+ ///
71
+ /// [`SpiDevice`]: embedded_hal::spi::SpiDevice
31
72
pub struct SdCard < SPI , CS , DELAYER >
32
73
where
33
- SPI : embedded_hal:: blocking:: spi:: Transfer < u8 > + embedded_hal:: blocking:: spi:: Write < u8 > ,
34
- CS : embedded_hal:: digital:: v2:: OutputPin ,
35
- <SPI as embedded_hal:: blocking:: spi:: Transfer < u8 > >:: Error : core:: fmt:: Debug ,
36
- <SPI as embedded_hal:: blocking:: spi:: Write < u8 > >:: Error : core:: fmt:: Debug ,
37
- DELAYER : embedded_hal:: blocking:: delay:: DelayUs < u8 > ,
74
+ SPI : embedded_hal:: spi:: SpiDevice < u8 > ,
75
+ CS : embedded_hal:: digital:: OutputPin ,
76
+ DELAYER : embedded_hal:: delay:: DelayNs ,
38
77
{
39
78
inner : RefCell < SdCardInner < SPI , CS , DELAYER > > ,
40
79
}
41
80
42
81
impl < SPI , CS , DELAYER > SdCard < SPI , CS , DELAYER >
43
82
where
44
- SPI : embedded_hal:: blocking:: spi:: Transfer < u8 > + embedded_hal:: blocking:: spi:: Write < u8 > ,
45
- CS : embedded_hal:: digital:: v2:: OutputPin ,
46
- <SPI as embedded_hal:: blocking:: spi:: Transfer < u8 > >:: Error : core:: fmt:: Debug ,
47
- <SPI as embedded_hal:: blocking:: spi:: Write < u8 > >:: Error : core:: fmt:: Debug ,
48
- DELAYER : embedded_hal:: blocking:: delay:: DelayUs < u8 > ,
83
+ SPI : embedded_hal:: spi:: SpiDevice < u8 > ,
84
+ CS : embedded_hal:: digital:: OutputPin ,
85
+ DELAYER : embedded_hal:: delay:: DelayNs ,
49
86
{
50
87
/// Create a new SD/MMC Card driver using a raw SPI interface.
51
88
///
89
+ /// See the docs of the [`SdCard`] struct for more information about
90
+ /// how to construct the needed `SPI` and `CS` types.
91
+ ///
52
92
/// The card will not be initialised at this time. Initialisation is
53
93
/// deferred until a method is called on the object.
54
94
///
59
99
60
100
/// Construct a new SD/MMC Card driver, using a raw SPI interface and the given options.
61
101
///
102
+ /// See the docs of the [`SdCard`] struct for more information about
103
+ /// how to construct the needed `SPI` and `CS` types.
104
+ ///
62
105
/// The card will not be initialised at this time. Initialisation is
63
106
/// deferred until a method is called on the object.
64
107
pub fn new_with_options (
@@ -152,11 +195,9 @@ where
152
195
153
196
impl < SPI , CS , DELAYER > BlockDevice for SdCard < SPI , CS , DELAYER >
154
197
where
155
- SPI : embedded_hal:: blocking:: spi:: Transfer < u8 > + embedded_hal:: blocking:: spi:: Write < u8 > ,
156
- CS : embedded_hal:: digital:: v2:: OutputPin ,
157
- <SPI as embedded_hal:: blocking:: spi:: Transfer < u8 > >:: Error : core:: fmt:: Debug ,
158
- <SPI as embedded_hal:: blocking:: spi:: Write < u8 > >:: Error : core:: fmt:: Debug ,
159
- DELAYER : embedded_hal:: blocking:: delay:: DelayUs < u8 > ,
198
+ SPI : embedded_hal:: spi:: SpiDevice < u8 > ,
199
+ CS : embedded_hal:: digital:: OutputPin ,
200
+ DELAYER : embedded_hal:: delay:: DelayNs ,
160
201
{
161
202
type Error = Error ;
162
203
@@ -205,11 +246,9 @@ where
205
246
/// All the APIs required `&mut self`.
206
247
struct SdCardInner < SPI , CS , DELAYER >
207
248
where
208
- SPI : embedded_hal:: blocking:: spi:: Transfer < u8 > + embedded_hal:: blocking:: spi:: Write < u8 > ,
209
- CS : embedded_hal:: digital:: v2:: OutputPin ,
210
- <SPI as embedded_hal:: blocking:: spi:: Transfer < u8 > >:: Error : core:: fmt:: Debug ,
211
- <SPI as embedded_hal:: blocking:: spi:: Write < u8 > >:: Error : core:: fmt:: Debug ,
212
- DELAYER : embedded_hal:: blocking:: delay:: DelayUs < u8 > ,
249
+ SPI : embedded_hal:: spi:: SpiDevice < u8 > ,
250
+ CS : embedded_hal:: digital:: OutputPin ,
251
+ DELAYER : embedded_hal:: delay:: DelayNs ,
213
252
{
214
253
spi : SPI ,
215
254
cs : CS ,
@@ -220,11 +259,9 @@ where
220
259
221
260
impl < SPI , CS , DELAYER > SdCardInner < SPI , CS , DELAYER >
222
261
where
223
- SPI : embedded_hal:: blocking:: spi:: Transfer < u8 > + embedded_hal:: blocking:: spi:: Write < u8 > ,
224
- CS : embedded_hal:: digital:: v2:: OutputPin ,
225
- <SPI as embedded_hal:: blocking:: spi:: Transfer < u8 > >:: Error : core:: fmt:: Debug ,
226
- <SPI as embedded_hal:: blocking:: spi:: Write < u8 > >:: Error : core:: fmt:: Debug ,
227
- DELAYER : embedded_hal:: blocking:: delay:: DelayUs < u8 > ,
262
+ SPI : embedded_hal:: spi:: SpiDevice < u8 > ,
263
+ CS : embedded_hal:: digital:: OutputPin ,
264
+ DELAYER : embedded_hal:: delay:: DelayNs ,
228
265
{
229
266
/// Read one or more blocks, starting at the given block index.
230
267
fn read ( & mut self , blocks : & mut [ Block ] , start_block_idx : BlockIdx ) -> Result < ( ) , Error > {
@@ -583,21 +620,24 @@ where
583
620
584
621
/// Send one byte and receive one byte over the SPI bus.
585
622
fn transfer_byte ( & mut self , out : u8 ) -> Result < u8 , Error > {
623
+ let mut read_buf = [ 0u8 ; 1 ] ;
586
624
self . spi
587
- . transfer ( & mut [ out] )
588
- . map ( |b| b [ 0 ] )
589
- . map_err ( |_e| Error :: Transport )
625
+ . transfer ( & mut read_buf , & [ out] )
626
+ . map_err ( |_| Error :: Transport ) ? ;
627
+ Ok ( read_buf [ 0 ] )
590
628
}
591
629
592
- /// Send mutiple bytes and ignore what comes back over the SPI bus.
630
+ /// Send multiple bytes and ignore what comes back over the SPI bus.
593
631
fn write_bytes ( & mut self , out : & [ u8 ] ) -> Result < ( ) , Error > {
594
632
self . spi . write ( out) . map_err ( |_e| Error :: Transport ) ?;
595
633
Ok ( ( ) )
596
634
}
597
635
598
636
/// Send multiple bytes and replace them with what comes back over the SPI bus.
599
637
fn transfer_bytes ( & mut self , in_out : & mut [ u8 ] ) -> Result < ( ) , Error > {
600
- self . spi . transfer ( in_out) . map_err ( |_e| Error :: Transport ) ?;
638
+ self . spi
639
+ . transfer_in_place ( in_out)
640
+ . map_err ( |_e| Error :: Transport ) ?;
601
641
Ok ( ( ) )
602
642
}
603
643
@@ -689,7 +729,7 @@ pub enum CardType {
689
729
/// Uses byte-addressing internally, so limited to 2GiB in size.
690
730
SD2 ,
691
731
/// An high-capacity 'SDHC' Card.
692
- ///
732
+ ///
693
733
/// Uses block-addressing internally to support capacities above 2GiB.
694
734
SDHC ,
695
735
}
@@ -753,7 +793,7 @@ impl Delay {
753
793
/// `Ok(())`.
754
794
fn delay < T > ( & mut self , delayer : & mut T , err : Error ) -> Result < ( ) , Error >
755
795
where
756
- T : embedded_hal:: blocking :: delay:: DelayUs < u8 > ,
796
+ T : embedded_hal:: delay:: DelayNs ,
757
797
{
758
798
if self . retries_left == 0 {
759
799
Err ( err)
0 commit comments