aboutsummaryrefslogtreecommitdiffstats
path: root/sw/deps/hd44780-driver/src/bus
diff options
context:
space:
mode:
Diffstat (limited to 'sw/deps/hd44780-driver/src/bus')
-rw-r--r--sw/deps/hd44780-driver/src/bus/eightbit.rs171
-rw-r--r--sw/deps/hd44780-driver/src/bus/fourbit.rs144
-rw-r--r--sw/deps/hd44780-driver/src/bus/i2c.rs71
-rw-r--r--sw/deps/hd44780-driver/src/bus/i2c_mcp23008.rs102
-rw-r--r--sw/deps/hd44780-driver/src/bus/mod.rs25
5 files changed, 513 insertions, 0 deletions
diff --git a/sw/deps/hd44780-driver/src/bus/eightbit.rs b/sw/deps/hd44780-driver/src/bus/eightbit.rs
new file mode 100644
index 0000000..99aff96
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/bus/eightbit.rs
@@ -0,0 +1,171 @@
+use embedded_hal::blocking::delay::{DelayMs, DelayUs};
+use embedded_hal::digital::v2::OutputPin;
+
+use crate::{
+ bus::DataBus,
+ error::{Error, Result},
+};
+
+pub struct EightBitBus<
+ RS: OutputPin,
+ EN: OutputPin,
+ D0: OutputPin,
+ D1: OutputPin,
+ D2: OutputPin,
+ D3: OutputPin,
+ D4: OutputPin,
+ D5: OutputPin,
+ D6: OutputPin,
+ D7: OutputPin,
+> {
+ rs: RS,
+ en: EN,
+ d0: D0,
+ d1: D1,
+ d2: D2,
+ d3: D3,
+ d4: D4,
+ d5: D5,
+ d6: D6,
+ d7: D7,
+}
+
+impl<
+ RS: OutputPin,
+ EN: OutputPin,
+ D0: OutputPin,
+ D1: OutputPin,
+ D2: OutputPin,
+ D3: OutputPin,
+ D4: OutputPin,
+ D5: OutputPin,
+ D6: OutputPin,
+ D7: OutputPin,
+ > EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>
+{
+ pub fn from_pins(
+ rs: RS,
+ en: EN,
+ d0: D0,
+ d1: D1,
+ d2: D2,
+ d3: D3,
+ d4: D4,
+ d5: D5,
+ d6: D6,
+ d7: D7,
+ ) -> EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7> {
+ EightBitBus {
+ rs,
+ en,
+ d0,
+ d1,
+ d2,
+ d3,
+ d4,
+ d5,
+ d6,
+ d7,
+ }
+ }
+
+ fn set_bus_bits(&mut self, data: u8) -> Result<()> {
+ let db0: bool = (0b0000_0001 & data) != 0;
+ let db1: bool = (0b0000_0010 & data) != 0;
+ let db2: bool = (0b0000_0100 & data) != 0;
+ let db3: bool = (0b0000_1000 & data) != 0;
+ let db4: bool = (0b0001_0000 & data) != 0;
+ let db5: bool = (0b0010_0000 & data) != 0;
+ let db6: bool = (0b0100_0000 & data) != 0;
+ let db7: bool = (0b1000_0000 & data) != 0;
+
+ if db0 {
+ self.d0.set_high().map_err(|_| Error)?;
+ } else {
+ self.d0.set_low().map_err(|_| Error)?;
+ }
+
+ if db1 {
+ self.d1.set_high().map_err(|_| Error)?;
+ } else {
+ self.d1.set_low().map_err(|_| Error)?;
+ }
+
+ if db2 {
+ self.d2.set_high().map_err(|_| Error)?;
+ } else {
+ self.d2.set_low().map_err(|_| Error)?;
+ }
+
+ if db3 {
+ self.d3.set_high().map_err(|_| Error)?;
+ } else {
+ self.d3.set_low().map_err(|_| Error)?;
+ }
+
+ if db4 {
+ self.d4.set_high().map_err(|_| Error)?;
+ } else {
+ self.d4.set_low().map_err(|_| Error)?;
+ }
+
+ if db5 {
+ self.d5.set_high().map_err(|_| Error)?;
+ } else {
+ self.d5.set_low().map_err(|_| Error)?;
+ }
+
+ if db6 {
+ self.d6.set_high().map_err(|_| Error)?;
+ } else {
+ self.d6.set_low().map_err(|_| Error)?;
+ }
+
+ if db7 {
+ self.d7.set_high().map_err(|_| Error)?;
+ } else {
+ self.d7.set_low().map_err(|_| Error)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl<
+ RS: OutputPin,
+ EN: OutputPin,
+ D0: OutputPin,
+ D1: OutputPin,
+ D2: OutputPin,
+ D3: OutputPin,
+ D4: OutputPin,
+ D5: OutputPin,
+ D6: OutputPin,
+ D7: OutputPin,
+ > DataBus for EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>
+{
+ fn write<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ byte: u8,
+ data: bool,
+ delay: &mut D,
+ ) -> Result<()> {
+ if data {
+ self.rs.set_high().map_err(|_| Error)?;
+ } else {
+ self.rs.set_low().map_err(|_| Error)?;
+ }
+
+ self.set_bus_bits(byte)?;
+
+ self.en.set_high().map_err(|_| Error)?;
+ delay.delay_ms(2u8);
+ self.en.set_low().map_err(|_| Error)?;
+
+ if data {
+ self.rs.set_low().map_err(|_| Error)?;
+ }
+
+ Ok(())
+ }
+}
diff --git a/sw/deps/hd44780-driver/src/bus/fourbit.rs b/sw/deps/hd44780-driver/src/bus/fourbit.rs
new file mode 100644
index 0000000..27519df
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/bus/fourbit.rs
@@ -0,0 +1,144 @@
+use embedded_hal::blocking::delay::{DelayMs, DelayUs};
+use embedded_hal::digital::v2::OutputPin;
+
+use crate::bus::DataBus;
+use crate::error::{Error, Result};
+
+pub struct FourBitBus<
+ RS: OutputPin,
+ EN: OutputPin,
+ D4: OutputPin,
+ D5: OutputPin,
+ D6: OutputPin,
+ D7: OutputPin,
+> {
+ rs: RS,
+ en: EN,
+ d4: D4,
+ d5: D5,
+ d6: D6,
+ d7: D7,
+}
+
+impl<RS: OutputPin, EN: OutputPin, D4: OutputPin, D5: OutputPin, D6: OutputPin, D7: OutputPin>
+ FourBitBus<RS, EN, D4, D5, D6, D7>
+{
+ pub fn from_pins(
+ rs: RS,
+ en: EN,
+ d4: D4,
+ d5: D5,
+ d6: D6,
+ d7: D7,
+ ) -> FourBitBus<RS, EN, D4, D5, D6, D7> {
+ FourBitBus {
+ rs,
+ en,
+ d4,
+ d5,
+ d6,
+ d7,
+ }
+ }
+
+ fn write_lower_nibble(&mut self, data: u8) -> Result<()> {
+ let db0: bool = (0b0000_0001 & data) != 0;
+ let db1: bool = (0b0000_0010 & data) != 0;
+ let db2: bool = (0b0000_0100 & data) != 0;
+ let db3: bool = (0b0000_1000 & data) != 0;
+
+ if db0 {
+ self.d4.set_high().map_err(|_| Error)?;
+ } else {
+ self.d4.set_low().map_err(|_| Error)?;
+ }
+
+ if db1 {
+ self.d5.set_high().map_err(|_| Error)?;
+ } else {
+ self.d5.set_low().map_err(|_| Error)?;
+ }
+
+ if db2 {
+ self.d6.set_high().map_err(|_| Error)?;
+ } else {
+ self.d6.set_low().map_err(|_| Error)?;
+ }
+
+ if db3 {
+ self.d7.set_high().map_err(|_| Error)?;
+ } else {
+ self.d7.set_low().map_err(|_| Error)?;
+ }
+
+ Ok(())
+ }
+
+ fn write_upper_nibble(&mut self, data: u8) -> Result<()> {
+ let db4: bool = (0b0001_0000 & data) != 0;
+ let db5: bool = (0b0010_0000 & data) != 0;
+ let db6: bool = (0b0100_0000 & data) != 0;
+ let db7: bool = (0b1000_0000 & data) != 0;
+
+ if db4 {
+ self.d4.set_high().map_err(|_| Error)?;
+ } else {
+ self.d4.set_low().map_err(|_| Error)?;
+ }
+
+ if db5 {
+ self.d5.set_high().map_err(|_| Error)?;
+ } else {
+ self.d5.set_low().map_err(|_| Error)?;
+ }
+
+ if db6 {
+ self.d6.set_high().map_err(|_| Error)?;
+ } else {
+ self.d6.set_low().map_err(|_| Error)?;
+ }
+
+ if db7 {
+ self.d7.set_high().map_err(|_| Error)?;
+ } else {
+ self.d7.set_low().map_err(|_| Error)?;
+ }
+ Ok(())
+ }
+}
+
+impl<RS: OutputPin, EN: OutputPin, D4: OutputPin, D5: OutputPin, D6: OutputPin, D7: OutputPin>
+ DataBus for FourBitBus<RS, EN, D4, D5, D6, D7>
+{
+ fn write<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ byte: u8,
+ data: bool,
+ delay: &mut D,
+ ) -> Result<()> {
+ if data {
+ self.rs.set_high().map_err(|_| Error)?;
+ } else {
+ self.rs.set_low().map_err(|_| Error)?;
+ }
+
+ self.write_upper_nibble(byte)?;
+
+ // Pulse the enable pin to recieve the upper nibble
+ self.en.set_high().map_err(|_| Error)?;
+ delay.delay_ms(2u8);
+ self.en.set_low().map_err(|_| Error)?;
+
+ self.write_lower_nibble(byte)?;
+
+ // Pulse the enable pin to recieve the lower nibble
+ self.en.set_high().map_err(|_| Error)?;
+ delay.delay_ms(2u8);
+ self.en.set_low().map_err(|_| Error)?;
+
+ if data {
+ self.rs.set_low().map_err(|_| Error)?;
+ }
+ Ok(())
+ }
+}
diff --git a/sw/deps/hd44780-driver/src/bus/i2c.rs b/sw/deps/hd44780-driver/src/bus/i2c.rs
new file mode 100644
index 0000000..160e205
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/bus/i2c.rs
@@ -0,0 +1,71 @@
+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 PCF8574 IC.
+/// Connections as follows:
+///
+/// <table>
+/// <tr><th>PCF8574 pin</th><th>name</th><th>LCD pin</th></tr>
+/// <tr><td>P0</td><td>RS</td><td>4</td></tr>
+/// <tr><td>P1</td><td>RW</td><td>5</td></tr>
+/// <tr><td>P2</td><td>E</td><td>6</td></tr>
+/// <tr><td>P3</td><td>Backlight</td><td></td></tr>
+/// <tr><td>P4</td><td>DB4</td><td>11</td></tr>
+/// <tr><td>P5</td><td>DB5</td><td>12</td></tr>
+/// <tr><td>P6</td><td>DB6</td><td>13</td></tr>
+/// <tr><td>P7</td><td>DB7</td><td>14</td></tr>
+/// </table>
+
+pub struct I2CBus<I2C: Write> {
+ i2c_bus: I2C,
+ address: u8,
+}
+
+const BACKLIGHT: u8 = 0b0000_1000;
+const ENABLE: u8 = 0b0000_0100;
+// const READ_WRITE: u8 = 0b0000_0010; // Not used as no reading of the `HD44780` is done
+const REGISTER_SELECT: u8 = 0b0000_0001;
+
+impl<I2C: Write> I2CBus<I2C> {
+ pub fn new(i2c_bus: I2C, address: u8) -> I2CBus<I2C> {
+ I2CBus { i2c_bus, address }
+ }
+
+ /// Write a nibble to the lcd
+ /// The nibble should be in the upper part of the byte
+ fn write_nibble<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ nibble: u8,
+ data: bool,
+ delay: &mut D,
+ ) {
+ let rs = match data {
+ false => 0u8,
+ true => REGISTER_SELECT,
+ };
+ let byte = nibble | rs | BACKLIGHT;
+
+ let _ = self.i2c_bus.write(self.address, &[byte, byte | ENABLE]);
+ delay.delay_ms(2u8);
+ let _ = self.i2c_bus.write(self.address, &[byte]);
+ }
+}
+
+impl<I2C: Write> DataBus for I2CBus<I2C> {
+ fn write<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ byte: u8,
+ data: bool,
+ delay: &mut D,
+ ) -> Result<()> {
+ let upper_nibble = byte & 0xF0;
+ self.write_nibble(upper_nibble, data, delay);
+
+ let lower_nibble = (byte & 0x0F) << 4;
+ self.write_nibble(lower_nibble, data, delay);
+
+ Ok(())
+ }
+}
diff --git a/sw/deps/hd44780-driver/src/bus/i2c_mcp23008.rs b/sw/deps/hd44780-driver/src/bus/i2c_mcp23008.rs
new file mode 100644
index 0000000..1ccb479
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/bus/i2c_mcp23008.rs
@@ -0,0 +1,102 @@
+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:
+///
+/// <table>
+/// <tr><th>MCP23008 pin</th><th>name</th><th>LCD pin</th></tr>
+/// <tr><td>0</td><td>N/C</td><td></td></tr>
+/// <tr><td>1</td><td>RS</td><td>4</td></tr>
+/// <tr><td>2</td><td>E</td><td>6</td></tr>
+/// <tr><td>3</td><td>DB4</td><td>11</td></tr>
+/// <tr><td>4</td><td>DB5</td><td>12</td></tr>
+/// <tr><td>5</td><td>DB6</td><td>13</td></tr>
+/// <tr><td>6</td><td>DB7</td><td>14</td></tr>
+/// <tr><td>7</td><td>Backlight</td><td></td></tr>
+/// </table>
+
+pub struct I2CMCP23008Bus<I2C: Write> {
+ i2c_bus: I2C,
+ address: u8,
+}
+
+const REG_IODIR : u8 = 0x00;
+const REG_GPIO : u8 = 0x09;
+
+impl<I2C: Write> I2CMCP23008Bus<I2C> {
+
+ /// 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<I2CMCP23008Bus<I2C>> {
+ 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<I2C: Write> DataBus for I2CMCP23008Bus<I2C> {
+ fn write<D: DelayUs<u16> + DelayMs<u8>>(
+ &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(())
+ }
+}
diff --git a/sw/deps/hd44780-driver/src/bus/mod.rs b/sw/deps/hd44780-driver/src/bus/mod.rs
new file mode 100644
index 0000000..b141f7e
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/bus/mod.rs
@@ -0,0 +1,25 @@
+use embedded_hal::blocking::delay::{DelayMs, DelayUs};
+
+mod eightbit;
+mod fourbit;
+mod i2c;
+mod i2c_mcp23008;
+
+pub use self::eightbit::EightBitBus;
+pub use self::fourbit::FourBitBus;
+pub use self::i2c::I2CBus;
+pub use self::i2c_mcp23008::I2CMCP23008Bus;
+
+use crate::error::Result;
+
+pub trait DataBus {
+ fn write<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ byte: u8,
+ data: bool,
+ delay: &mut D,
+ ) -> Result<()>;
+
+ // TODO
+ // fn read(...)
+}