Skip to content

Commit a64dc24

Browse files
committed
spi: add Operation::DelayUs(u32).
1 parent 30a8190 commit a64dc24

File tree

7 files changed

+77
-34
lines changed

7 files changed

+77
-34
lines changed

embedded-hal-async/src/spi.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub use embedded_hal::spi::{
88
Error, ErrorKind, ErrorType, Mode, Operation, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3,
99
};
1010

11+
use crate::delay::DelayUs;
12+
1113
/// SPI device trait
1214
///
1315
/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected
@@ -195,30 +197,32 @@ where
195197
///
196198
/// This is the most straightforward way of obtaining an [`SpiDevice`] from an [`SpiBus`],
197199
/// ideal for when no sharing is required (only one SPI device is present on the bus).
198-
pub struct ExclusiveDevice<BUS, CS> {
200+
pub struct ExclusiveDevice<BUS, CS, D> {
199201
bus: BUS,
200202
cs: CS,
203+
delay: D,
201204
}
202205

203-
impl<BUS, CS> ExclusiveDevice<BUS, CS> {
206+
impl<BUS, CS, D> ExclusiveDevice<BUS, CS, D> {
204207
/// Create a new ExclusiveDevice
205-
pub fn new(bus: BUS, cs: CS) -> Self {
206-
Self { bus, cs }
208+
pub fn new(bus: BUS, cs: CS, delay: D) -> Self {
209+
Self { bus, cs, delay }
207210
}
208211
}
209212

210-
impl<BUS, CS> ErrorType for ExclusiveDevice<BUS, CS>
213+
impl<BUS, CS, D> ErrorType for ExclusiveDevice<BUS, CS, D>
211214
where
212215
BUS: ErrorType,
213216
CS: OutputPin,
214217
{
215218
type Error = ExclusiveDeviceError<BUS::Error, CS::Error>;
216219
}
217220

218-
impl<Word: Copy + 'static, BUS, CS> blocking::SpiDevice<Word> for ExclusiveDevice<BUS, CS>
221+
impl<Word: Copy + 'static, BUS, CS, D> blocking::SpiDevice<Word> for ExclusiveDevice<BUS, CS, D>
219222
where
220223
BUS: blocking::SpiBus<Word>,
221224
CS: OutputPin,
225+
D: embedded_hal::delay::DelayUs,
222226
{
223227
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
224228
self.cs.set_low().map_err(ExclusiveDeviceError::Cs)?;
@@ -230,6 +234,10 @@ where
230234
Operation::Write(buf) => self.bus.write(buf),
231235
Operation::Transfer(read, write) => self.bus.transfer(read, write),
232236
Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf),
237+
Operation::DelayUs(us) => {
238+
self.delay.delay_us(*us);
239+
Ok(())
240+
}
233241
};
234242
if let Err(e) = res {
235243
break 'ops Err(e);
@@ -250,10 +258,11 @@ where
250258
}
251259
}
252260

253-
impl<Word: Copy + 'static, BUS, CS> SpiDevice<Word> for ExclusiveDevice<BUS, CS>
261+
impl<Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for ExclusiveDevice<BUS, CS, D>
254262
where
255263
BUS: SpiBus<Word>,
256264
CS: OutputPin,
265+
D: DelayUs,
257266
{
258267
async fn transaction(
259268
&mut self,
@@ -268,6 +277,10 @@ where
268277
Operation::Write(buf) => self.bus.write(buf).await,
269278
Operation::Transfer(read, write) => self.bus.transfer(read, write).await,
270279
Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf).await,
280+
Operation::DelayUs(us) => {
281+
self.delay.delay_us(*us).await;
282+
Ok(())
283+
}
271284
};
272285
if let Err(e) = res {
273286
break 'ops Err(e);

embedded-hal-bus/src/spi/critical_section.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use core::cell::RefCell;
22
use critical_section::Mutex;
3+
use embedded_hal::delay::DelayUs;
34
use embedded_hal::digital::OutputPin;
45
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
56

@@ -15,34 +16,35 @@ use super::DeviceError;
1516
/// The downside is critical sections typically require globally disabling interrupts, so `CriticalSectionDevice` will likely
1617
/// negatively impact real-time properties, such as interrupt latency. If you can, prefer using
1718
/// [`RefCellDevice`](super::RefCellDevice) instead, which does not require taking critical sections.
18-
pub struct CriticalSectionDevice<'a, BUS, CS> {
19-
bus: &'a Mutex<RefCell<BUS>>,
19+
pub struct CriticalSectionDevice<'a, BUS, CS, D> {
20+
bus: &'a Mutex<RefCell<(BUS, D)>>,
2021
cs: CS,
2122
}
2223

23-
impl<'a, BUS, CS> CriticalSectionDevice<'a, BUS, CS> {
24+
impl<'a, BUS, CS, D> CriticalSectionDevice<'a, BUS, CS, D> {
2425
/// Create a new ExclusiveDevice
25-
pub fn new(bus: &'a Mutex<RefCell<BUS>>, cs: CS) -> Self {
26+
pub fn new(bus: &'a Mutex<RefCell<(BUS, D)>>, cs: CS) -> Self {
2627
Self { bus, cs }
2728
}
2829
}
2930

30-
impl<'a, BUS, CS> ErrorType for CriticalSectionDevice<'a, BUS, CS>
31+
impl<'a, BUS, CS, D> ErrorType for CriticalSectionDevice<'a, BUS, CS, D>
3132
where
3233
BUS: ErrorType,
3334
CS: OutputPin,
3435
{
3536
type Error = DeviceError<BUS::Error, CS::Error>;
3637
}
3738

38-
impl<'a, Word: Copy + 'static, BUS, CS> SpiDevice<Word> for CriticalSectionDevice<'a, BUS, CS>
39+
impl<'a, Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for CriticalSectionDevice<'a, BUS, CS, D>
3940
where
4041
BUS: SpiBus<Word>,
4142
CS: OutputPin,
43+
D: DelayUs,
4244
{
4345
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
4446
critical_section::with(|cs| {
45-
let bus = &mut *self.bus.borrow_ref_mut(cs);
47+
let (bus, delay) = &mut *self.bus.borrow_ref_mut(cs);
4648

4749
self.cs.set_low().map_err(DeviceError::Cs)?;
4850

@@ -51,6 +53,10 @@ where
5153
Operation::Write(buf) => bus.write(buf),
5254
Operation::Transfer(read, write) => bus.transfer(read, write),
5355
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
56+
Operation::DelayUs(us) => {
57+
delay.delay_us(*us);
58+
Ok(())
59+
}
5460
});
5561

5662
// On failure, it's important to still flush and deassert CS.

embedded-hal-bus/src/spi/exclusive.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! SPI bus sharing mechanisms.
22
3+
use embedded_hal::delay::DelayUs;
34
use embedded_hal::digital::OutputPin;
45
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
56

@@ -9,30 +10,32 @@ use super::DeviceError;
910
///
1011
/// This is the most straightforward way of obtaining an [`SpiDevice`] from an [`SpiBus`](embedded_hal::spi::SpiBus),
1112
/// ideal for when no sharing is required (only one SPI device is present on the bus).
12-
pub struct ExclusiveDevice<BUS, CS> {
13+
pub struct ExclusiveDevice<BUS, CS, D> {
1314
bus: BUS,
1415
cs: CS,
16+
delay: D,
1517
}
1618

17-
impl<BUS, CS> ExclusiveDevice<BUS, CS> {
19+
impl<BUS, CS, D> ExclusiveDevice<BUS, CS, D> {
1820
/// Create a new ExclusiveDevice
19-
pub fn new(bus: BUS, cs: CS) -> Self {
20-
Self { bus, cs }
21+
pub fn new(bus: BUS, cs: CS, delay: D) -> Self {
22+
Self { bus, cs, delay }
2123
}
2224
}
2325

24-
impl<BUS, CS> ErrorType for ExclusiveDevice<BUS, CS>
26+
impl<BUS, CS, D> ErrorType for ExclusiveDevice<BUS, CS, D>
2527
where
2628
BUS: ErrorType,
2729
CS: OutputPin,
2830
{
2931
type Error = DeviceError<BUS::Error, CS::Error>;
3032
}
3133

32-
impl<Word: Copy + 'static, BUS, CS> SpiDevice<Word> for ExclusiveDevice<BUS, CS>
34+
impl<Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for ExclusiveDevice<BUS, CS, D>
3335
where
3436
BUS: SpiBus<Word>,
3537
CS: OutputPin,
38+
D: DelayUs,
3639
{
3740
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
3841
self.cs.set_low().map_err(DeviceError::Cs)?;
@@ -42,6 +45,10 @@ where
4245
Operation::Write(buf) => self.bus.write(buf),
4346
Operation::Transfer(read, write) => self.bus.transfer(read, write),
4447
Operation::TransferInPlace(buf) => self.bus.transfer_in_place(buf),
48+
Operation::DelayUs(us) => {
49+
self.delay.delay_us(*us);
50+
Ok(())
51+
}
4552
});
4653

4754
// On failure, it's important to still flush and deassert CS.

embedded-hal-bus/src/spi/mutex.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use embedded_hal::delay::DelayUs;
12
use embedded_hal::digital::OutputPin;
23
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
34
use std::sync::Mutex;
@@ -12,33 +13,34 @@ use super::DeviceError;
1213
/// Sharing is implemented with a `std` [`Mutex`](std::sync::Mutex). It allows a single bus across multiple threads,
1314
/// with finer-grained locking than [`CriticalSectionDevice`](super::CriticalSectionDevice). The downside is
1415
/// it is only available in `std` targets.
15-
pub struct MutexDevice<'a, BUS, CS> {
16-
bus: &'a Mutex<BUS>,
16+
pub struct MutexDevice<'a, BUS, CS, D> {
17+
bus: &'a Mutex<(BUS, D)>,
1718
cs: CS,
1819
}
1920

20-
impl<'a, BUS, CS> MutexDevice<'a, BUS, CS> {
21+
impl<'a, BUS, CS, D> MutexDevice<'a, BUS, CS, D> {
2122
/// Create a new ExclusiveDevice
22-
pub fn new(bus: &'a Mutex<BUS>, cs: CS) -> Self {
23+
pub fn new(bus: &'a Mutex<(BUS, D)>, cs: CS) -> Self {
2324
Self { bus, cs }
2425
}
2526
}
2627

27-
impl<'a, BUS, CS> ErrorType for MutexDevice<'a, BUS, CS>
28+
impl<'a, BUS, CS, D> ErrorType for MutexDevice<'a, BUS, CS, D>
2829
where
2930
BUS: ErrorType,
3031
CS: OutputPin,
3132
{
3233
type Error = DeviceError<BUS::Error, CS::Error>;
3334
}
3435

35-
impl<'a, Word: Copy + 'static, BUS, CS> SpiDevice<Word> for MutexDevice<'a, BUS, CS>
36+
impl<'a, Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for MutexDevice<'a, BUS, CS, D>
3637
where
3738
BUS: SpiBus<Word>,
3839
CS: OutputPin,
40+
D: DelayUs,
3941
{
4042
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
41-
let bus = &mut *self.bus.lock().unwrap();
43+
let (bus, delay) = &mut *self.bus.lock().unwrap();
4244

4345
self.cs.set_low().map_err(DeviceError::Cs)?;
4446

@@ -47,6 +49,10 @@ where
4749
Operation::Write(buf) => bus.write(buf),
4850
Operation::Transfer(read, write) => bus.transfer(read, write),
4951
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
52+
Operation::DelayUs(us) => {
53+
delay.delay_us(*us);
54+
Ok(())
55+
}
5056
});
5157

5258
// On failure, it's important to still flush and deassert CS.

embedded-hal-bus/src/spi/refcell.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use core::cell::RefCell;
2+
use embedded_hal::delay::DelayUs;
23
use embedded_hal::digital::OutputPin;
34
use embedded_hal::spi::{ErrorType, Operation, SpiBus, SpiDevice};
45

@@ -12,33 +13,34 @@ use super::DeviceError;
1213
/// Sharing is implemented with a `RefCell`. This means it has low overhead, but `RefCellDevice` instances are not `Send`,
1314
/// so it only allows sharing within a single thread (interrupt priority level). If you need to share a bus across several
1415
/// threads, use [`CriticalSectionDevice`](super::CriticalSectionDevice) instead.
15-
pub struct RefCellDevice<'a, BUS, CS> {
16-
bus: &'a RefCell<BUS>,
16+
pub struct RefCellDevice<'a, BUS, CS, D> {
17+
bus: &'a RefCell<(BUS, D)>,
1718
cs: CS,
1819
}
1920

20-
impl<'a, BUS, CS> RefCellDevice<'a, BUS, CS> {
21+
impl<'a, BUS, CS, D> RefCellDevice<'a, BUS, CS, D> {
2122
/// Create a new ExclusiveDevice
22-
pub fn new(bus: &'a RefCell<BUS>, cs: CS) -> Self {
23+
pub fn new(bus: &'a RefCell<(BUS, D)>, cs: CS) -> Self {
2324
Self { bus, cs }
2425
}
2526
}
2627

27-
impl<'a, BUS, CS> ErrorType for RefCellDevice<'a, BUS, CS>
28+
impl<'a, BUS, CS, D> ErrorType for RefCellDevice<'a, BUS, CS, D>
2829
where
2930
BUS: ErrorType,
3031
CS: OutputPin,
3132
{
3233
type Error = DeviceError<BUS::Error, CS::Error>;
3334
}
3435

35-
impl<'a, Word: Copy + 'static, BUS, CS> SpiDevice<Word> for RefCellDevice<'a, BUS, CS>
36+
impl<'a, Word: Copy + 'static, BUS, CS, D> SpiDevice<Word> for RefCellDevice<'a, BUS, CS, D>
3637
where
3738
BUS: SpiBus<Word>,
3839
CS: OutputPin,
40+
D: DelayUs,
3941
{
4042
fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
41-
let bus = &mut *self.bus.borrow_mut();
43+
let (bus, delay) = &mut *self.bus.borrow_mut();
4244

4345
self.cs.set_low().map_err(DeviceError::Cs)?;
4446

@@ -47,6 +49,10 @@ where
4749
Operation::Write(buf) => bus.write(buf),
4850
Operation::Transfer(read, write) => bus.transfer(read, write),
4951
Operation::TransferInPlace(buf) => bus.transfer_in_place(buf),
52+
Operation::DelayUs(us) => {
53+
delay.delay_us(*us);
54+
Ok(())
55+
}
5056
});
5157

5258
// On failure, it's important to still flush and deassert CS.

embedded-hal/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
- spi: added `Operation::DelayUs(u32)`.
12+
1013
### Removed
1114
- spi: removed read-only and write-only traits.
1215

embedded-hal/src/spi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ pub enum Operation<'a, Word: 'static> {
313313
///
314314
/// Equivalent to [`SpiBus::transfer_in_place`].
315315
TransferInPlace(&'a mut [Word]),
316+
/// Delay for at least the specified number of microseconds
317+
DelayUs(u32),
316318
}
317319

318320
/// SPI device trait

0 commit comments

Comments
 (0)