Skip to content

Commit e7ef46f

Browse files
Merge pull request #106 from AnyTimeTraveler/update-embedded-hal
Update embedded hal to 1.0.0
2 parents 3b5c026 + 959b670 commit e7ef46f

File tree

4 files changed

+141
-99
lines changed

4 files changed

+141
-99
lines changed

Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ version = "0.6.0"
1313
[dependencies]
1414
byteorder = {version = "1", default-features = false}
1515
defmt = {version = "0.3", optional = true}
16-
embedded-hal = "0.2.3"
16+
embedded-hal = "1.0.0"
1717
heapless = "0.7"
1818
log = {version = "0.4", default-features = false, optional = true}
1919

2020
[dev-dependencies]
21-
env_logger = "0.9"
22-
hex-literal = "0.3"
21+
env_logger = "0.10.0"
22+
hex-literal = "0.4.1"
2323
flate2 = "1.0"
2424
sha2 = "0.10"
2525
chrono = "0.4"
26+
embedded-hal-bus = "0.1.0"
2627

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

examples/readme_test.rs

Lines changed: 38 additions & 14 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::blocking::spi::Transfer<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::blocking::spi::Write<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::v2::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,11 +51,12 @@ impl embedded_hal::digital::v2::OutputPin for FakeCs {
3251
}
3352
}
3453

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

37-
impl embedded_hal::blocking::delay::DelayUs<u8> for FakeDelayer {
38-
fn delay_us(&mut self, us: u8) {
39-
std::thread::sleep(std::time::Duration::from_micros(u64::from(us)));
57+
impl embedded_hal::delay::DelayNs for FakeDelayer {
58+
fn delay_ns(&mut self, ns: u32) {
59+
std::thread::sleep(std::time::Duration::from_nanos(u64::from(ns)));
4060
}
4161
}
4262

@@ -74,10 +94,14 @@ 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+
// BEGIN Fake stuff that will be replaced with real peripherals
98+
let spi_bus = RefCell::new(FakeSpiBus());
7999
let delay = FakeDelayer();
100+
let sdmmc_spi = embedded_hal_bus::spi::RefCellDevice::new(&spi_bus, DummyCsPin, delay);
101+
let sdmmc_cs = FakeCs();
80102
let time_source = FakeTimesource();
103+
// END Fake stuff that will be replaced with real peripherals
104+
81105
// Build an SD Card interface out of an SPI device, a chip-select pin and the delay object
82106
let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delay);
83107
// Get the card size (this also triggers card initialisation because it's not been done yet)

src/lib.rs

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,55 +16,32 @@
1616
//! couldn't work with a USB Thumb Drive, but we only supply a `BlockDevice`
1717
//! suitable for reading SD and SDHC cards over SPI.
1818
//!
19-
//! ```rust,no_run
20-
//! # struct DummySpi;
21-
//! # struct DummyCsPin;
22-
//! # struct DummyUart;
23-
//! # struct DummyTimeSource;
24-
//! # struct DummyDelayer;
25-
//! # impl embedded_hal::blocking::spi::Transfer<u8> for DummySpi {
26-
//! # type Error = ();
27-
//! # fn transfer<'w>(&mut self, data: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { Ok(&[0]) }
28-
//! # }
29-
//! # impl embedded_hal::blocking::spi::Write<u8> for DummySpi {
30-
//! # type Error = ();
31-
//! # fn write(&mut self, data: &[u8]) -> Result<(), Self::Error> { Ok(()) }
32-
//! # }
33-
//! # impl embedded_hal::digital::v2::OutputPin for DummyCsPin {
34-
//! # type Error = ();
35-
//! # fn set_low(&mut self) -> Result<(), ()> { Ok(()) }
36-
//! # fn set_high(&mut self) -> Result<(), ()> { Ok(()) }
37-
//! # }
38-
//! # impl embedded_sdmmc::TimeSource for DummyTimeSource {
39-
//! # fn get_timestamp(&self) -> embedded_sdmmc::Timestamp { embedded_sdmmc::Timestamp::from_fat(0, 0) }
40-
//! # }
41-
//! # impl embedded_hal::blocking::delay::DelayUs<u8> for DummyDelayer {
42-
//! # fn delay_us(&mut self, us: u8) {}
43-
//! # }
44-
//! # impl std::fmt::Write for DummyUart { fn write_str(&mut self, s: &str) -> std::fmt::Result { Ok(()) } }
45-
//! # use std::fmt::Write;
46-
//! # use embedded_sdmmc::VolumeManager;
47-
//! # fn main() -> Result<(), embedded_sdmmc::Error<embedded_sdmmc::SdCardError>> {
48-
//! # let mut sdmmc_spi = DummySpi;
49-
//! # let mut sdmmc_cs = DummyCsPin;
50-
//! # let time_source = DummyTimeSource;
51-
//! # let delayer = DummyDelayer;
52-
//! let sdcard = embedded_sdmmc::SdCard::new(sdmmc_spi, sdmmc_cs, delayer);
53-
//! println!("Card size is {} bytes", sdcard.num_bytes()?);
54-
//! let mut volume_mgr = embedded_sdmmc::VolumeManager::new(sdcard, time_source);
55-
//! let mut volume0 = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0))?;
56-
//! println!("Volume 0: {:?}", volume0);
57-
//! let mut root_dir = volume0.open_root_dir()?;
58-
//! let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", embedded_sdmmc::Mode::ReadOnly)?;
59-
//! while !my_file.is_eof() {
60-
//! let mut buffer = [0u8; 32];
61-
//! let num_read = my_file.read(&mut buffer)?;
62-
//! for b in &buffer[0..num_read] {
63-
//! print!("{}", *b as char);
19+
//! ```rust
20+
//! use embedded_sdmmc::{Error, Mode, SdCard, SdCardError, TimeSource, VolumeIdx, VolumeManager};
21+
//!
22+
//! fn example<S, CS, D, T>(spi: S, cs: CS, delay: D, ts: T) -> Result<(), Error<SdCardError>>
23+
//! where
24+
//! S: embedded_hal::spi::SpiDevice,
25+
//! CS: embedded_hal::digital::OutputPin,
26+
//! D: embedded_hal::delay::DelayNs,
27+
//! T: TimeSource,
28+
//! {
29+
//! let sdcard = SdCard::new(spi, cs, delay);
30+
//! println!("Card size is {} bytes", sdcard.num_bytes()?);
31+
//! let mut volume_mgr = VolumeManager::new(sdcard, ts);
32+
//! let mut volume0 = volume_mgr.open_volume(VolumeIdx(0))?;
33+
//! println!("Volume 0: {:?}", volume0);
34+
//! let mut root_dir = volume0.open_root_dir()?;
35+
//! let mut my_file = root_dir.open_file_in_dir("MY_FILE.TXT", Mode::ReadOnly)?;
36+
//! while !my_file.is_eof() {
37+
//! let mut buffer = [0u8; 32];
38+
//! let num_read = my_file.read(&mut buffer)?;
39+
//! for b in &buffer[0..num_read] {
40+
//! print!("{}", *b as char);
41+
//! }
6442
//! }
43+
//! Ok(())
6544
//! }
66-
//! # Ok(())
67-
//! # }
6845
//! ```
6946
//!
7047
//! ## Features

src/sdcard/mod.rs

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,74 @@ 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 [`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+
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`.
70+
///
71+
/// [`SpiDevice`]: embedded_hal::spi::SpiDevice
3172
pub struct SdCard<SPI, CS, DELAYER>
3273
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,
3877
{
3978
inner: RefCell<SdCardInner<SPI, CS, DELAYER>>,
4079
}
4180

4281
impl<SPI, CS, DELAYER> SdCard<SPI, CS, DELAYER>
4382
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,
4986
{
5087
/// Create a new SD/MMC Card driver using a raw SPI interface.
5188
///
89+
/// See the docs of the [`SdCard`] struct for more information about
90+
/// how to construct the needed `SPI` and `CS` types.
91+
///
5292
/// The card will not be initialised at this time. Initialisation is
5393
/// deferred until a method is called on the object.
5494
///
@@ -59,6 +99,9 @@ where
5999

60100
/// Construct a new SD/MMC Card driver, using a raw SPI interface and the given options.
61101
///
102+
/// See the docs of the [`SdCard`] struct for more information about
103+
/// how to construct the needed `SPI` and `CS` types.
104+
///
62105
/// The card will not be initialised at this time. Initialisation is
63106
/// deferred until a method is called on the object.
64107
pub fn new_with_options(
@@ -152,11 +195,9 @@ where
152195

153196
impl<SPI, CS, DELAYER> BlockDevice for SdCard<SPI, CS, DELAYER>
154197
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,
160201
{
161202
type Error = Error;
162203

@@ -205,11 +246,9 @@ where
205246
/// All the APIs required `&mut self`.
206247
struct SdCardInner<SPI, CS, DELAYER>
207248
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,
213252
{
214253
spi: SPI,
215254
cs: CS,
@@ -220,11 +259,9 @@ where
220259

221260
impl<SPI, CS, DELAYER> SdCardInner<SPI, CS, DELAYER>
222261
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,
228265
{
229266
/// Read one or more blocks, starting at the given block index.
230267
fn read(&mut self, blocks: &mut [Block], start_block_idx: BlockIdx) -> Result<(), Error> {
@@ -583,21 +620,24 @@ where
583620

584621
/// Send one byte and receive one byte over the SPI bus.
585622
fn transfer_byte(&mut self, out: u8) -> Result<u8, Error> {
623+
let mut read_buf = [0u8; 1];
586624
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])
590628
}
591629

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.
593631
fn write_bytes(&mut self, out: &[u8]) -> Result<(), Error> {
594632
self.spi.write(out).map_err(|_e| Error::Transport)?;
595633
Ok(())
596634
}
597635

598636
/// Send multiple bytes and replace them with what comes back over the SPI bus.
599637
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)?;
601641
Ok(())
602642
}
603643

@@ -689,7 +729,7 @@ pub enum CardType {
689729
/// Uses byte-addressing internally, so limited to 2GiB in size.
690730
SD2,
691731
/// An high-capacity 'SDHC' Card.
692-
///
732+
///
693733
/// Uses block-addressing internally to support capacities above 2GiB.
694734
SDHC,
695735
}
@@ -753,7 +793,7 @@ impl Delay {
753793
/// `Ok(())`.
754794
fn delay<T>(&mut self, delayer: &mut T, err: Error) -> Result<(), Error>
755795
where
756-
T: embedded_hal::blocking::delay::DelayUs<u8>,
796+
T: embedded_hal::delay::DelayNs,
757797
{
758798
if self.retries_left == 0 {
759799
Err(err)

0 commit comments

Comments
 (0)