1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
//! LP55231
//!
//! This is a driver for the [TI LP55231](http://www.ti.com/product/LP55231) RGB LED controller IC
//! using the [`embedded_hal`](https://github.com/rust-embedded/embedded-hal/) traits.
//!
//! NOTE that this driver is not yet platform agnostic, as it relies on `cortex_m` for a delay.
//!
//! This driver optionally takes a [digital output
//! pin](https://docs.rs/embedded-hal/0.2.1/embedded_hal/digital/trait.OutputPin.html) to control
//! power to the LP55231. It will drive the pin (digital) high on power-on, and (digital) low on
//! power-off.
#![no_std]
#![deny(missing_docs)]
extern crate embedded_hal as hal;
#[macro_use]
extern crate bitflags;
use core::fmt::Debug;
use hal::blocking::i2c::{Write, WriteRead};
use hal::digital::OutputPin;
pub mod registers;
use registers as reg;
#[derive(Debug)]
/// Error conditions returned by the LP55231
pub enum Error<I> {
/// The LP is not currently enabled
NotEnabled,
/// Generic I2c error
I2cError(I),
}
#[derive(Copy, Clone)]
/// Available I2C addresses for the part
pub enum Addr {
/// ASEL1=GND, ASEL2=GND
_0x32,
/// ASEL1=GND, ASEL2=VEN
_0x33,
/// ASEL1=VEN, ASEL2=GND
_0x34,
/// ASEL1=VEN, ASEL2=VEN
_0x35,
}
impl From<Addr> for u8 {
fn from(a: Addr) -> Self {
match a {
Addr::_0x32 => 0x32_u8,
Addr::_0x33 => 0x33_u8,
Addr::_0x34 => 0x34_u8,
Addr::_0x35 => 0x35_u8,
}
}
}
#[derive(Debug, Copy, Clone)]
/// Enumeration of the 9 LED lines from the chip
pub enum D {
/// LED line D1
D1,
/// LED line D2
D2,
/// LED line D3
D3,
/// LED line D4
D4,
/// LED line D5
D5,
/// LED line D6
D6,
/// LED line D7
D7,
/// LED line D8
D8,
/// LED line D9
D9,
}
impl From<D> for u8 {
fn from(d: D) -> Self {
match d {
D::D1 => 0,
D::D2 => 1,
D::D3 => 2,
D::D4 => 3,
D::D5 => 4,
D::D6 => 5,
D::D7 => 6,
D::D8 => 7,
D::D9 => 8,
}
}
}
/// The LP55231 device
pub struct Lp55231<I, P> {
/// The owned I2C bus
i2c: I,
/// The owned enable pin
en_pin: Option<P>,
/// The I2C address of this device
addr: u8,
/// Has the LP55231 been enabled
en: bool,
}
impl<E, I, P> Lp55231<I, P>
where
E: Debug,
I: Write<Error = E> + WriteRead<Error = E>,
P: OutputPin,
{
/// Create a new instance of an LP55231 that exclusively owns its I2C bus. Optionally takes a
/// power control pin.
pub fn new(i2c: I, en_pin: Option<P>, addr: Addr) -> Self {
Lp55231 {
i2c,
en_pin,
addr: u8::from(addr) << 1,
en: false,
}
}
/// Convenience method to call `self.i2c.write` with `self.addr`
fn send(&mut self, bytes: &[u8]) -> Result<(), Error<E>> {
if self.en {
self.i2c.write(self.addr, bytes).map_err(|e| Error::I2cError(e))
} else {
Err(Error::NotEnabled)
}
}
/// Enable the device for use
///
/// Sets the enable line high, then sends an enable command, waits 500us, and then configures
/// to device to use its internal clock, enable the charge pump at 1.5x boost, and
/// auto-increment on writes.
pub fn enable(&mut self) -> Result<(), Error<E>> {
if let Some(p) = self.en_pin.as_mut() {
p.set_high();
}
// TODO there should be a 500us delay here, but the chip appears to mostly work without it,
// so I'm not going to worry about it now. Ideally, this function should take a
// `embedded_hal::delay::Delay` and wait.
self.en = true;
self.send(&[reg::CNTRL1, (reg::Cntrl1::CHIP_EN).bits()])?;
self.send(&[
reg::MISC,
(reg::Misc::INT_CLK_EN
| reg::Misc::CLK_DET_EN
| reg::Misc::CP_MODE_1_5x
| reg::Misc::EN_AUTO_INCR)
.bits(),
])?;
Ok(())
}
/// Soft-reset the device NOW
pub fn reset(&mut self) -> Result<(), Error<E>> {
self.send(&[reg::Reset::RESET_NOW.bits()])?;
Ok(())
}
/// Turn off the device NOW
pub fn disable(&mut self) {
if let Some(p) = self.en_pin.as_mut() {
p.set_low();
}
self.en = false;
}
/// Set the D line to the provided PWM value
pub fn set_pwm(&mut self, d: D, pwm: u8) -> Result<(), Error<E>> {
self.send(&[reg::D_PWM_BASE + u8::from(d), pwm])?;
Ok(())
}
}