140
140
//!
141
141
//! HALs **must not** add infrastructure for sharing at the [`SpiBus`] level. User code owning a [`SpiBus`] must have the guarantee
142
142
//! 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.
143
160
144
161
use core:: fmt:: Debug ;
145
162
@@ -162,6 +179,7 @@ pub trait SpiDevice: ErrorType {
162
179
/// - Locks the bus
163
180
/// - Asserts the CS (Chip Select) pin.
164
181
/// - 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.
165
183
/// - Deasserts the CS pin.
166
184
/// - Unlocks the bus.
167
185
///
@@ -232,12 +250,29 @@ impl<T: SpiDevice> SpiDevice for &mut T {
232
250
}
233
251
}
234
252
253
+ /// Flush support for SPI bus
254
+ pub trait SpiBusFlush : ErrorType {
255
+ /// Blocks until all operations have completed and the bus is idle.
256
+ ///
257
+ /// See the [module-level documentation](self) for important usage information.
258
+ fn flush ( & mut self ) -> Result < ( ) , Self :: Error > ;
259
+ }
260
+
261
+ impl < T : SpiBusFlush > SpiBusFlush for & mut T {
262
+ fn flush ( & mut self ) -> Result < ( ) , Self :: Error > {
263
+ T :: flush ( self )
264
+ }
265
+ }
266
+
235
267
/// Read-only SPI bus
236
- pub trait SpiBusRead < Word : Copy = u8 > : ErrorType {
268
+ pub trait SpiBusRead < Word : Copy = u8 > : SpiBusFlush {
237
269
/// Reads `words` from the slave.
238
270
///
239
271
/// The word value sent on MOSI during reading is implementation-defined,
240
272
/// typically `0x00`, `0xFF`, or configurable.
273
+ ///
274
+ /// Implementations are allowed to return before the operation is
275
+ /// complete. See the [module-level documentation](self) for detials.
241
276
fn read ( & mut self , words : & mut [ Word ] ) -> Result < ( ) , Self :: Error > ;
242
277
}
243
278
@@ -248,8 +283,11 @@ impl<T: SpiBusRead<Word>, Word: Copy> SpiBusRead<Word> for &mut T {
248
283
}
249
284
250
285
/// Write-only SPI bus
251
- pub trait SpiBusWrite < Word : Copy = u8 > : ErrorType {
286
+ pub trait SpiBusWrite < Word : Copy = u8 > : SpiBusFlush {
252
287
/// Writes `words` to the slave, ignoring all the incoming words
288
+ ///
289
+ /// Implementations are allowed to return before the operation is
290
+ /// complete. See the [module-level documentation](self) for detials.
253
291
fn write ( & mut self , words : & [ Word ] ) -> Result < ( ) , Self :: Error > ;
254
292
}
255
293
@@ -273,11 +311,17 @@ pub trait SpiBus<Word: Copy = u8>: SpiBusRead<Word> + SpiBusWrite<Word> {
273
311
/// incoming words after `read` has been filled will be discarded. If `write` is shorter,
274
312
/// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
275
313
/// typically `0x00`, `0xFF`, or configurable.
314
+ ///
315
+ /// Implementations are allowed to return before the operation is
316
+ /// complete. See the [module-level documentation](self) for detials.
276
317
fn transfer ( & mut self , read : & mut [ Word ] , write : & [ Word ] ) -> Result < ( ) , Self :: Error > ;
277
318
278
319
/// Writes and reads simultaneously. The contents of `words` are
279
320
/// written to the slave, and the received words are stored into the same
280
321
/// `words` buffer, overwriting it.
322
+ ///
323
+ /// Implementations are allowed to return before the operation is
324
+ /// complete. See the [module-level documentation](self) for detials.
281
325
fn transfer_in_place ( & mut self , words : & mut [ Word ] ) -> Result < ( ) , Self :: Error > ;
282
326
}
283
327
@@ -331,15 +375,15 @@ impl<BUS, CS> ExclusiveDevice<BUS, CS> {
331
375
332
376
impl < BUS , CS > ErrorType for ExclusiveDevice < BUS , CS >
333
377
where
334
- BUS : ErrorType ,
378
+ BUS : SpiBusFlush ,
335
379
CS : OutputPin ,
336
380
{
337
381
type Error = ExclusiveDeviceError < BUS :: Error , CS :: Error > ;
338
382
}
339
383
340
384
impl < BUS , CS > SpiDevice for ExclusiveDevice < BUS , CS >
341
385
where
342
- BUS : ErrorType ,
386
+ BUS : SpiBusFlush ,
343
387
CS : OutputPin ,
344
388
{
345
389
type Bus = BUS ;
@@ -352,10 +396,12 @@ where
352
396
353
397
let f_res = f ( & mut self . bus ) ;
354
398
355
- // If the closure fails, it's important to still deassert CS.
399
+ // On failure, it's important to still flush and deassert CS.
400
+ let flush_res = self . bus . flush ( ) ;
356
401
let cs_res = self . cs . set_high ( ) ;
357
402
358
403
let f_res = f_res. map_err ( ExclusiveDeviceError :: Spi ) ?;
404
+ flush_res. map_err ( ExclusiveDeviceError :: Spi ) ?;
359
405
cs_res. map_err ( ExclusiveDeviceError :: Cs ) ?;
360
406
361
407
Ok ( f_res)
0 commit comments