use embedded_hal::blocking::delay::{DelayMs, DelayUs};
use embedded_hal::blocking::i2c::Write;
use crate::{bus::DataBus, error::Result};
/// This module supports I2C backpacks with a MCP23008 IC, like
/// the one from adafruit.
/// Connections as follows:
///
///
/// MCP23008 pin | name | LCD pin |
/// 0 | N/C | |
/// 1 | RS | 4 |
/// 2 | E | 6 |
/// 3 | DB4 | 11 |
/// 4 | DB5 | 12 |
/// 5 | DB6 | 13 |
/// 6 | DB7 | 14 |
/// 7 | Backlight | |
///
pub struct I2CMCP23008Bus {
i2c_bus: I2C,
address: u8,
}
const REG_IODIR : u8 = 0x00;
const REG_GPIO : u8 = 0x09;
impl I2CMCP23008Bus {
/// Create a new instance of the MCP23008 I2C driver. The address of those
/// devices is 0b010_0xxx where x is configured by bootstrap pins.
pub fn new(i2c_bus: I2C, address: u8) -> Result> {
let mut mcp23008 = I2CMCP23008Bus { i2c_bus, address };
// Set to reset values according to datasheet
mcp23008.write_reg(REG_IODIR, 0b1111_1111)?;
for reg in 0x01usize..0x0A {
mcp23008.write_reg(reg as u8, 0)?;
}
// Configure pins 1..=7 as outputs, see pin mapping above
mcp23008.write_reg(REG_IODIR, 0b0000_0001)?;
Ok(mcp23008)
}
fn write_reg(&mut self, reg: u8, value: u8) -> Result<()> {
let data = [reg, value];
self.i2c_bus.write(self.address, &data)
.map_err(|_| crate::error::Error)
}
fn set_pins(&mut self, pins: u8) -> Result<()> {
self.write_reg(REG_GPIO, pins)
}
}
impl DataBus for I2CMCP23008Bus {
fn write + DelayMs>(
&mut self,
byte: u8,
data: bool,
delay: &mut D,
) -> Result<()> {
let rs = if data { 0b10 } else { 0b00 };
let en = 0b0000_0100;
let backlight = 0b1000_0000; // always enable backlight
let upper_nibble = (byte & 0xF0) >> 4;
let lower_nibble = byte & 0x0F;
// upper nibble: [d7 d6 d5 d4]
// Pulse EN
// lower nibble: [d3 d2 d1 d0]
// Pulse EN
let pins = rs | backlight | (upper_nibble << 3);
self.set_pins(pins)?;
delay.delay_ms(1);
let pins = rs | en | backlight | (upper_nibble << 3);
self.set_pins(pins)?;
delay.delay_ms(1);
let pins = rs | backlight | (lower_nibble << 3);
self.set_pins(pins)?;
delay.delay_ms(1);
let pins = rs | en | backlight | (lower_nibble << 3);
self.set_pins(pins)?;
delay.delay_ms(1);
let pins = backlight | (lower_nibble << 3);
self.set_pins(pins)?;
Ok(())
}
}