diff --git a/src/lib.rs b/src/lib.rs index 17c75a4..ee52767 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,5 +53,5 @@ pub use crate::delay::Delay; pub use crate::i2c::{I2CError, I2cdev}; pub use crate::serial::{Serial, SerialError}; #[cfg(feature = "spi")] -pub use crate::spi::{SPIError, Spidev}; +pub use crate::spi::{SPIError, SpidevBus, SpidevDevice}; pub use crate::timer::{CountDown, Periodic, SysTimer}; diff --git a/src/spi.rs b/src/spi.rs index 10018fc..9e9a539 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -9,27 +9,96 @@ use std::io; use std::ops; use std::path::Path; -/// Newtype around [`spidev::Spidev`] that implements the `embedded-hal` traits +/// Spidev wrapper providing the embedded-hal [`SpiDevice`] trait. /// -/// [Delay operations][delay] are capped to 65535 microseconds. +/// Use this struct when you want a single spidev device, using a Linux-managed CS pin, +/// which is already defined in your devicetree. Linux will handle sharing the bus +/// between different SPI devices, even between different processes. /// -/// [`spidev::Spidev`]: https://docs.rs/spidev/0.5.2/spidev/struct.Spidev.html -/// [delay]: embedded_hal::spi::Operation::DelayUs -pub struct Spidev(pub spidev::Spidev); +/// You get an object that implements [`SpiDevice`], which is what most drivers require, +/// but does not implement [`SpiBus`]. In some rare cases, you may require [`SpiBus`] +/// instead; for that refer to [`SpidevBus`] below. You may also want to use [`SpiBus`] +/// if you want to handle all the CS pins yourself using GPIO. +/// +/// This struct wraps a [`spidev::Spidev`] struct, so it can be constructed directly +/// and the inner struct accessed if needed, for example to (re)configure the SPI settings. +/// +/// Note that [delay operations] on this device are capped to 65535 microseconds. +/// +/// [`SpiDevice`]: embedded_hal::spi::SpiDevice +/// [`SpiBus`]: embedded_hal::spi::SpiBus +/// [`spidev::Spidev`]: spidev::Spidev +/// [delay operations]: embedded_hal::spi::Operation::DelayUs +pub struct SpidevDevice(pub spidev::Spidev); + +/// Spidev wrapper providing the embedded-hal [`SpiBus`] trait. +/// +/// Use this struct when you require direct access to the underlying SPI bus, for +/// example when you want to use GPIOs as software-controlled CS pins to share the +/// bus with multiple devices, or because a driver requires the entire bus (for +/// example to drive smart LEDs). +/// +/// Do not use this struct if you're accessing SPI devices that already appear in your +/// device tree; you will not be able to drive CS pins that are already used by spidev +/// as GPIOs. Instead use [`SpidevDevice`]. +/// +/// This struct must still be created from a [`spidev::Spidev`] device, but there are two +/// important notes: +/// +/// 1. The CS pin associated with this spidev device will be driven whenever any device accesses +/// this bus, so it should be an unconnected or unused pin. +/// 2. No other spidev device on the same bus may be used as long as this `SpidevBus` exists, +/// as Linux will _not_ do anything to ensure this bus has exclusive access. +/// +/// It is recommended to use a dummy spidev device associated with an unused CS pin, and then use +/// regular GPIOs as CS pins if required. If you are planning to share this bus using GPIOs, the +/// [`embedded-hal-bus`] crate may be of interest. +/// +/// If necessary, you can [configure] the underlying [`spidev::Spidev`] instance with the +/// [`SPI_NO_CS`] flag set to prevent any CS pin activity. +/// +/// [`SpiDevice`]: embedded_hal::spi::SpiDevice +/// [`SpiBus`]: embedded_hal::spi::SpiBus +/// [`embedded-hal-bus`]: https://docs.rs/embedded-hal-bus/ +/// [`spidev::Spidev`]: spidev::Spidev +/// [delay operations]: embedded_hal::spi::Operation::DelayUs +/// [configure]: spidev::Spidev::configure +/// [`SPI_NO_CS`]: spidev::SpiModeFlags::SPI_NO_CS +pub struct SpidevBus(pub spidev::Spidev); + +impl SpidevDevice { + /// See [`spidev::Spidev::open`] for details. + /// + /// The provided `path` is for the specific device you wish to access. + /// Access to the bus is shared with other devices via the Linux kernel. + pub fn open
(path: P) -> Result (path: P) -> Result