mcp23017_driver/
lib.rs

1#![no_std]
2
3use embedded_hal::i2c::I2c;
4use embedded_hal_bus::i2c::AtomicDevice;
5use embedded_hal_bus::util::AtomicCell;
6use error::Error;
7use pin::interrupt::InterruptController;
8use pin::{Pin, Pins};
9
10pub mod error;
11pub mod pin;
12
13pub(crate) mod registers;
14
15/// A driver representing a single Microchip MCP23017.
16///
17/// Generic over an I2C bus `S` and device address `A`.
18pub struct Mcp23017<S: I2c, const A: u8> {
19    cell: AtomicCell<S>,
20}
21
22impl<S: I2c, const A: u8> Mcp23017<S, A> {
23    /// Construct a new driver for a device accessible over the bus.
24    pub fn new(i2c: S) -> Self {
25        Self {
26            cell: AtomicCell::new(i2c),
27        }
28    }
29
30    /// Extract individually controllable pins and an interrupt controller from the device.
31    ///
32    /// Pins A7 and B7 are pre-configured as outputs, as mandated by the
33    /// datasheet.
34    ///
35    /// Errors if communication with the device fails.
36    pub fn split(&mut self) -> Result<(Pins<S, A>, InterruptController<S, A>), Error<S>> {
37        unsafe {
38            Ok((
39                Pins {
40                    a0: Pin::new(AtomicDevice::new(&self.cell)),
41                    a1: Pin::new(AtomicDevice::new(&self.cell)),
42                    a2: Pin::new(AtomicDevice::new(&self.cell)),
43                    a3: Pin::new(AtomicDevice::new(&self.cell)),
44                    a4: Pin::new(AtomicDevice::new(&self.cell)),
45                    a5: Pin::new(AtomicDevice::new(&self.cell)),
46                    a6: Pin::new(AtomicDevice::new(&self.cell)),
47                    a7: Pin::new(AtomicDevice::new(&self.cell)).try_into()?,
48
49                    b0: Pin::new(AtomicDevice::new(&self.cell)),
50                    b1: Pin::new(AtomicDevice::new(&self.cell)),
51                    b2: Pin::new(AtomicDevice::new(&self.cell)),
52                    b3: Pin::new(AtomicDevice::new(&self.cell)),
53                    b4: Pin::new(AtomicDevice::new(&self.cell)),
54                    b5: Pin::new(AtomicDevice::new(&self.cell)),
55                    b6: Pin::new(AtomicDevice::new(&self.cell)),
56                    b7: Pin::new(AtomicDevice::new(&self.cell)).try_into()?,
57                },
58                InterruptController::new(AtomicDevice::new(&self.cell)),
59            ))
60        }
61    }
62}