From 5d1cff57f9f5acd740a8b5f8c941beefdcc00176 Mon Sep 17 00:00:00 2001 From: "Matthias P. Braendli" Date: Sun, 28 Jun 2020 16:42:21 +0200 Subject: sw: configure si5351 --- sw/deps/hd44780-driver/src/bus/eightbit.rs | 171 +++++++++++++++++++++++++ sw/deps/hd44780-driver/src/bus/fourbit.rs | 144 +++++++++++++++++++++ sw/deps/hd44780-driver/src/bus/i2c.rs | 71 ++++++++++ sw/deps/hd44780-driver/src/bus/i2c_mcp23008.rs | 102 +++++++++++++++ sw/deps/hd44780-driver/src/bus/mod.rs | 25 ++++ 5 files changed, 513 insertions(+) create mode 100644 sw/deps/hd44780-driver/src/bus/eightbit.rs create mode 100644 sw/deps/hd44780-driver/src/bus/fourbit.rs create mode 100644 sw/deps/hd44780-driver/src/bus/i2c.rs create mode 100644 sw/deps/hd44780-driver/src/bus/i2c_mcp23008.rs create mode 100644 sw/deps/hd44780-driver/src/bus/mod.rs (limited to 'sw/deps/hd44780-driver/src/bus') 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 +{ + 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 { + 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 +{ + fn write + DelayMs>( + &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 + FourBitBus +{ + pub fn from_pins( + rs: RS, + en: EN, + d4: D4, + d5: D5, + d6: D6, + d7: D7, + ) -> FourBitBus { + 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 + DataBus for FourBitBus +{ + fn write + DelayMs>( + &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: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
PCF8574 pinnameLCD pin
P0RS4
P1RW5
P2E6
P3Backlight
P4DB411
P5DB512
P6DB613
P7DB714
+ +pub struct I2CBus { + 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 I2CBus { + pub fn new(i2c_bus: I2C, address: u8) -> I2CBus { + I2CBus { i2c_bus, address } + } + + /// Write a nibble to the lcd + /// The nibble should be in the upper part of the byte + fn write_nibble + DelayMs>( + &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 DataBus for I2CBus { + fn write + DelayMs>( + &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: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
MCP23008 pinnameLCD pin
0N/C
1RS4
2E6
3DB411
4DB512
5DB613
6DB714
7Backlight
+ +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(()) + } +} 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 + DelayMs>( + &mut self, + byte: u8, + data: bool, + delay: &mut D, + ) -> Result<()>; + + // TODO + // fn read(...) +} -- cgit v1.2.3