Skip to content

Commit 4d3aa31

Browse files
committed
Create and document DummyCsPin for use with e-h1.0
1 parent 69d8047 commit 4d3aa31

File tree

3 files changed

+88
-19
lines changed

3 files changed

+88
-19
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ hex-literal = "0.4.1"
2323
flate2 = "1.0"
2424
sha2 = "0.10"
2525
chrono = "0.4"
26+
embedded-hal-bus = "0.1.0-rc.1"
2627

2728
[features]
2829
default = ["log"]

examples/readme_test.rs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,45 @@
33
//! We add enough stuff to make it compile, but it won't run because our fake
44
//! SPI doesn't do any replies.
55
6-
struct FakeSpi();
6+
use core::cell::RefCell;
77

8-
impl embedded_hal::spi::SpiDevice<u8> for FakeSpi {
8+
use embedded_sdmmc::sdcard::DummyCsPin;
9+
10+
struct FakeSpiBus();
11+
12+
impl embedded_hal::spi::ErrorType for FakeSpiBus {
913
type Error = core::convert::Infallible;
10-
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
11-
Ok(words)
12-
}
1314
}
1415

15-
impl embedded_hal::spi::SpiDevice<u8> for FakeSpi {
16-
type Error = core::convert::Infallible;
17-
fn write(&mut self, _words: &[u8]) -> Result<(), Self::Error> {
16+
impl embedded_hal::spi::SpiBus<u8> for FakeSpiBus {
17+
fn read(&mut self, _: &mut [u8]) -> Result<(), Self::Error> {
18+
Ok(())
19+
}
20+
21+
fn write(&mut self, _: &[u8]) -> Result<(), Self::Error> {
22+
Ok(())
23+
}
24+
25+
fn transfer(&mut self, _: &mut [u8], _: &[u8]) -> Result<(), Self::Error> {
26+
Ok(())
27+
}
28+
29+
fn transfer_in_place(&mut self, _: &mut [u8]) -> Result<(), Self::Error> {
30+
Ok(())
31+
}
32+
33+
fn flush(&mut self) -> Result<(), Self::Error> {
1834
Ok(())
1935
}
2036
}
2137

2238
struct FakeCs();
2339

24-
impl embedded_hal::digital::OutputPin for FakeCs {
40+
impl embedded_hal::digital::ErrorType for FakeCs {
2541
type Error = core::convert::Infallible;
42+
}
43+
44+
impl embedded_hal::digital::OutputPin for FakeCs {
2645
fn set_low(&mut self) -> Result<(), Self::Error> {
2746
Ok(())
2847
}
@@ -32,10 +51,11 @@ impl embedded_hal::digital::OutputPin for FakeCs {
3251
}
3352
}
3453

54+
#[derive(Clone, Copy)]
3555
struct FakeDelayer();
3656

3757
impl embedded_hal::delay::DelayUs for FakeDelayer {
38-
fn delay_us(&mut self, us: u8) {
58+
fn delay_us(&mut self, us: u32) {
3959
std::thread::sleep(std::time::Duration::from_micros(u64::from(us)));
4060
}
4161
}
@@ -74,9 +94,10 @@ impl From<embedded_sdmmc::SdCardError> for Error {
7494
}
7595

7696
fn main() -> Result<(), Error> {
77-
let sdmmc_spi = FakeSpi();
78-
let sdmmc_cs = FakeCs();
97+
let spi_bus = RefCell::new(FakeSpiBus());
7998
let delay = FakeDelayer();
99+
let sdmmc_spi = embedded_hal_bus::spi::RefCellDevice::new(&spi_bus, DummyCsPin, delay);
100+
let sdmmc_cs = FakeCs();
80101
let time_source = FakeTimesource();
81102
// Build an SD Card interface out of an SPI device, a chip-select pin and the delay object
82103
let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delay);

src/sdcard/mod.rs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,50 @@ use crate::{debug, warn};
2121
// Types and Implementations
2222
// ****************************************************************************
2323

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 [`DelayUs`] as well as our [`DummyCsPin`] in the constructor.
36+
///
37+
/// [`SpiDevice`]: embedded_hal::spi::SpiDevice
38+
/// [`SpiBus`]: embedded_hal::spi::SpiBus
39+
/// [`DelayUs`]: embedded_hal::delay::DelayUs
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+
2459
/// Represents an SD Card on an SPI bus.
2560
///
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.
2968
///
3069
/// All the APIs take `&self` - mutability is handled using an inner `RefCell`.
3170
pub struct SdCard<SPI, CS, DELAYER>
@@ -45,6 +84,9 @@ where
4584
{
4685
/// Create a new SD/MMC Card driver using a raw SPI interface.
4786
///
87+
/// See the docs of the [`SdCard`] struct for more information about
88+
/// how to construct the needed `SPI` and `CS` types.
89+
///
4890
/// The card will not be initialised at this time. Initialisation is
4991
/// deferred until a method is called on the object.
5092
///
@@ -55,6 +97,9 @@ where
5597

5698
/// Construct a new SD/MMC Card driver, using a raw SPI interface and the given options.
5799
///
100+
/// See the docs of the [`SdCard`] struct for more information about
101+
/// how to construct the needed `SPI` and `CS` types.
102+
///
58103
/// The card will not be initialised at this time. Initialisation is
59104
/// deferred until a method is called on the object.
60105
pub fn new_with_options(
@@ -573,9 +618,9 @@ where
573618

574619
/// Send one byte and receive one byte over the SPI bus.
575620
fn transfer_byte(&mut self, out: u8) -> Result<u8, Error> {
576-
let mut read_buf = [0u8;1];
621+
let mut read_buf = [0u8; 1];
577622
self.spi
578-
.transfer(&mut read_buf,&[out])
623+
.transfer(&mut read_buf, &[out])
579624
.map_err(|_| Error::Transport)?;
580625
Ok(read_buf[0])
581626
}
@@ -588,7 +633,9 @@ where
588633

589634
/// Send multiple bytes and replace them with what comes back over the SPI bus.
590635
fn transfer_bytes(&mut self, in_out: &mut [u8]) -> Result<(), Error> {
591-
self.spi.transfer_in_place(in_out).map_err(|_e| Error::Transport)?;
636+
self.spi
637+
.transfer_in_place(in_out)
638+
.map_err(|_e| Error::Transport)?;
592639
Ok(())
593640
}
594641

@@ -680,7 +727,7 @@ pub enum CardType {
680727
/// Uses byte-addressing internally, so limited to 2GiB in size.
681728
SD2,
682729
/// An high-capacity 'SDHC' Card.
683-
///
730+
///
684731
/// Uses block-addressing internally to support capacities above 2GiB.
685732
SDHC,
686733
}

0 commit comments

Comments
 (0)