Skip to content

Commit 9520962

Browse files
committed
spi: allow impls returning early, add flush. Fixes #264
1 parent e42923f commit 9520962

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
1111
- The Minimum Supported Rust Version (MSRV) is now 1.54.0
1212
- `spi`: unify all traits into `SpiReadBus`, `SpiWriteBus` and `SpiBus` (read-write).
1313
- `spi`: Add `SpiDevice` trait to represent a single device in a (possibly shared) bus, with managed chip-select (CS) pin.
14+
- `spi`: Clarify that implementations are allowed to return before operations are finished, add `flush` to wait until finished.
1415

1516
## [v1.0.0-alpha.7] - 2022-02-09
1617

src/spi/blocking.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,23 @@
140140
//!
141141
//! HALs **must not** add infrastructure for sharing at the [`SpiBus`] level. User code owning a [`SpiBus`] must have the guarantee
142142
//! of exclusive access.
143+
//!
144+
//! # Flushing
145+
//!
146+
//! To improve performance, Bus implementations are allowed to return before the operation is finished, i.e. when the bus is still not
147+
//! idle. You must call [`flush`](SpiBusFlush::flush) to wait for operations to actually finish, for example before deasserting CS in a
148+
//! [`SpiDevice`] implementation, or before deinitializing the hardware SPI peripheral.
149+
//!
150+
//! For example, for [`write`](SpiBusWrite::write) operations, it is common for hardware SPI peripherals to have a small
151+
//! FIFO buffer, usually 1-4 bytes. Software writes data to the FIFO, and the peripheral sends it on MOSI at its own pace,
152+
//! at the specified SPI frequency. It is allowed for an implementation of [`write`](SpiBusWrite::write) to return as soon
153+
//! as all the data has been written to the FIFO, before it is actually sent. Calling [`flush`](SpiBusFlush::flush) would
154+
//! wait until all the bits have actually been sent, the FIFO is empty, and the bus is idle.
155+
//!
156+
//! This still applies to other operations such as [`read`](SpiBusRead::read) or [`transfer`](SpiBus::transfer). It is less obvious
157+
//! why, because these methods can't return before receiving all the read data. However it's still technically possible
158+
//! for them to return before the bus is idle. For example, assuming SPI mode 0, the last bit is sampled on the first (rising) edge
159+
//! of SCK, at which point a method could return, but the second (falling) SCK edge still has to happen before the bus is idle.
143160
144161
use core::fmt::Debug;
145162

@@ -162,6 +179,7 @@ pub trait SpiDevice: ErrorType {
162179
/// - Locks the bus
163180
/// - Asserts the CS (Chip Select) pin.
164181
/// - Calls `f` with an exclusive reference to the bus, which can then be used to do transfers against the device.
182+
/// - [Flushes](SpiBusFlush::flush) the bus.
165183
/// - Deasserts the CS pin.
166184
/// - Unlocks the bus.
167185
///
@@ -184,12 +202,29 @@ impl<T: SpiDevice> SpiDevice for &mut T {
184202
}
185203
}
186204

205+
/// Flush support for SPI bus
206+
pub trait SpiBusFlush: ErrorType {
207+
/// Blocks until all operations have completed and the bus is idle.
208+
///
209+
/// See the [module-level documentation](self) for important usage information.
210+
fn flush(&mut self) -> Result<(), Self::Error>;
211+
}
212+
213+
impl<T: SpiBusFlush> SpiBusFlush for &mut T {
214+
fn flush(&mut self) -> Result<(), Self::Error> {
215+
T::flush(self)
216+
}
217+
}
218+
187219
/// Read-only SPI bus
188-
pub trait SpiBusRead<Word: Copy = u8>: ErrorType {
220+
pub trait SpiBusRead<Word: Copy = u8>: SpiBusFlush {
189221
/// Reads `words` from the slave.
190222
///
191223
/// The word value sent on MOSI during reading is implementation-defined,
192224
/// typically `0x00`, `0xFF`, or configurable.
225+
///
226+
/// Implementations are allowed to return before the operation is
227+
/// complete. See the [module-level documentation](self) for detials.
193228
fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
194229
}
195230

@@ -200,8 +235,11 @@ impl<T: SpiBusRead<Word>, Word: Copy> SpiBusRead<Word> for &mut T {
200235
}
201236

202237
/// Write-only SPI bus
203-
pub trait SpiBusWrite<Word: Copy = u8>: ErrorType {
238+
pub trait SpiBusWrite<Word: Copy = u8>: SpiBusFlush {
204239
/// Writes `words` to the slave, ignoring all the incoming words
240+
///
241+
/// Implementations are allowed to return before the operation is
242+
/// complete. See the [module-level documentation](self) for detials.
205243
fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
206244
}
207245

@@ -225,11 +263,17 @@ pub trait SpiBus<Word: Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> {
225263
/// incoming words after `read` has been filled will be discarded. If `write` is shorter,
226264
/// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
227265
/// typically `0x00`, `0xFF`, or configurable.
266+
///
267+
/// Implementations are allowed to return before the operation is
268+
/// complete. See the [module-level documentation](self) for detials.
228269
fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
229270

230271
/// Writes and reads simultaneously. The contents of `words` are
231272
/// written to the slave, and the received words are stored into the same
232273
/// `words` buffer, overwriting it.
274+
///
275+
/// Implementations are allowed to return before the operation is
276+
/// complete. See the [module-level documentation](self) for detials.
233277
fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
234278
}
235279

@@ -283,15 +327,15 @@ impl<BUS, CS> ExclusiveDevice<BUS, CS> {
283327

284328
impl<BUS, CS> ErrorType for ExclusiveDevice<BUS, CS>
285329
where
286-
BUS: ErrorType,
330+
BUS: SpiBusFlush,
287331
CS: OutputPin,
288332
{
289333
type Error = ExclusiveDeviceError<BUS::Error, CS::Error>;
290334
}
291335

292336
impl<BUS, CS> SpiDevice for ExclusiveDevice<BUS, CS>
293337
where
294-
BUS: ErrorType,
338+
BUS: SpiBusFlush,
295339
CS: OutputPin,
296340
{
297341
type Bus = BUS;
@@ -304,10 +348,12 @@ where
304348

305349
let f_res = f(&mut self.bus);
306350

307-
// If the closure fails, it's important to still deassert CS.
351+
// On failure, it's important to still flush and deassert CS.
352+
let flush_res = self.bus.flush();
308353
let cs_res = self.cs.set_high();
309354

310355
let f_res = f_res.map_err(ExclusiveDeviceError::Spi)?;
356+
flush_res.map_err(ExclusiveDeviceError::Spi)?;
311357
cs_res.map_err(ExclusiveDeviceError::Cs)?;
312358

313359
Ok(f_res)

0 commit comments

Comments
 (0)