| 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 | |
| 174 | use core::fmt::Debug; |
| 175 | |
| 176 | #[cfg (feature = "defmt-03" )] |
| 177 | use crate::defmt; |
| 178 | |
| 179 | /// Clock polarity. |
| 180 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
| 181 | #[cfg_attr (feature = "defmt-03" , derive(defmt::Format))] |
| 182 | pub 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))] |
| 192 | pub 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))] |
| 202 | pub 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. |
| 210 | pub const MODE_0: Mode = Mode { |
| 211 | polarity: Polarity::IdleLow, |
| 212 | phase: Phase::CaptureOnFirstTransition, |
| 213 | }; |
| 214 | |
| 215 | /// Helper for CPOL = 0, CPHA = 1. |
| 216 | pub const MODE_1: Mode = Mode { |
| 217 | polarity: Polarity::IdleLow, |
| 218 | phase: Phase::CaptureOnSecondTransition, |
| 219 | }; |
| 220 | |
| 221 | /// Helper for CPOL = 1, CPHA = 0. |
| 222 | pub const MODE_2: Mode = Mode { |
| 223 | polarity: Polarity::IdleHigh, |
| 224 | phase: Phase::CaptureOnFirstTransition, |
| 225 | }; |
| 226 | |
| 227 | /// Helper for CPOL = 1, CPHA = 1. |
| 228 | pub const MODE_3: Mode = Mode { |
| 229 | polarity: Polarity::IdleHigh, |
| 230 | phase: Phase::CaptureOnSecondTransition, |
| 231 | }; |
| 232 | |
| 233 | /// SPI error. |
| 234 | pub 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 | |
| 243 | impl 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 ] |
| 258 | pub 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 | |
| 271 | impl Error for ErrorKind { |
| 272 | #[inline ] |
| 273 | fn kind(&self) -> ErrorKind { |
| 274 | *self |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | impl 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. |
| 306 | pub trait ErrorType { |
| 307 | /// Error type. |
| 308 | type Error: Error; |
| 309 | } |
| 310 | |
| 311 | impl<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))] |
| 320 | pub 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. |
| 347 | pub 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 | |
| 406 | impl<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. |
| 438 | pub 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 | |
| 481 | impl<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 | } |
| 507 | |