rpi_embedded/
spi.rs

1// Copyright (c) 2017-2019 Rene van der Meer
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the "Software"),
5// to deal in the Software without restriction, including without limitation
6// the rights to use, copy, modify, merge, publish, distribute, sublicense,
7// and/or sell copies of the Software, and to permit persons to whom the
8// Software is furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19// DEALINGS IN THE SOFTWARE.
20
21//! Interface for the main and auxiliary SPI peripherals.
22//!
23//! RPPAL provides access to the available SPI buses by using the `spidev` device
24//! interface through `/dev/spidevB.S`, where B refers to an SPI bus, and S to
25//! a Slave Select pin. Which buses and pins are available depends on your
26//! Raspberry Pi model and configuration, as explained below.
27//!
28//! ## SPI buses
29//!
30//! The Raspberry Pi's GPIO header exposes several SPI buses. SPI0 is available
31//! on all Raspberry Pi models. SPI1 is available on models with a 40-pin
32//! header. SPI2 is only available on the Compute and Compute 3. SPI3 through SPI6
33//! are only available on the Raspberry Pi 4 B.
34//!
35//! ### SPI0
36//!
37//! SPI0 is disabled by default. You can enable it by running
38//! `sudo raspi-config`, or by manually adding `dtparam=spi=on` to
39//! `/boot/config.txt`. The associated pins are listed below.
40//!
41//! * MISO: BCM GPIO 9 (physical pin 21)
42//! * MOSI: BCM GPIO 10 (physical pin 19)
43//! * SCLK: BCM GPIO 11 (physical pin 23)
44//! * SS: [`Ss0`] BCM GPIO 8 (physical pin 24), [`Ss1`] BCM GPIO 7 (physical pin 26)
45//!
46//! ### SPI1
47//!
48//! SPI1 is an auxiliary peripheral that's referred to as mini SPI. According
49//! to the BCM2835 documentation, using higher clock speeds on SPI1 requires
50//! additional CPU time compared to SPI0, caused by smaller FIFOs and no DMA
51//! support. It doesn't support [`Mode1`] or [`Mode3`]. SPI1 can be enabled by
52//! adding `dtoverlay=spi1-1cs` to `/boot/config.txt`. Replace `1cs` with
53//! either `2cs` or `3cs` if you require 2 or 3 Slave Select pins.
54//! The associated pins are listed below.
55//!
56//! * MISO: BCM GPIO 19 (physical pin 35)
57//! * MOSI: BCM GPIO 20 (physical pin 38)
58//! * SCLK: BCM GPIO 21 (physical pin 40)
59//! * SS: [`Ss0`] BCM GPIO 18 (physical pin 12), [`Ss1`] BCM GPIO 17 (physical pin 11), [`Ss2`] BCM GPIO 16 (physical pin 36)
60//!
61//! ### SPI2
62//!
63//! SPI2 shares the same characteristics and limitations as SPI1. It can be
64//! enabled by adding `dtoverlay=spi2-1cs` to `/boot/config.txt`. Replace
65//! `1cs` with either `2cs` or `3cs` if you require 2 or 3 Slave Select
66//! pins. The associated pins are listed below.
67//!
68//! * MISO: BCM GPIO 40
69//! * MOSI: BCM GPIO 41
70//! * SCLK: BCM GPIO 42
71//! * SS: [`Ss0`] BCM GPIO 43, [`Ss1`] BCM GPIO 44, [`Ss2`] BCM GPIO 45
72//!
73//! ### SPI3
74//!
75//! SPI3 can be enabled by adding `dtoverlay=spi3-1cs` to `/boot/config.txt`. Replace
76//! `1cs` with `2cs` if you require 2 Slave Select pins. The associated pins are listed below.
77//!
78//! * MISO: BCM GPIO 1 (physical pin 28)
79//! * MOSI: BCM GPIO 2 (physical pin 3)
80//! * SCLK: BCM GPIO 3 (physical pin 5)
81//! * SS: [`Ss0`] BCM GPIO 0 (physical pin 27), [`Ss1`] BCM GPIO 24 (physical pin 18)
82//!
83//! ### SPI4
84//!
85//! SPI4 can be enabled by adding `dtoverlay=spi4-1cs` to `/boot/config.txt`. Replace
86//! `1cs` with `2cs` if you require 2 Slave Select pins. The associated pins are listed below.
87//!
88//! * MISO: BCM GPIO 5 (physical pin 29)
89//! * MOSI: BCM GPIO 6 (physical pin 31)
90//! * SCLK: BCM GPIO 7 (physical pin 26)
91//! * SS: [`Ss0`] BCM GPIO 4 (physical pin 7), [`Ss1`] BCM GPIO 25 (physical pin 22)
92//!
93//! ### SPI5
94//!
95//! SPI5 can be enabled by adding `dtoverlay=spi5-1cs` to `/boot/config.txt`. Replace
96//! `1cs` with `2cs` if you require 2 Slave Select pins. The associated pins are listed below.
97//!
98//! * MISO: BCM GPIO 13 (physical pin 33)
99//! * MOSI: BCM GPIO 14 (physical pin 8)
100//! * SCLK: BCM GPIO 15 (physical pin 10)
101//! * SS: [`Ss0`] BCM GPIO 12 (physical pin 32), [`Ss1`] BCM GPIO 26 (physical pin 37)
102//!
103//! ### SPI6
104//!
105//! SPI6 can be enabled by adding `dtoverlay=spi6-1cs` to `/boot/config.txt`. Replace
106//! `1cs` with `2cs` if you require 2 Slave Select pins. The associated pins are listed below.
107//!
108//! * MISO: BCM GPIO 19 (physical pin 35)
109//! * MOSI: BCM GPIO 20 (physical pin 38)
110//! * SCLK: BCM GPIO 21 (physical pin 40)
111//! * SS: [`Ss0`] BCM GPIO 18 (physical pin 12), [`Ss1`] BCM GPIO 27 (physical pin 13)
112//!
113//! SPI6 is tied to the same GPIO pins as SPI1. It's not possible to enable both
114//! buses at the same time.
115//!
116//! ### Alternative pins
117//!
118//! The GPIO pin numbers mentioned above are part of the default configuration.
119//! Some of their functionality can be moved to different pins. Read
120//! `/boot/overlays/README` for more information.
121//!
122//! ## Buffer size limits
123//!
124//! By default, `spidev` can handle up to 4096 bytes in a single transfer. You
125//! can increase this limit to a maximum of 65536 bytes by appending
126//! `spidev.bufsiz=65536` to the single line of parameters in `/boot/cmdline.txt`.
127//! Remember to reboot the Raspberry Pi afterwards. The current value of bufsiz
128//! can be checked with `cat /sys/module/spidev/parameters/bufsiz`.
129//!
130//! ## Not supported
131//!
132//! Some features exposed by the generic `spidev` interface aren't fully
133//! supported by the underlying driver or the BCM283x SoC: `SPI_LSB_FIRST` (LSB
134//! first bit order), `SPI_3WIRE` (bidirectional mode), `SPI_LOOP` (loopback mode),
135//! `SPI_NO_CS` (no Slave Select), `SPI_READY` (slave ready signal),
136//! `SPI_TX_DUAL`/`SPI_RX_DUAL` (dual SPI), `SPI_TX_QUAD`/`SPI_RX_QUAD` (quad SPI),
137//! and any number of bits per word other than 8.
138//!
139//! If your slave device requires `SPI_LSB_FIRST`, you can use the
140//! [`reverse_bits`] function instead to reverse the bit order in software.
141//!
142//! `SPI_LOOP` mode can be achieved by connecting the MOSI and MISO pins
143//! together.
144//!
145//! `SPI_NO_CS` can be implemented by connecting the Slave Select pin on your
146//! slave device to any other available GPIO pin on the Pi, and manually
147//! changing it to high and low as needed.
148//!
149//! [`Ss0`]: enum.SlaveSelect.html
150//! [`Ss1`]: enum.SlaveSelect.html
151//! [`Ss2`]: enum.SlaveSelect.html
152//! [`Mode1`]: enum.Mode.html
153//! [`Mode3`]: enum.Mode.html
154//! [`reverse_bits`]: fn.reverse_bits.html
155
156use std::error;
157use std::fmt;
158use std::fs::{File, OpenOptions};
159use std::io;
160use std::io::{Read, Write};
161use std::marker::PhantomData;
162use std::os::unix::io::AsRawFd;
163use std::result;
164
165#[cfg(feature = "hal")]
166mod hal;
167mod ioctl;
168mod segment;
169
170pub use self::segment::Segment;
171
172/// Errors that can occur when accessing the SPI peripheral.
173#[derive(Debug)]
174pub enum Error {
175    /// I/O error.
176    Io(io::Error),
177    /// The specified number of bits per word is not supported.
178    ///
179    /// The Raspberry Pi currently only supports 8 bit words. Any other value
180    /// will trigger this error.
181    BitsPerWordNotSupported(u8),
182    /// The specified bit order is not supported.
183    ///
184    /// The Raspberry Pi currently only supports the [`MsbFirst`] bit order. If you
185    /// need the [`LsbFirst`] bit order, you can use the [`reverse_bits`] function
186    /// instead to reverse the bit order in software by converting your write
187    /// buffer before sending it to the slave device, and your read buffer after
188    /// reading any incoming data.
189    ///
190    /// [`MsbFirst`]: enum.BitOrder.html
191    /// [`LsbFirst`]: enum.BitOrder.html
192    /// [`reverse_bits`]: fn.reverse_bits.html
193    BitOrderNotSupported(BitOrder),
194    /// The specified clock speed is not supported.
195    ClockSpeedNotSupported(u32),
196    /// The specified mode is not supported.
197    ModeNotSupported(Mode),
198    /// The specified Slave Select polarity is not supported.
199    PolarityNotSupported(Polarity),
200}
201
202impl fmt::Display for Error {
203    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        match *self {
205            Error::Io(ref err) => write!(f, "I/O error: {}", err),
206            Error::BitsPerWordNotSupported(bits_per_word) => {
207                write!(f, "Bits per word value not supported: {}", bits_per_word)
208            }
209            Error::BitOrderNotSupported(bit_order) => {
210                write!(f, "Bit order value not supported: {:?}", bit_order)
211            }
212            Error::ClockSpeedNotSupported(clock_speed) => {
213                write!(f, "Clock speed value not supported: {}", clock_speed)
214            }
215            Error::ModeNotSupported(mode) => write!(f, "Mode value not supported: {:?}", mode),
216            Error::PolarityNotSupported(polarity) => {
217                write!(f, "Polarity value not supported: {:?}", polarity)
218            }
219        }
220    }
221}
222
223impl error::Error for Error {}
224
225impl From<io::Error> for Error {
226    fn from(err: io::Error) -> Error {
227        Error::Io(err)
228    }
229}
230
231/// Result type returned from methods that can have `spi::Error`s.
232pub type Result<T> = result::Result<T, Error>;
233
234const LOOKUP_REVERSE_BITS: [u8; 256] = [
235    0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
236    0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
237    0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
238    0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
239    0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
240    0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
241    0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
242    0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
243    0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
244    0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
245    0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
246    0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
247    0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
248    0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
249    0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
250    0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
251];
252
253/// Reverses the bits of each byte in `buffer`.
254///
255/// Use this function to switch the bit order between most-significant bit first
256/// and least-significant bit first.
257#[inline(always)]
258pub fn reverse_bits(buffer: &mut [u8]) {
259    for byte in buffer {
260        *byte = LOOKUP_REVERSE_BITS[*byte as usize];
261    }
262}
263
264/// SPI buses.
265///
266/// The Raspberry Pi exposes up to five SPI buses, depending on the model and
267/// your `/boot/config.txt` configuration. More information can be found [here].
268///
269/// [here]: index.html
270#[derive(Debug, PartialEq, Eq, Copy, Clone)]
271pub enum Bus {
272    Spi0 = 0,
273    Spi1 = 1,
274    Spi2 = 2,
275    Spi3 = 3,
276    Spi4 = 4,
277    Spi5 = 5,
278    Spi6 = 6,
279}
280
281impl fmt::Display for Bus {
282    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
283        match *self {
284            Bus::Spi0 => write!(f, "Spi0"),
285            Bus::Spi1 => write!(f, "Spi1"),
286            Bus::Spi2 => write!(f, "Spi2"),
287            Bus::Spi3 => write!(f, "Spi3"),
288            Bus::Spi4 => write!(f, "Spi4"),
289            Bus::Spi5 => write!(f, "Spi5"),
290            Bus::Spi6 => write!(f, "Spi6"),
291        }
292    }
293}
294
295/// Slave Select pins.
296///
297/// Slave Select is used to signal which slave device should pay attention to
298/// the SPI bus. Slave Select (SS) is the more commonly used name, but
299/// it's also known as Chip Select (CS) or Chip Enable (CE). Throughout the Raspberry
300/// Pi's documentation, config files and BCM2835 datasheet, multiple different names
301/// are used. Any pins referred to as CE0, CE1, and CE2 or CS0, CS1, and CS2 are equivalent
302/// to `Ss0`, `Ss1`, and `Ss2`.
303///
304/// The number of available Slave Select pins for the selected SPI bus depends
305/// on your `/boot/config.txt` configuration. More information can be found
306/// [here].
307///
308/// [here]: index.html
309#[derive(Debug, PartialEq, Eq, Copy, Clone)]
310pub enum SlaveSelect {
311    Ss0 = 0,
312    Ss1 = 1,
313    Ss2 = 2,
314}
315
316impl fmt::Display for SlaveSelect {
317    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
318        match *self {
319            SlaveSelect::Ss0 => write!(f, "Ss0"),
320            SlaveSelect::Ss1 => write!(f, "Ss1"),
321            SlaveSelect::Ss2 => write!(f, "Ss2"),
322        }
323    }
324}
325
326/// Slave Select polarities.
327#[derive(Debug, PartialEq, Eq, Copy, Clone)]
328pub enum Polarity {
329    ActiveLow = 0,
330    ActiveHigh = 1,
331}
332
333impl fmt::Display for Polarity {
334    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335        match *self {
336            Polarity::ActiveLow => write!(f, "ActiveLow"),
337            Polarity::ActiveHigh => write!(f, "ActiveHigh"),
338        }
339    }
340}
341
342/// SPI modes indicating the clock polarity and phase.
343///
344/// Select the appropriate SPI mode for your device. Each mode configures the
345/// clock polarity (CPOL) and clock phase (CPHA) as shown below:
346///
347/// * Mode0: CPOL 0, CPHA 0
348/// * Mode1: CPOL 0, CPHA 1
349/// * Mode2: CPOL 1, CPHA 0
350/// * Mode3: CPOL 1, CPHA 1
351///
352/// The [`Spi0`] bus supports all 4 modes. [`Spi1`] and [`Spi2`] only support
353/// `Mode0` and `Mode2`.
354///
355/// More information on clock polarity and phase can be found on [Wikipedia].
356///
357/// [`Spi0`]: enum.Bus.html
358/// [`Spi1`]: enum.Bus.html
359/// [`Spi2`]: enum.Bus.html
360/// [Wikipedia]: https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus#Clock_polarity_and_phase
361#[derive(Debug, PartialEq, Eq, Copy, Clone)]
362pub enum Mode {
363    Mode0 = 0,
364    Mode1 = 1,
365    Mode2 = 2,
366    Mode3 = 3,
367}
368
369impl fmt::Display for Mode {
370    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
371        match *self {
372            Mode::Mode0 => write!(f, "Mode0"),
373            Mode::Mode1 => write!(f, "Mode1"),
374            Mode::Mode2 => write!(f, "Mode2"),
375            Mode::Mode3 => write!(f, "Mode3"),
376        }
377    }
378}
379
380/// Bit orders.
381///
382/// The bit order determines in what order data is shifted out and shifted in.
383/// Select the bit order that's appropriate for the device you're
384/// communicating with.
385///
386/// `MsbFirst` will transfer the most-significant bit first. `LsbFirst` will
387/// transfer the least-significant bit first.
388///
389/// The Raspberry Pi currently only supports the `MsbFirst` bit order. If you
390/// need the `LsbFirst` bit order, you can use the [`reverse_bits`] function
391/// instead to reverse the bit order in software by converting your write
392/// buffer before sending it to the slave device, and your read buffer after
393/// reading any incoming data.
394///
395/// [`reverse_bits`]: fn.reverse_bits.html
396#[derive(Debug, PartialEq, Eq, Copy, Clone)]
397pub enum BitOrder {
398    MsbFirst = 0,
399    LsbFirst = 1,
400}
401
402impl fmt::Display for BitOrder {
403    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404        match *self {
405            BitOrder::MsbFirst => write!(f, "MsbFirst"),
406            BitOrder::LsbFirst => write!(f, "LsbFirst"),
407        }
408    }
409}
410
411/// Provides access to the Raspberry Pi's SPI peripherals.
412///
413/// Before using `Spi`, make sure your Raspberry Pi has the necessary SPI buses
414/// and Slave Select pins enabled. More information can be found [here].
415///
416/// The `embedded-hal` [`blocking::spi::Transfer<u8>`], [`blocking::spi::Write<u8>`]
417/// and [`spi::FullDuplex<u8>`] trait
418/// implementations for `Spi` can be enabled by specifying the optional `hal`
419/// feature in the dependency declaration for the `rppal` crate.
420///
421/// [here]: index.html
422/// [`blocking::spi::Transfer<u8>`]: ../../embedded_hal/blocking/spi/trait.Transfer.html
423/// [`blocking::spi::Write<u8>`]: ../../embedded_hal/blocking/spi/trait.Write.html
424/// [`spi::FullDuplex<u8>`]: ../../embedded_hal/spi/trait.FullDuplex.html
425pub struct Spi {
426    spidev: File,
427    // Stores the last read value. Used for embedded_hal::spi::FullDuplex.
428    #[cfg(feature = "hal")]
429    last_read: u8,
430    // The not_sync field is a workaround to force !Sync. Spi isn't safe for
431    // Sync because of ioctl() and the underlying drivers. This avoids needing
432    // #![feature(optin_builtin_traits)] to manually add impl !Sync for Spi.
433    not_sync: PhantomData<*const ()>,
434}
435
436impl Spi {
437    /// Constructs a new `Spi`.
438    ///
439    /// `bus` and `slave_select` specify the selected SPI bus and one of its
440    /// associated Slave Select pins.
441    ///
442    /// `clock_speed` defines the maximum clock frequency in hertz (Hz). The SPI driver
443    /// will automatically round down to the closest valid frequency.
444    ///
445    /// `mode` selects the clock polarity and phase.
446    pub fn new(bus: Bus, slave_select: SlaveSelect, clock_speed: u32, mode: Mode) -> Result<Spi> {
447        // The following options currently aren't supported by spidev in Raspbian Stretch on the Pi:
448        //
449        // LSB_FIRST - ioctl() returns EINVAL when set
450        // 3WIRE - neither MOSI nor MISO show any outgoing data in half-duplex mode
451        // LOOP - ioctl() returns EINVAL when set
452        // NO_CS - SS is still set to active (tried both file write() and ioctl())
453        // READY - ioctl() returns EINVAL when set
454        // TX_DUAL/TX_QUAD/RX_DUAL/RX_QUAD - Not supported by BCM283x
455        // bits per word - any value other than 0 or 8 returns EINVAL when set
456
457        let spidev = OpenOptions::new()
458            .read(true)
459            .write(true)
460            .open(format!("/dev/spidev{}.{}", bus as u8, slave_select as u8))?;
461
462        // Reset all mode flags
463        if let Err(e) = ioctl::set_mode32(spidev.as_raw_fd(), mode as u32) {
464            if e.kind() == io::ErrorKind::InvalidInput {
465                return Err(Error::ModeNotSupported(mode));
466            } else {
467                return Err(Error::Io(e));
468            }
469        }
470
471        let spi = Spi {
472            spidev,
473            #[cfg(feature = "hal")]
474            last_read: 0,
475            not_sync: PhantomData,
476        };
477
478        // Set defaults and user-specified settings
479        spi.set_bits_per_word(8)?;
480        spi.set_clock_speed(clock_speed)?;
481
482        Ok(spi)
483    }
484
485    /// Gets the bit order.
486    pub fn bit_order(&self) -> Result<BitOrder> {
487        let mut bit_order: u8 = 0;
488        ioctl::lsb_first(self.spidev.as_raw_fd(), &mut bit_order)?;
489
490        Ok(match bit_order {
491            0 => BitOrder::MsbFirst,
492            _ => BitOrder::LsbFirst,
493        })
494    }
495
496    /// Sets the order in which bits are shifted out and in.
497    ///
498    /// The Raspberry Pi currently only supports the [`MsbFirst`] bit order. If you
499    /// need the [`LsbFirst`] bit order, you can use the [`reverse_bits`] function
500    /// instead to reverse the bit order in software by converting your write
501    /// buffer before sending it to the slave device, and your read buffer after
502    /// reading any incoming data.
503    ///
504    /// By default, `bit_order` is set to `MsbFirst`.
505    ///
506    /// [`MsbFirst`]: enum.BitOrder.html
507    /// [`LsbFirst`]: enum.BitOrder.html
508    /// [`reverse_bits`]: fn.reverse_bits.html
509    pub fn set_bit_order(&self, bit_order: BitOrder) -> Result<()> {
510        match ioctl::set_lsb_first(self.spidev.as_raw_fd(), bit_order as u8) {
511            Ok(_) => Ok(()),
512            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {
513                Err(Error::BitOrderNotSupported(bit_order))
514            }
515            Err(e) => Err(Error::Io(e)),
516        }
517    }
518
519    /// Gets the number of bits per word.
520    pub fn bits_per_word(&self) -> Result<u8> {
521        let mut bits_per_word: u8 = 0;
522        ioctl::bits_per_word(self.spidev.as_raw_fd(), &mut bits_per_word)?;
523
524        Ok(bits_per_word)
525    }
526
527    /// Sets the number of bits per word.
528    ///
529    /// The Raspberry Pi currently only supports 8 bit words.
530    ///
531    /// By default, `bits_per_word` is set to 8.
532    pub fn set_bits_per_word(&self, bits_per_word: u8) -> Result<()> {
533        match ioctl::set_bits_per_word(self.spidev.as_raw_fd(), bits_per_word) {
534            Ok(_) => Ok(()),
535            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {
536                Err(Error::BitsPerWordNotSupported(bits_per_word))
537            }
538            Err(e) => Err(Error::Io(e)),
539        }
540    }
541
542    /// Gets the clock frequency in hertz (Hz).
543    pub fn clock_speed(&self) -> Result<u32> {
544        let mut clock_speed: u32 = 0;
545        ioctl::clock_speed(self.spidev.as_raw_fd(), &mut clock_speed)?;
546
547        Ok(clock_speed)
548    }
549
550    /// Sets the clock frequency in hertz (Hz).
551    ///
552    /// The SPI driver will automatically round down to the closest valid frequency.
553    pub fn set_clock_speed(&self, clock_speed: u32) -> Result<()> {
554        match ioctl::set_clock_speed(self.spidev.as_raw_fd(), clock_speed) {
555            Ok(_) => Ok(()),
556            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {
557                Err(Error::ClockSpeedNotSupported(clock_speed))
558            }
559            Err(e) => Err(Error::Io(e)),
560        }
561    }
562
563    /// Gets the SPI mode.
564    pub fn mode(&self) -> Result<Mode> {
565        let mut mode: u8 = 0;
566        ioctl::mode(self.spidev.as_raw_fd(), &mut mode)?;
567
568        Ok(match mode & 0x03 {
569            0x01 => Mode::Mode1,
570            0x02 => Mode::Mode2,
571            0x03 => Mode::Mode3,
572            _ => Mode::Mode0,
573        })
574    }
575
576    /// Sets the SPI mode.
577    ///
578    /// The SPI mode indicates the serial clock polarity and phase. Some modes
579    /// may not be available depending on the SPI bus that's used.
580    pub fn set_mode(&self, mode: Mode) -> Result<()> {
581        let mut new_mode: u8 = 0;
582        ioctl::mode(self.spidev.as_raw_fd(), &mut new_mode)?;
583
584        // Make sure we only replace the CPOL/CPHA bits
585        new_mode = (new_mode & !0x03) | (mode as u8);
586
587        match ioctl::set_mode(self.spidev.as_raw_fd(), new_mode) {
588            Ok(_) => Ok(()),
589            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {
590                Err(Error::ModeNotSupported(mode))
591            }
592            Err(e) => Err(Error::Io(e)),
593        }
594    }
595
596    /// Gets the Slave Select polarity.
597    pub fn ss_polarity(&self) -> Result<Polarity> {
598        let mut mode: u8 = 0;
599        ioctl::mode(self.spidev.as_raw_fd(), &mut mode)?;
600
601        if (mode & ioctl::MODE_CS_HIGH) == 0 {
602            Ok(Polarity::ActiveLow)
603        } else {
604            Ok(Polarity::ActiveHigh)
605        }
606    }
607
608    /// Sets Slave Select polarity.
609    ///
610    /// By default, the Slave Select polarity is set to `ActiveLow`.
611    pub fn set_ss_polarity(&self, polarity: Polarity) -> Result<()> {
612        let mut new_mode: u8 = 0;
613        ioctl::mode(self.spidev.as_raw_fd(), &mut new_mode)?;
614
615        if polarity == Polarity::ActiveHigh {
616            new_mode |= ioctl::MODE_CS_HIGH;
617        } else {
618            new_mode &= !ioctl::MODE_CS_HIGH;
619        }
620
621        match ioctl::set_mode(self.spidev.as_raw_fd(), new_mode) {
622            Ok(_) => Ok(()),
623            Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {
624                Err(Error::PolarityNotSupported(polarity))
625            }
626            Err(e) => Err(Error::Io(e)),
627        }
628    }
629
630    /// Receives incoming data from the slave device and writes it to `buffer`.
631    ///
632    /// The SPI protocol doesn't indicate how much incoming data is waiting,
633    /// so the total number of bytes read depends on the length of `buffer`.
634    ///
635    /// During the read, the MOSI line is kept in a state that results in a
636    /// zero value byte shifted out for every byte `read` receives on the MISO
637    /// line.
638    ///
639    /// Slave Select is set to active at the start of the read, and inactive
640    /// when the read completes.
641    ///
642    /// Returns how many bytes were read.
643    pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
644        Ok(self.spidev.read(buffer)?)
645    }
646
647    /// Sends the outgoing data contained in `buffer` to the slave device.
648    ///
649    /// Any data received on the MISO line from the slave is ignored.
650    ///
651    /// Slave Select is set to active at the start of the write, and inactive
652    /// when the write completes.
653    ///
654    /// Returns how many bytes were written.
655    pub fn write(&mut self, buffer: &[u8]) -> Result<usize> {
656        Ok(self.spidev.write(buffer)?)
657    }
658
659    /// Sends and receives data at the same time.
660    ///
661    /// SPI is a full-duplex protocol that shifts out bits to the slave device
662    /// on the MOSI line while simultaneously shifting in bits it receives on
663    /// the MISO line. `transfer` stores the incoming data in `read_buffer`,
664    /// and sends the outgoing data contained in `write_buffer`.
665    ///
666    /// Because data is sent and received simultaneously, `transfer` will only
667    /// transfer as many bytes as the shortest of the two buffers contains.
668    ///
669    /// Slave Select is set to active at the start of the transfer, and inactive
670    /// when the transfer completes.
671    ///
672    /// Returns how many bytes were transferred.
673    pub fn transfer(&self, read_buffer: &mut [u8], write_buffer: &[u8]) -> Result<usize> {
674        let segment = Segment::new(read_buffer, write_buffer);
675
676        ioctl::transfer(self.spidev.as_raw_fd(), &[segment])?;
677
678        Ok(segment.len())
679    }
680
681    /// Transfers multiple half-duplex or full-duplex segments.
682    ///
683    /// `transfer_segments` transfers multiple segments in a single call. Each
684    /// [`Segment`] contains a reference to either a read buffer or a write buffer,
685    /// or both. Optional settings can be configured that override the SPI bus
686    /// settings for that specific segment.
687    ///
688    /// By default, Slave Select stays active until all segments have been
689    /// transferred. You can change this behavior using [`Segment::set_ss_change`].
690    ///
691    /// [`Segment`]: struct.Segment.html
692    /// [`Segment::set_ss_change`]: struct.Segment.html#method.set_ss_change
693    pub fn transfer_segments(&self, segments: &[Segment<'_, '_>]) -> Result<()> {
694        ioctl::transfer(self.spidev.as_raw_fd(), segments)?;
695
696        Ok(())
697    }
698}
699
700// Send is safe for Spi, but we're marked !Send because of the dummy pointer that's
701// needed to force !Sync.
702unsafe impl Send for Spi {}
703
704impl fmt::Debug for Spi {
705    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
706        f.debug_struct("Spi").field("spidev", &self.spidev).finish()
707    }
708}