embedded_hal/
spi.rs

1//! Blocking SPI master mode traits.
2//!
3//! # Bus vs Device
4//!
5//! SPI allows sharing a single bus between many SPI devices. The SCK, MOSI and MISO lines are
6//! wired in parallel to all the devices, and each device gets a dedicated chip-select (CS) line from the MCU, like this:
7//!
8#![doc= include_str!("spi-shared-bus.svg")]
9//!
10//! CS is usually active-low. When CS is high (not asserted), SPI devices ignore all incoming data, and
11//! don't drive MISO. When CS is low (asserted), the device is active: reacts to incoming data on MOSI and
12//! drives MISO with the response data. By asserting one CS or another, the MCU can choose to which
13//! SPI device it "talks" to on the (possibly shared) bus.
14//!
15//! This bus sharing is common when having multiple SPI devices in the same board, since it uses fewer MCU
16//! pins (`n+3` instead of `4*n`), and fewer MCU SPI peripherals (`1` instead of `n`).
17//!
18//! However, it poses a challenge when building portable drivers for SPI devices. The driver needs to
19//! be able to talk to its device on the bus, while not interfering with other drivers talking to other
20//! devices.
21//!
22//! To solve this, `embedded-hal` has two kinds of SPI traits: **SPI bus** and **SPI device**.
23//!
24//! ## Bus
25//!
26//! The [`SpiBus`] trait represents **exclusive ownership** over the whole SPI bus. This is usually the entire
27//! SPI MCU peripheral, plus the SCK, MOSI and MISO pins.
28//!
29//! Owning an instance of an SPI bus guarantees exclusive access, this is, we have the guarantee no other
30//! piece of code will try to use the bus while we own it.
31//!
32//! ## Device
33//!
34//! The [`SpiDevice`] trait represents **ownership over a single SPI device selected by a CS pin** in a (possibly shared) bus. This is typically:
35//!
36//! - Exclusive ownership of the **CS pin**.
37//! - Access to the **underlying SPI bus**. If shared, it'll be behind some kind of lock/mutex.
38//!
39//! An [`SpiDevice`] allows initiating [transactions](SpiDevice::transaction) against the target device on the bus. A transaction
40//! consists of asserting CS, then doing one or more transfers, then deasserting CS. For the entire duration of the transaction, the [`SpiDevice`]
41//! implementation will ensure no other transaction can be opened on the same bus. This is the key that allows correct sharing of the bus.
42//!
43//! # For driver authors
44//!
45//! When implementing a driver, it's crucial to pick the right trait, to ensure correct operation
46//! with maximum interoperability. Here are some guidelines depending on the device you're implementing a driver for:
47//!
48//! If your device **has a CS pin**, use [`SpiDevice`]. Do not manually
49//! manage the CS pin, the [`SpiDevice`] implementation will do it for you.
50//! By using [`SpiDevice`], your driver will cooperate nicely with other drivers for other devices in the same shared SPI bus.
51//!
52//! ```
53//! # use embedded_hal::spi::{SpiBus, SpiDevice, Operation};
54//! pub struct MyDriver<SPI> {
55//!     spi: SPI,
56//! }
57//!
58//! impl<SPI> MyDriver<SPI>
59//! where
60//!     SPI: SpiDevice,
61//! {
62//!     pub fn new(spi: SPI) -> Self {
63//!         Self { spi }
64//!     }
65//!
66//!     pub fn read_foo(&mut self) -> Result<[u8; 2], MyError<SPI::Error>> {
67//!         let mut buf = [0; 2];
68//!
69//!         // `transaction` asserts and deasserts CS for us. No need to do it manually!
70//!         self.spi.transaction(&mut [
71//!             Operation::Write(&[0x90]),
72//!             Operation::Read(&mut buf),
73//!         ]).map_err(MyError::Spi)?;
74//!
75//!         Ok(buf)
76//!     }
77//! }
78//!
79//! #[derive(Copy, Clone, Debug)]
80//! enum MyError<SPI> {
81//!     Spi(SPI),
82//!     // Add other errors for your driver here.
83//! }
84//! ```
85//!
86//! If your device **does not have a CS pin**, use [`SpiBus`]. This will ensure
87//! your driver has exclusive access to the bus, so no other drivers can interfere. It's not possible to safely share
88//! a bus without CS pins. By requiring [`SpiBus`] you disallow sharing, ensuring correct operation.
89//!
90//! ```
91//! # use embedded_hal::spi::SpiBus;
92//! pub struct MyDriver<SPI> {
93//!     spi: SPI,
94//! }
95//!
96//! impl<SPI> MyDriver<SPI>
97//! where
98//!     SPI: SpiBus,
99//! {
100//!     pub fn new(spi: SPI) -> Self {
101//!         Self { spi }
102//!     }
103//!
104//!     pub fn read_foo(&mut self) -> Result<[u8; 2], MyError<SPI::Error>> {
105//!         let mut buf = [0; 2];
106//!         self.spi.write(&[0x90]).map_err(MyError::Spi)?;
107//!         self.spi.read(&mut buf).map_err(MyError::Spi)?;
108//!         Ok(buf)
109//!     }
110//! }
111//!
112//! #[derive(Copy, Clone, Debug)]
113//! enum MyError<SPI> {
114//!     Spi(SPI),
115//!     // Add other errors for your driver here.
116//! }
117//! ```
118//!
119//! If you're (ab)using SPI to **implement other protocols** by bitbanging (WS2812B, onewire, generating arbitrary waveforms...), use [`SpiBus`].
120//! SPI bus sharing doesn't make sense at all in this case. By requiring [`SpiBus`] you disallow sharing, ensuring correct operation.
121//!
122//! # For HAL authors
123//!
124//! HALs **must** implement [`SpiBus`]. Users can combine the bus together with the CS pin (which should
125//! implement [`OutputPin`](crate::digital::OutputPin)) using HAL-independent [`SpiDevice`] implementations such as the ones in [`embedded-hal-bus`](https://crates.io/crates/embedded-hal-bus).
126//!
127//! HALs may additionally implement [`SpiDevice`] to **take advantage of hardware CS management**, which may provide some performance
128//! benefits. (There's no point in a HAL implementing [`SpiDevice`] if the CS management is software-only, this task is better left to
129//! the HAL-independent implementations).
130//!
131//! HALs **must not** add infrastructure for sharing at the [`SpiBus`] level. User code owning a [`SpiBus`] must have the guarantee
132//! of exclusive access.
133//!
134//! # Flushing
135//!
136//! To improve performance, [`SpiBus`] implementations are allowed to return before the operation is finished, i.e. when the bus is still not
137//! idle. This allows pipelining SPI transfers with CPU work.
138//!
139//! When calling another method when a previous operation is still in progress, implementations can either wait for the previous operation
140//! to finish, or enqueue the new one, but they must not return a "busy" error. Users must be able to do multiple method calls in a row
141//! and have them executed "as if" they were done sequentially, without having to check for "busy" errors.
142//!
143//! When using a [`SpiBus`], call [`flush`](SpiBus::flush) to wait for operations to actually finish. Examples of situations
144//! where this is needed are:
145//! - To synchronize SPI activity and GPIO activity, for example before deasserting a CS pin.
146//! - Before deinitializing the hardware SPI peripheral.
147//!
148//! When using a [`SpiDevice`], you can still call [`flush`](SpiBus::flush) on the bus within a transaction.
149//! It's very rarely needed, because [`transaction`](SpiDevice::transaction) already flushes for you
150//! before deasserting CS. For example, you may need it to synchronize with GPIOs other than CS, such as DCX pins
151//! sometimes found in SPI displays.
152//!
153//! For example, for [`write`](SpiBus::write) operations, it is common for hardware SPI peripherals to have a small
154//! FIFO buffer, usually 1-4 bytes. Software writes data to the FIFO, and the peripheral sends it on MOSI at its own pace,
155//! at the specified SPI frequency. It is allowed for an implementation of [`write`](SpiBus::write) to return as soon
156//! as all the data has been written to the FIFO, before it is actually sent. Calling [`flush`](SpiBus::flush) would
157//! wait until all the bits have actually been sent, the FIFO is empty, and the bus is idle.
158//!
159//! This still applies to other operations such as [`read`](SpiBus::read) or [`transfer`](SpiBus::transfer). It is less obvious
160//! why, because these methods can't return before receiving all the read data. However it's still technically possible
161//! 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
162//! of SCK, at which point a method could return, but the second (falling) SCK edge still has to happen before the bus is idle.
163//!
164//! # CS-to-clock delays
165//!
166//! Many chips require a minimum delay between asserting CS and the first SCK edge, and the last SCK edge and deasserting CS.
167//! Drivers should *NOT* use [`Operation::DelayNs`] for this, they should instead document that the user should configure the
168//! delays when creating the `SpiDevice` instance, same as they have to configure the SPI frequency and mode. This has a few advantages:
169//!
170//! - Allows implementations that use hardware-managed CS to program the delay in hardware
171//! - Allows the end user more flexibility. For example, they can choose to not configure any delay if their MCU is slow
172//!   enough to "naturally" do the delay (very common if the delay is in the order of nanoseconds).
173
174use core::fmt::Debug;
175
176#[cfg(feature = "defmt-03")]
177use crate::defmt;
178
179/// Clock polarity.
180#[derive(Clone, Copy, Debug, PartialEq, Eq)]
181#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
182pub enum Polarity {
183    /// Clock signal low when idle.
184    IdleLow,
185    /// Clock signal high when idle.
186    IdleHigh,
187}
188
189/// Clock phase.
190#[derive(Clone, Copy, Debug, PartialEq, Eq)]
191#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
192pub enum Phase {
193    /// Data in "captured" on the first clock transition.
194    CaptureOnFirstTransition,
195    /// Data in "captured" on the second clock transition.
196    CaptureOnSecondTransition,
197}
198
199/// SPI mode.
200#[derive(Clone, Copy, Debug, PartialEq, Eq)]
201#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
202pub struct Mode {
203    /// Clock polarity.
204    pub polarity: Polarity,
205    /// Clock phase.
206    pub phase: Phase,
207}
208
209/// Helper for CPOL = 0, CPHA = 0.
210pub const MODE_0: Mode = Mode {
211    polarity: Polarity::IdleLow,
212    phase: Phase::CaptureOnFirstTransition,
213};
214
215/// Helper for CPOL = 0, CPHA = 1.
216pub const MODE_1: Mode = Mode {
217    polarity: Polarity::IdleLow,
218    phase: Phase::CaptureOnSecondTransition,
219};
220
221/// Helper for CPOL = 1, CPHA = 0.
222pub const MODE_2: Mode = Mode {
223    polarity: Polarity::IdleHigh,
224    phase: Phase::CaptureOnFirstTransition,
225};
226
227/// Helper for CPOL = 1, CPHA = 1.
228pub const MODE_3: Mode = Mode {
229    polarity: Polarity::IdleHigh,
230    phase: Phase::CaptureOnSecondTransition,
231};
232
233/// SPI error.
234pub trait Error: Debug {
235    /// Convert error to a generic SPI error kind.
236    ///
237    /// By using this method, SPI errors freely defined by HAL implementations
238    /// can be converted to a set of generic SPI errors upon which generic
239    /// code can act.
240    fn kind(&self) -> ErrorKind;
241}
242
243impl Error for core::convert::Infallible {
244    #[inline]
245    fn kind(&self) -> ErrorKind {
246        match *self {}
247    }
248}
249
250/// SPI error kind.
251///
252/// This represents a common set of SPI operation errors. HAL implementations are
253/// free to define more specific or additional error types. However, by providing
254/// a mapping to these common SPI errors, generic code can still react to them.
255#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
256#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
257#[non_exhaustive]
258pub enum ErrorKind {
259    /// The peripheral receive buffer was overrun.
260    Overrun,
261    /// Multiple devices on the SPI bus are trying to drive the slave select pin, e.g. in a multi-master setup.
262    ModeFault,
263    /// Received data does not conform to the peripheral configuration.
264    FrameFormat,
265    /// An error occurred while asserting or deasserting the Chip Select pin.
266    ChipSelectFault,
267    /// A different error occurred. The original error may contain more information.
268    Other,
269}
270
271impl Error for ErrorKind {
272    #[inline]
273    fn kind(&self) -> ErrorKind {
274        *self
275    }
276}
277
278impl core::fmt::Display for ErrorKind {
279    #[inline]
280    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
281        match self {
282            Self::Overrun => write!(f, "The peripheral receive buffer was overrun"),
283            Self::ModeFault => write!(
284                f,
285                "Multiple devices on the SPI bus are trying to drive the slave select pin"
286            ),
287            Self::FrameFormat => write!(
288                f,
289                "Received data does not conform to the peripheral configuration"
290            ),
291            Self::ChipSelectFault => write!(
292                f,
293                "An error occurred while asserting or deasserting the Chip Select pin"
294            ),
295            Self::Other => write!(
296                f,
297                "A different error occurred. The original error may contain more information"
298            ),
299        }
300    }
301}
302
303/// SPI error type trait.
304///
305/// This just defines the error type, to be used by the other SPI traits.
306pub trait ErrorType {
307    /// Error type.
308    type Error: Error;
309}
310
311impl<T: ErrorType + ?Sized> ErrorType for &mut T {
312    type Error = T::Error;
313}
314
315/// SPI transaction operation.
316///
317/// This allows composition of SPI operations into a single bus transaction.
318#[derive(Debug, PartialEq, Eq)]
319#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
320pub enum Operation<'a, Word: 'static> {
321    /// Read data into the provided buffer.
322    ///
323    /// Equivalent to [`SpiBus::read`].
324    Read(&'a mut [Word]),
325    /// Write data from the provided buffer, discarding read data.
326    ///
327    /// Equivalent to [`SpiBus::write`].
328    Write(&'a [Word]),
329    /// Read data into the first buffer, while writing data from the second buffer.
330    ///
331    /// Equivalent to [`SpiBus::transfer`].
332    Transfer(&'a mut [Word], &'a [Word]),
333    /// Write data out while reading data into the provided buffer.
334    ///
335    /// Equivalent to [`SpiBus::transfer_in_place`].
336    TransferInPlace(&'a mut [Word]),
337    /// Delay for at least the specified number of nanoseconds.
338    DelayNs(u32),
339}
340
341/// SPI device trait.
342///
343/// `SpiDevice` represents ownership over a single SPI device on a (possibly shared) bus, selected
344/// with a CS (Chip Select) pin.
345///
346/// See the [module-level documentation](self) for important usage information.
347pub trait SpiDevice<Word: Copy + 'static = u8>: ErrorType {
348    /// Perform a transaction against the device.
349    ///
350    /// - Locks the bus
351    /// - Asserts the CS (Chip Select) pin.
352    /// - Performs all the operations.
353    /// - [Flushes](SpiBus::flush) the bus.
354    /// - Deasserts the CS pin.
355    /// - Unlocks the bus.
356    ///
357    /// The locking mechanism is implementation-defined. The only requirement is it must prevent two
358    /// transactions from executing concurrently against the same bus. Examples of implementations are:
359    /// critical sections, blocking mutexes, returning an error or panicking if the bus is already busy.
360    ///
361    /// On bus errors the implementation should try to deassert CS.
362    /// If an error occurs while deasserting CS the bus error should take priority as the return value.
363    fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error>;
364
365    /// Do a read within a transaction.
366    ///
367    /// This is a convenience method equivalent to `device.transaction(&mut [Operation::Read(buf)])`.
368    ///
369    /// See also: [`SpiDevice::transaction`], [`SpiBus::read`]
370    #[inline]
371    fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
372        self.transaction(&mut [Operation::Read(buf)])
373    }
374
375    /// Do a write within a transaction.
376    ///
377    /// This is a convenience method equivalent to `device.transaction(&mut [Operation::Write(buf)])`.
378    ///
379    /// See also: [`SpiDevice::transaction`], [`SpiBus::write`]
380    #[inline]
381    fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
382        self.transaction(&mut [Operation::Write(buf)])
383    }
384
385    /// Do a transfer within a transaction.
386    ///
387    /// This is a convenience method equivalent to `device.transaction(&mut [Operation::Transfer(read, write)]`.
388    ///
389    /// See also: [`SpiDevice::transaction`], [`SpiBus::transfer`]
390    #[inline]
391    fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
392        self.transaction(&mut [Operation::Transfer(read, write)])
393    }
394
395    /// Do an in-place transfer within a transaction.
396    ///
397    /// This is a convenience method equivalent to `device.transaction(&mut [Operation::TransferInPlace(buf)]`.
398    ///
399    /// See also: [`SpiDevice::transaction`], [`SpiBus::transfer_in_place`]
400    #[inline]
401    fn transfer_in_place(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
402        self.transaction(&mut [Operation::TransferInPlace(buf)])
403    }
404}
405
406impl<Word: Copy + 'static, T: SpiDevice<Word> + ?Sized> SpiDevice<Word> for &mut T {
407    #[inline]
408    fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
409        T::transaction(self, operations)
410    }
411
412    #[inline]
413    fn read(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
414        T::read(self, buf)
415    }
416
417    #[inline]
418    fn write(&mut self, buf: &[Word]) -> Result<(), Self::Error> {
419        T::write(self, buf)
420    }
421
422    #[inline]
423    fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
424        T::transfer(self, read, write)
425    }
426
427    #[inline]
428    fn transfer_in_place(&mut self, buf: &mut [Word]) -> Result<(), Self::Error> {
429        T::transfer_in_place(self, buf)
430    }
431}
432
433/// SPI bus.
434///
435/// `SpiBus` represents **exclusive ownership** over the whole SPI bus, with SCK, MOSI and MISO pins.
436///
437/// See the [module-level documentation](self) for important information on SPI Bus vs Device traits.
438pub trait SpiBus<Word: Copy + 'static = u8>: ErrorType {
439    /// Read `words` from the slave.
440    ///
441    /// The word value sent on MOSI during reading is implementation-defined,
442    /// typically `0x00`, `0xFF`, or configurable.
443    ///
444    /// Implementations are allowed to return before the operation is
445    /// complete. See the [module-level documentation](self) for details.
446    fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
447
448    /// Write `words` to the slave, ignoring all the incoming words.
449    ///
450    /// Implementations are allowed to return before the operation is
451    /// complete. See the [module-level documentation](self) for details.
452    fn write(&mut self, words: &[Word]) -> Result<(), Self::Error>;
453
454    /// Write and read simultaneously. `write` is written to the slave on MOSI and
455    /// words received on MISO are stored in `read`.
456    ///
457    /// It is allowed for `read` and `write` to have different lengths, even zero length.
458    /// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
459    /// incoming words after `read` has been filled will be discarded. If `write` is shorter,
460    /// the value of words sent in MOSI after all `write` has been sent is implementation-defined,
461    /// typically `0x00`, `0xFF`, or configurable.
462    ///
463    /// Implementations are allowed to return before the operation is
464    /// complete. See the [module-level documentation](self) for details.
465    fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error>;
466
467    /// Write and read simultaneously. The contents of `words` are
468    /// written to the slave, and the received words are stored into the same
469    /// `words` buffer, overwriting it.
470    ///
471    /// Implementations are allowed to return before the operation is
472    /// complete. See the [module-level documentation](self) for details.
473    fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error>;
474
475    /// Wait until all operations have completed and the bus is idle.
476    ///
477    /// See the [module-level documentation](self) for important usage information.
478    fn flush(&mut self) -> Result<(), Self::Error>;
479}
480
481impl<T: SpiBus<Word> + ?Sized, Word: Copy + 'static> SpiBus<Word> for &mut T {
482    #[inline]
483    fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
484        T::read(self, words)
485    }
486
487    #[inline]
488    fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> {
489        T::write(self, words)
490    }
491
492    #[inline]
493    fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> {
494        T::transfer(self, read, write)
495    }
496
497    #[inline]
498    fn transfer_in_place(&mut self, words: &mut [Word]) -> Result<(), Self::Error> {
499        T::transfer_in_place(self, words)
500    }
501
502    #[inline]
503    fn flush(&mut self) -> Result<(), Self::Error> {
504        T::flush(self)
505    }
506}