Expand description
PCA9535 driver using embedded-hal
§Device
The PCA9535 and PCA9535C are 16-bit IO-Expanders using the I2C/SMBus interface. The devices operate at a voltage level of 2.3-5.5V
§GPIO
The expander provides two 5V tolerant GPIO banks with eight pins. Each pin is configurable separately as either input or output and additionally allows for polarity inversion. The open-drain interrupt output of the device indicates a change if any of the input states differs from the state of the input port register.
On initialization, all pins are configured as high-impedance inputs. The PCA9535 features totem pole IOs, while the PCA9535C IOs are open-drain.
§I2C
The device uses 7Bit addressing and allows the hardware configuration of the first 3 address bits, allowing for up to 8 expanders on the same bus.
§General info
The library uses the blocking I2C embedded-hal traits. Each implementation of Expander
owns the provided I2C instance.
If multiple drivers/devices need access to the same I2C bus, sharing the bus using crates like embedded-hal-bus is recommended.
§Usage
This library can be used in multiple ways depending on the use case and needs.
§Operation types
The device has two possible configurations on how i2c bus traffic is handled:
§Immediate
The immediate expander interface Pca9535Immediate
issues an i2c bus transaction on each function call, which changes the state of the expander.
It does not make use of the open drain interrupt output of the device to reduce bus traffic and does not hold any state on the device registers.
use rppal::i2c::I2c;
use pca9535::Pca9535Immediate;
let i2c = I2c::new().unwrap();
let address = 32;
let expander = Pca9535Immediate::new(i2c, address);
§Cached
The cached expander interface Pca9535Cached
stores the state of the device registers internally to reduce the i2c bus traffic as much as possible.
It relies on the open drain interrupt pin of the device to detect any changes to the registers. Thus, the use of this hardware pin is mandatory for this interface.
use rppal::i2c::I2c;
use rppal::gpio::Gpio;
use pca9535::Pca9535Cached;
let gpio = Gpio::new().unwrap();
//A HAL GPIO Input pin which is connected to the interrupt pin of the IO Expander
let expander_interrupt_pin = gpio.get(0).unwrap().into_input();
let i2c = I2c::new().unwrap();
let address = 32;
let expander = Pca9535Cached::new(i2c, address, expander_interrupt_pin, true); // create cached expander and initialize cache to defaults
§Usage types
Once the operation type has been determined, there are two ways of interacting with the IO expander:
§Standard Expander Interface
Every Expander
implements the StandardExpanderInterface
. This interface offers various functions to interact with the expander.
Those functions do not hold any state of whether the pins are currently configured as inputs or outputs. The user needs to ensure that the pins are in the desired configuration
before calling other functions to get valid and expected results.
use rppal::i2c::I2c;
use pca9535::GPIOBank;
use pca9535::StandardExpanderInterface;
use pca9535::Pca9535Immediate;
let i2c = I2c::new().unwrap();
let address = 32;
let mut expander = Pca9535Immediate::new(i2c, address); //Either Immediate or Cached expander
expander.pin_into_output(GPIOBank::Bank0, 3).unwrap();
expander.pin_set_high(GPIOBank::Bank0, 3).unwrap();
// and so on...
§Expander HAL Pins
This interface offers the possibility to use the GPIO of the IO expander as hal
pins, either to use for other hal
librariers or just as a standardized way to handle GPIOs.
As this is a special interface which is sync and can be used across multiple threads etc. the operation types need to be wrapped into an IoExpander
type.
use std::sync::Mutex;
use rppal::i2c::I2c;
use pca9535::IoExpander;
use pca9535::Pca9535Immediate;
let i2c = I2c::new().unwrap();
let address = 32;
let mut expander = Pca9535Immediate::new(i2c, address); //Either Immediate or Cached expander
let io_expander: IoExpander<_, _, Mutex<_>> = IoExpander::new(expander); // Wrapped expander in std environment using Mutex as ExpanderMutex
Using this wrapper, the expander gets automatically wrapped into an ExpanderMutex
, which ensures exclusive access to the expander and makes it Sync
.
Currently, ExpanderMutex is only implemented for the std
environment. You can activate this implementation by enabling the “std” feature of this crate. For other architectures on bare metal, etc.
The ExpanderMutex trait can be implemented on any type, which ensures exclusive access to the contained data. Once this is done, the expander can be wrapped inside an IoExpander as described previously
using the newly implemented ExpanderMutex trait.
Now, it is possible to generate either ExpanderInputPin
or ExpanderOutputPin
and manipulate the IO expander through those pins.
They implement all the standard hal
traits on GPIO pins and could theoretically also be used in other libraries requiring hal GPIO pins.
use std::sync::Mutex;
use rppal::i2c::I2c;
use hal::digital::{InputPin, OutputPin};
use pca9535::IoExpander;
use pca9535::Pca9535Immediate;
use pca9535::{ExpanderInputPin, ExpanderOutputPin};
use pca9535::GPIOBank::{Bank0, Bank1};
use pca9535::PinState;
let i2c = I2c::new().unwrap();
let address = 32;
let mut expander = Pca9535Immediate::new(i2c, address);
let io_expander: IoExpander<_, _, Mutex<_>> = IoExpander::new(expander);
let mut expander_pin_1_5 = ExpanderInputPin::new(&io_expander, Bank1, 5).unwrap();
let mut expander_pin_0_2 = ExpanderOutputPin::new(&io_expander, Bank0, 2, PinState::Low).unwrap();
expander_pin_0_2.set_high();
let is_high = expander_pin_1_5.is_high();
// and so on...
Re-exports§
pub use expander::cached::Pca9535Cached;
pub use expander::immediate::Pca9535Immediate;
pub use expander::io::IoExpander;
pub use expander::standard::StandardExpanderInterface;
pub use expander::Expander;
pub use expander::ExpanderError;
pub use expander::SyncExpander;
pub use mutex::ExpanderMutex;
pub use pin::ExpanderInputPin;
pub use pin::ExpanderOutputPin;
Modules§
- expander
- Contains all available Expander interfaces and traits.
- mutex
- Contains the ExpanderMutex Trait to use an Expander accross threads.
- pin
- Contains the implementation of the hal-pin usage inteface.