aboutsummaryrefslogtreecommitdiffstats
path: root/sw/deps/hd44780-driver
diff options
context:
space:
mode:
Diffstat (limited to 'sw/deps/hd44780-driver')
-rw-r--r--sw/deps/hd44780-driver/.gitignore13
-rw-r--r--sw/deps/hd44780-driver/.travis.yml8
-rw-r--r--sw/deps/hd44780-driver/Cargo.toml15
-rw-r--r--sw/deps/hd44780-driver/LICENSE21
-rw-r--r--sw/deps/hd44780-driver/README.md75
-rw-r--r--sw/deps/hd44780-driver/examples/.gitignore2
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/.cargo/config13
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/.gdbinit20
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/Cargo.toml29
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/examples/4bit.rs71
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/examples/basic.rs67
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/examples/scrolling.rs91
-rw-r--r--sw/deps/hd44780-driver/examples/metro_m0/memory.x8
-rw-r--r--sw/deps/hd44780-driver/examples/raspberrypi/.gitignore1
-rw-r--r--sw/deps/hd44780-driver/examples/raspberrypi/Cargo.toml8
-rw-r--r--sw/deps/hd44780-driver/examples/raspberrypi/src/main.rs75
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/.cargo/config9
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/.gitignore5
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/Cargo.toml23
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/README3
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/build.rs15
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/memory.x5
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.cfg12
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.gdb32
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x-i2c/src/main.rs52
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/.cargo/config9
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/.gitignore5
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/Cargo.toml23
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/README3
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/build.rs15
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/memory.x5
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/openocd.cfg12
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/openocd.gdb32
-rw-r--r--sw/deps/hd44780-driver/examples/stm32f30x/src/main.rs55
-rw-r--r--sw/deps/hd44780-driver/header.gifbin0 -> 2071130 bytes
-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
-rw-r--r--sw/deps/hd44780-driver/src/display_mode.rs95
-rw-r--r--sw/deps/hd44780-driver/src/entry_mode.rs97
-rw-r--r--sw/deps/hd44780-driver/src/error.rs3
-rw-r--r--sw/deps/hd44780-driver/src/lib.rs552
44 files changed, 2092 insertions, 0 deletions
diff --git a/sw/deps/hd44780-driver/.gitignore b/sw/deps/hd44780-driver/.gitignore
new file mode 100644
index 0000000..c8bdb63
--- /dev/null
+++ b/sw/deps/hd44780-driver/.gitignore
@@ -0,0 +1,13 @@
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
+Cargo.lock
+
+# These are backup files generated by rustfmt
+**/*.rs.bk
+
+/target
+**/*.rs.bk
diff --git a/sw/deps/hd44780-driver/.travis.yml b/sw/deps/hd44780-driver/.travis.yml
new file mode 100644
index 0000000..bc6c006
--- /dev/null
+++ b/sw/deps/hd44780-driver/.travis.yml
@@ -0,0 +1,8 @@
+language: rust
+
+rust:
+ - stable
+ - beta
+ - nightly
+
+cache: cargo \ No newline at end of file
diff --git a/sw/deps/hd44780-driver/Cargo.toml b/sw/deps/hd44780-driver/Cargo.toml
new file mode 100644
index 0000000..b6bd9e8
--- /dev/null
+++ b/sw/deps/hd44780-driver/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "hd44780-driver"
+version = "0.3.0"
+edition = "2018"
+keywords = ["no-std", "lcd", "embedded-hal-driver", "embedded-hal", "hd44780"]
+categories = ["embedded", "hardware-support", "no-std"]
+description = "A crate to use HD44780 compliant displays with embedded-hal"
+authors = ["John Doneth <doneth7@gmail.com>"]
+license = "MIT"
+repository = "https://github.com/JohnDoneth/hd44780-driver"
+documentation = "https://docs.rs/hd44780-driver"
+readme = "README.md"
+
+[dependencies]
+embedded-hal = "0.2.3"
diff --git a/sw/deps/hd44780-driver/LICENSE b/sw/deps/hd44780-driver/LICENSE
new file mode 100644
index 0000000..3ec01c6
--- /dev/null
+++ b/sw/deps/hd44780-driver/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 John Doneth
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/sw/deps/hd44780-driver/README.md b/sw/deps/hd44780-driver/README.md
new file mode 100644
index 0000000..cd692f5
--- /dev/null
+++ b/sw/deps/hd44780-driver/README.md
@@ -0,0 +1,75 @@
+# hd44780-driver
+
+[![crates.io](https://img.shields.io/crates/v/hd44780-driver.svg)](https://crates.io/crates/hd44780-driver)
+[![crates.io](https://img.shields.io/crates/d/hd44780-driver.svg)](https://crates.io/crates/hd44780-driver)
+[![crates.io](https://img.shields.io/crates/l/hd44780-driver.svg)](https://crates.io/crates/hd44780-driver)
+[![travis-ci.org](https://travis-ci.org/JohnDoneth/hd44780-driver.svg?branch=master)](https://travis-ci.org/JohnDoneth/hd44780-driver)
+
+Implementation of the `embedded-hal` traits for the HD44780.
+
+![](/header.gif)
+
+
+### Documentation
+
+Crates.io - https://docs.rs/hd44780-driver
+
+### Examples
+
+Currently there are basic examples for **Raspberry Pi** as well as the **Adafruit Metro Express M0** as those are the devices I currently have on hand.
+
+Any platform that implements the [embedded-hal](https://github.com/rust-embedded/embedded-hal) traits is supported by this library! See [awesome-embedded-rust](https://github.com/rust-embedded/awesome-embedded-rust#hal-implementation-crates) for a list of supported platforms.
+
+### Getting Started
+
+This library aims to keep it simple in that to get started all you will have to do is supply the `HD44780::new` function a bunch of pins from your platform that implement the `OutputPin` trait for [embedded-hal](https://github.com/rust-embedded/embedded-hal) as well as a struct that implements the delay traits `DelayUs<u16>` and `DelayMs<u8>`.
+
+```rust
+// Code grabbed from the metro_m0 example
+let mut lcd = HD44780::new_4bit(
+ pins.d4.into_open_drain_output(&mut pins.port), // Register Select pin
+ pins.d3.into_open_drain_output(&mut pins.port), // Enable pin
+
+ pins.d9.into_open_drain_output(&mut pins.port), // d4
+ pins.d10.into_open_drain_output(&mut pins.port), // d5
+ pins.d11.into_open_drain_output(&mut pins.port), // d6
+ pins.d12.into_open_drain_output(&mut pins.port), // d7
+
+ delay,
+);
+
+// Unshift display and set cursor to 0
+lcd.reset();
+
+// Clear existing characters
+lcd.clear();
+
+// Display the following string
+lcd.write_str("Hello, world!");
+
+// Move the cursor to the second line
+lcd.set_cursor_pos(40);
+
+// Display the following string on the second line
+lcd.write_str("I'm on line 2!");
+```
+
+### Features
+- 4-bit & 8-bit modes are supported
+- Support for I2C backpacks based on PCF8574 and MCP23008 port expanders
+
+### Todo
+- Busy flag support (Waiting for support from [embedded-hal](https://github.com/rust-embedded/embedded-hal) to read and write from a pin)
+- Non-blocking API
+- A more user-friendly API with additional features
+- Custom characters
+
+### Contributing
+
+- Additional issues as well as pull-requests are welcome.
+
+- If you have a platform not yet covered in this repository that is supported by [embedded-hal](https://github.com/rust-embedded/embedded-hal), a pull-request of an example would be awesome!
+
+### License
+
+This project is licensed under MIT license ([LICENSE](https://github.com/kunerd/clerk/blob/master/docs/CONTRIBUTING.md) or <https://opensource.org/licenses/MIT>)
diff --git a/sw/deps/hd44780-driver/examples/.gitignore b/sw/deps/hd44780-driver/examples/.gitignore
new file mode 100644
index 0000000..fd8951e
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/.gitignore
@@ -0,0 +1,2 @@
+target
+cargo.lock \ No newline at end of file
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/.cargo/config b/sw/deps/hd44780-driver/examples/metro_m0/.cargo/config
new file mode 100644
index 0000000..ce9679d
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/.cargo/config
@@ -0,0 +1,13 @@
+# samd21 is a Cortex-M0 and thus thumbv6m
+
+[build]
+target = "thumbv6m-none-eabi"
+
+[target.thumbv6m-none-eabi]
+runner = 'arm-none-eabi-gdb'
+rustflags = [
+ "-C", "link-arg=-Tlink.x",
+ "-C", "linker=lld",
+ "-Z", "linker-flavor=ld.lld",
+ "-Z", "thinlto=no",
+] \ No newline at end of file
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/.gdbinit b/sw/deps/hd44780-driver/examples/metro_m0/.gdbinit
new file mode 100644
index 0000000..7b9b83b
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/.gdbinit
@@ -0,0 +1,20 @@
+set auto-load safe-path /
+
+# print demangled symbols by default
+set print asm-demangle on
+
+# JLink
+target extended-remote :2331
+monitor flash breakpoints 1
+# allow hprints to show up in gdb
+monitor semihosting enable
+monitor semihosting IOClient 3
+
+monitor reset
+load
+
+# OpenOCD
+#target extended-remote :3333
+#monitor arm semihosting enable
+#load
+#step \ No newline at end of file
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/Cargo.toml b/sw/deps/hd44780-driver/examples/metro_m0/Cargo.toml
new file mode 100644
index 0000000..bd88b22
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/Cargo.toml
@@ -0,0 +1,29 @@
+[package]
+name = "metro_m0_hd44780_examples"
+version = "0.2.0"
+authors = ["John Doneth <doneth7@gmail.com>"]
+keywords = ["no-std", "arm", "cortex-m", "embedded-hal"]
+license = "MIT"
+
+[dependencies]
+cortex-m = "~0.4"
+hd44780-driver = { path = "../.." }
+atsamd21-hal = "~0.1"
+embedded-hal = "~0.2"
+metro_m0 = { git = "https://github.com/wez/atsamd21-rs.git" }
+
+cortex-m-rt = "*"
+
+[dev-dependencies]
+panic-abort = "~0.1"
+panic-semihosting = "~0.1"
+cortex-m-semihosting = "~0.2"
+cortex-m-rtfm = "~0.3"
+sx1509 = "~0.2"
+
+[features]
+# ask the HAL to enable atsamd21g18a support
+default = ["rt", "atsamd21-hal/samd21g18a"]
+rt = ["atsamd21-hal/rt"]
+unproven = ["atsamd21-hal/unproven"]
+use_semihosting = []
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/examples/4bit.rs b/sw/deps/hd44780-driver/examples/metro_m0/examples/4bit.rs
new file mode 100644
index 0000000..5cf46c3
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/examples/4bit.rs
@@ -0,0 +1,71 @@
+#![feature(used)]
+#![no_std]
+
+extern crate cortex_m_semihosting;
+
+#[cfg(not(feature = "use_semihosting"))]
+extern crate panic_abort;
+
+#[cfg(feature = "use_semihosting")]
+extern crate panic_semihosting;
+
+extern crate cortex_m;
+extern crate cortex_m_rt;
+extern crate atsamd21_hal;
+extern crate metro_m0;
+
+use metro_m0::clock::GenericClockController;
+use metro_m0::delay::Delay;
+use metro_m0::{CorePeripherals, Peripherals};
+
+extern crate hd44780_driver;
+
+use hd44780_driver::HD44780;
+
+extern crate embedded_hal;
+
+fn main() {
+ let mut peripherals = Peripherals::take().unwrap();
+
+ let core = CorePeripherals::take().unwrap();
+
+ let mut clocks = GenericClockController::new(
+ peripherals.GCLK,
+ &mut peripherals.PM,
+ &mut peripherals.SYSCTRL,
+ &mut peripherals.NVMCTRL,
+ );
+
+ let mut pins = metro_m0::pins(peripherals.PORT);
+ let delay = Delay::new(core.SYST, &mut clocks);
+
+ let mut lcd = HD44780::new_4bit(
+
+ pins.d4.into_open_drain_output(&mut pins.port), // Register Select pin
+ pins.d3.into_open_drain_output(&mut pins.port), // Enable pin
+
+ pins.d9.into_open_drain_output(&mut pins.port), // d4
+ pins.d10.into_open_drain_output(&mut pins.port), // d5
+ pins.d11.into_open_drain_output(&mut pins.port), // d6
+ pins.d12.into_open_drain_output(&mut pins.port), // d7
+
+ delay,
+ );
+
+ // Unshift display and set cursor to 0
+ lcd.reset();
+
+ // Clear existing characters
+ lcd.clear();
+
+ // Display the following string
+ lcd.write_str("Hello, world!");
+
+ // Move the cursor to the second line
+ lcd.set_cursor_pos(40);
+
+ // Display the following string on the second line
+ lcd.write_str("I'm on line 2!");
+
+ loop { }
+}
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/examples/basic.rs b/sw/deps/hd44780-driver/examples/metro_m0/examples/basic.rs
new file mode 100644
index 0000000..2adb5b0
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/examples/basic.rs
@@ -0,0 +1,67 @@
+#![feature(used)]
+#![no_std]
+
+extern crate cortex_m_semihosting;
+
+#[cfg(not(feature = "use_semihosting"))]
+extern crate panic_abort;
+
+#[cfg(feature = "use_semihosting")]
+extern crate panic_semihosting;
+
+extern crate cortex_m;
+extern crate cortex_m_rt;
+extern crate atsamd21_hal;
+extern crate metro_m0;
+
+use metro_m0::clock::GenericClockController;
+use metro_m0::delay::Delay;
+use metro_m0::{CorePeripherals, Peripherals};
+
+extern crate hd44780_driver;
+
+use hd44780_driver::HD44780;
+
+fn main() {
+ let mut peripherals = Peripherals::take().unwrap();
+
+ let core = CorePeripherals::take().unwrap();
+
+ let mut clocks = GenericClockController::new(
+ peripherals.GCLK,
+ &mut peripherals.PM,
+ &mut peripherals.SYSCTRL,
+ &mut peripherals.NVMCTRL,
+ );
+
+ let mut pins = metro_m0::pins(peripherals.PORT);
+ let delay = Delay::new(core.SYST, &mut clocks);
+
+ let mut lcd = HD44780::new_8bit(
+
+ pins.d4.into_open_drain_output(&mut pins.port), // Register Select pin
+ pins.d3.into_open_drain_output(&mut pins.port), // Enable pin
+
+ pins.d5.into_open_drain_output(&mut pins.port), // d0
+ pins.d6.into_open_drain_output(&mut pins.port), // d1
+ pins.d7.into_open_drain_output(&mut pins.port), // d2
+ pins.d8.into_open_drain_output(&mut pins.port), // d3
+ pins.d9.into_open_drain_output(&mut pins.port), // d4
+ pins.d10.into_open_drain_output(&mut pins.port), // d5
+ pins.d11.into_open_drain_output(&mut pins.port), // d6
+ pins.d12.into_open_drain_output(&mut pins.port), // d7
+
+ delay,
+ );
+
+ // Unshift display and set cursor to 0
+ lcd.reset();
+
+ // Clear existing characters
+ lcd.clear();
+
+ // Display the following string
+ lcd.write_str("Hello, world!");
+
+ loop { }
+}
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/examples/scrolling.rs b/sw/deps/hd44780-driver/examples/metro_m0/examples/scrolling.rs
new file mode 100644
index 0000000..f02a752
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/examples/scrolling.rs
@@ -0,0 +1,91 @@
+#![feature(used)]
+#![no_std]
+
+extern crate cortex_m_semihosting;
+
+#[cfg(not(feature = "use_semihosting"))]
+extern crate panic_abort;
+
+#[cfg(feature = "use_semihosting")]
+extern crate panic_semihosting;
+
+extern crate cortex_m;
+extern crate cortex_m_rt;
+extern crate atsamd21_hal;
+extern crate metro_m0;
+
+use metro_m0::clock::GenericClockController;
+use metro_m0::delay::Delay;
+use metro_m0::{CorePeripherals, Peripherals};
+
+extern crate hd44780_driver;
+
+use hd44780_driver::{HD44780, DisplayMode, Display, Cursor, CursorBlink};
+
+extern crate embedded_hal;
+
+fn busy_loop(){
+ #[allow(unused_variables)]
+ let mut i = 0;
+
+ for _ in 0..50000 {
+ i += 1;
+ }
+}
+
+fn main() {
+ let mut peripherals = Peripherals::take().unwrap();
+
+ let core = CorePeripherals::take().unwrap();
+
+ let mut clocks = GenericClockController::new(
+ peripherals.GCLK,
+ &mut peripherals.PM,
+ &mut peripherals.SYSCTRL,
+ &mut peripherals.NVMCTRL,
+ );
+
+ let mut pins = metro_m0::pins(peripherals.PORT);
+ let delay = Delay::new(core.SYST, &mut clocks);
+
+ let mut lcd = HD44780::new_8bit(
+
+ pins.d4.into_open_drain_output(&mut pins.port), // Register Select pin
+ pins.d3.into_open_drain_output(&mut pins.port), // Enable pin
+
+ pins.d5.into_open_drain_output(&mut pins.port), // d0
+ pins.d6.into_open_drain_output(&mut pins.port), // d1
+ pins.d7.into_open_drain_output(&mut pins.port), // d2
+ pins.d8.into_open_drain_output(&mut pins.port), // d3
+ pins.d9.into_open_drain_output(&mut pins.port), // d4
+ pins.d10.into_open_drain_output(&mut pins.port), // d5
+ pins.d11.into_open_drain_output(&mut pins.port), // d6
+ pins.d12.into_open_drain_output(&mut pins.port), // d7
+
+ delay,
+ );
+
+ //lcd.set_cursor_mode(CursorMode::Increment);
+ lcd.set_autoscroll(true);
+
+ lcd.set_display_mode(DisplayMode {
+ cursor_visible : Cursor::Invisible,
+ cursor_blink : CursorBlink::On,
+ display_visible : Display::On,
+ });
+
+ let string = "Hello, world! ";
+
+ // Display the following string
+ loop {
+
+ for c in string.chars() {
+ lcd.write_char(c);
+
+ busy_loop();
+ }
+
+ }
+
+
+}
diff --git a/sw/deps/hd44780-driver/examples/metro_m0/memory.x b/sw/deps/hd44780-driver/examples/metro_m0/memory.x
new file mode 100644
index 0000000..859903b
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/metro_m0/memory.x
@@ -0,0 +1,8 @@
+MEMORY
+{
+ /* Leave 8k for the default bootloader on the Metro M0 */
+ FLASH (rx) : ORIGIN = 0x00000000 + 8K, LENGTH = 256K - 8K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+_stack_start = ORIGIN(RAM) + LENGTH(RAM);
+
diff --git a/sw/deps/hd44780-driver/examples/raspberrypi/.gitignore b/sw/deps/hd44780-driver/examples/raspberrypi/.gitignore
new file mode 100644
index 0000000..2bf0f84
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/raspberrypi/.gitignore
@@ -0,0 +1 @@
+.cargo \ No newline at end of file
diff --git a/sw/deps/hd44780-driver/examples/raspberrypi/Cargo.toml b/sw/deps/hd44780-driver/examples/raspberrypi/Cargo.toml
new file mode 100644
index 0000000..db5d98f
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/raspberrypi/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "raspberrypi-hd44780-example"
+version = "0.2.0"
+authors = ["John Doneth <Doneth7@gmail.com>"]
+
+[dependencies]
+linux-embedded-hal = "0.2"
+hd44780-driver = { path = "../.." }
diff --git a/sw/deps/hd44780-driver/examples/raspberrypi/src/main.rs b/sw/deps/hd44780-driver/examples/raspberrypi/src/main.rs
new file mode 100644
index 0000000..2fefcbe
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/raspberrypi/src/main.rs
@@ -0,0 +1,75 @@
+extern crate linux_embedded_hal;
+extern crate hd44780_driver;
+
+use linux_embedded_hal::{Delay, Pin};
+use linux_embedded_hal::sysfs_gpio::Direction;
+
+use hd44780_driver::{HD44780, DisplayMode, Cursor, CursorBlink, Display};
+
+fn main() {
+
+ let rs = Pin::new(26);
+ let en = Pin::new(22);
+
+ let db0 = Pin::new(19);
+ let db1 = Pin::new(13);
+ let db2 = Pin::new(6);
+ let db3 = Pin::new(5);
+ let db4 = Pin::new(21);
+ let db5 = Pin::new(20);
+ let db6 = Pin::new(16);
+ let db7 = Pin::new(12);
+
+ rs.export().unwrap();
+ en.export().unwrap();
+
+ db0.export().unwrap();
+ db1.export().unwrap();
+ db2.export().unwrap();
+ db3.export().unwrap();
+ db4.export().unwrap();
+ db5.export().unwrap();
+ db6.export().unwrap();
+ db7.export().unwrap();
+
+ rs.set_direction(Direction::Low).unwrap();
+ en.set_direction(Direction::Low).unwrap();
+
+ db0.set_direction(Direction::Low).unwrap();
+ db1.set_direction(Direction::Low).unwrap();
+ db2.set_direction(Direction::Low).unwrap();
+ db3.set_direction(Direction::Low).unwrap();
+ db4.set_direction(Direction::Low).unwrap();
+ db5.set_direction(Direction::Low).unwrap();
+ db6.set_direction(Direction::Low).unwrap();
+ db7.set_direction(Direction::Low).unwrap();
+
+ let mut lcd = HD44780::new_8bit(
+ rs,
+ en,
+ db0,
+ db1,
+ db2,
+ db3,
+ db4,
+ db5,
+ db6,
+ db7,
+ Delay,
+ );
+
+ lcd.reset();
+
+ lcd.clear();
+
+ lcd.set_display_mode(
+ DisplayMode {
+ display: Display::On,
+ cursor_visibility: Cursor::Visible,
+ cursor_blink: CursorBlink::On,
+ }
+ );
+
+ lcd.write_str("Hello, world!");
+
+}
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/.cargo/config b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/.cargo/config
new file mode 100644
index 0000000..8cb4006
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/.cargo/config
@@ -0,0 +1,9 @@
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
+runner = "gdb-multiarch -q -x openocd.gdb"
+
+rustflags = [
+ "-C", "link-arg=-Tlink.x",
+]
+
+[build]
+target = "thumbv7em-none-eabihf"
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/.gitignore b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/.gitignore
new file mode 100644
index 0000000..59a4524
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/.gitignore
@@ -0,0 +1,5 @@
+**/*.rs.bk
+.#*
+.gdb_history
+Cargo.lock
+target/
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/Cargo.toml b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/Cargo.toml
new file mode 100644
index 0000000..3a53b47
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+authors = ["Robin Krahl <robin.krahl@ireas.org>", "Nils Van Zuijlen <nils.van-zuijlen@mailo.com>"]
+edition = "2018"
+name = "stm32f30x-hd44780-i2c-example"
+version = "0.1.0"
+license = "MIT"
+publish = false
+
+[dependencies]
+cortex-m = "0.5.8"
+cortex-m-rt = "0.6.5"
+embedded-hal = "0.2.2"
+panic-halt = "0.2.0"
+hd44780-driver = { path = "../.." }
+
+[dependencies.hal]
+version = "0.2.0"
+package = "stm32f30x-hal"
+
+[profile.release]
+codegen-units = 1
+debug = true
+lto = true
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/README b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/README
new file mode 100644
index 0000000..9fc6a18
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/README
@@ -0,0 +1,3 @@
+This example is based on the cortex-m-quickstart project avaiable at
+https://github.com/rust-embedded/cortex-m-quickstart under the MIT License or
+the Apache License, Version 2.0.
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/build.rs b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/build.rs
new file mode 100644
index 0000000..461e48f
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/build.rs
@@ -0,0 +1,15 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ File::create(out.join("memory.x"))
+ .unwrap()
+ .write_all(include_bytes!("memory.x"))
+ .unwrap();
+ println!("cargo:rustc-link-search={}", out.display());
+
+ println!("cargo:rerun-if-changed=memory.x");
+}
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/memory.x b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/memory.x
new file mode 100644
index 0000000..2b098b1
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/memory.x
@@ -0,0 +1,5 @@
+MEMORY
+{
+ FLASH : ORIGIN = 0x08000000, LENGTH = 512K
+ RAM : ORIGIN = 0x20000000, LENGTH = 64K
+}
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.cfg b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.cfg
new file mode 100644
index 0000000..81551c8
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.cfg
@@ -0,0 +1,12 @@
+# Sample OpenOCD configuration for the STM32F3DISCOVERY development board
+
+# Depending on the hardware revision you got you'll have to pick ONE of these
+# interfaces. At any time only one interface should be commented out.
+
+# Revision C (newer revision)
+source [find interface/stlink-v2-1.cfg]
+
+# Revision A and B (older revisions)
+# source [find interface/stlink-v2.cfg]
+
+source [find target/stm32f3x.cfg]
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.gdb b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.gdb
new file mode 100644
index 0000000..a7fd5d1
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/openocd.gdb
@@ -0,0 +1,32 @@
+target extended-remote :3333
+
+# print demangled symbols
+set print asm-demangle on
+
+# detect unhandled exceptions, hard faults and panics
+break DefaultHandler
+break UserHardFault
+break rust_begin_unwind
+
+# *try* to stop at the user entry point (it might be gone due to inlining)
+break main
+
+monitor arm semihosting enable
+
+# # send captured ITM to the file itm.fifo
+# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
+# # 8000000 must match the core clock frequency
+# monitor tpiu config internal itm.txt uart off 8000000
+
+# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
+# # 8000000 must match the core clock frequency
+# # 2000000 is the frequency of the SWO pin
+# monitor tpiu config external uart off 8000000 2000000
+
+# # enable ITM port 0
+# monitor itm port 0 on
+
+load
+
+# start the process but immediately halt the processor
+stepi
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x-i2c/src/main.rs b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/src/main.rs
new file mode 100644
index 0000000..3ecfafd
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x-i2c/src/main.rs
@@ -0,0 +1,52 @@
+#![no_std]
+#![no_main]
+
+extern crate panic_halt;
+
+use core::fmt::Write;
+use cortex_m_rt::entry;
+use hal::prelude::*;
+use hal::flash::FlashExt;
+use hal::i2c::I2c;
+use hd44780_driver::{Cursor, CursorBlink, Display, DisplayMode, HD44780};
+
+// Connections:
+// VSS: GND
+// VDD: 5V
+// SCL: PB6
+// SDA: PB9
+// I2C address : 0x3F
+
+const I2C_ADDRESS: u8 = 0x3F;
+
+#[entry]
+fn main() -> ! {
+ let cp = cortex_m::Peripherals::take().unwrap();
+ let dp = hal::stm32f30x::Peripherals::take().unwrap();
+
+ let mut flash = dp.FLASH.constrain();
+ let mut rcc = dp.RCC.constrain();
+ let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
+
+ let clocks = rcc.cfgr.freeze(&mut flash.acr);
+ let delay = hal::delay::Delay::new(cp.SYST, clocks);
+
+ let scl = gpiob.pb6.into_af4(&mut gpiob.moder, &mut gpiob.afrl);
+ let sda = gpiob.pb9.into_af4(&mut gpiob.moder, &mut gpiob.afrh);
+
+ let i2c = I2c::i2c1(dp.I2C1, (scl, sda), 400.khz(), clocks, &mut rcc.apb1);
+
+ let mut lcd = HD44780::new_i2c(i2c, I2C_ADDRESS, delay);
+ lcd.reset();
+ lcd.clear();
+ lcd.set_display_mode(
+ DisplayMode {
+ display: Display::On,
+ cursor_visibility: Cursor::Visible,
+ cursor_blink: CursorBlink::On,
+ }
+ );
+ let _ = lcd.write_str("Hello, world!");
+
+ loop {}
+}
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/.cargo/config b/sw/deps/hd44780-driver/examples/stm32f30x/.cargo/config
new file mode 100644
index 0000000..ac7edbb
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/.cargo/config
@@ -0,0 +1,9 @@
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
+runner = "arm-none-eabi-gdb -q -x openocd.gdb"
+
+rustflags = [
+ "-C", "link-arg=-Tlink.x",
+]
+
+[build]
+target = "thumbv7em-none-eabihf"
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/.gitignore b/sw/deps/hd44780-driver/examples/stm32f30x/.gitignore
new file mode 100644
index 0000000..59a4524
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/.gitignore
@@ -0,0 +1,5 @@
+**/*.rs.bk
+.#*
+.gdb_history
+Cargo.lock
+target/
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/Cargo.toml b/sw/deps/hd44780-driver/examples/stm32f30x/Cargo.toml
new file mode 100644
index 0000000..5e51866
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+authors = ["Robin Krahl <robin.krahl@ireas.org>"]
+edition = "2018"
+name = "stm32f30x-hd44780-example"
+version = "0.1.0"
+license = "MIT"
+publish = false
+
+[dependencies]
+cortex-m = "0.5.8"
+cortex-m-rt = "0.6.5"
+embedded-hal = "0.2.2"
+panic-halt = "0.2.0"
+hd44780-driver = { path = "../.." }
+
+[dependencies.hal]
+version = "0.2.0"
+package = "stm32f30x-hal"
+
+[profile.release]
+codegen-units = 1
+debug = true
+lto = true
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/README b/sw/deps/hd44780-driver/examples/stm32f30x/README
new file mode 100644
index 0000000..9fc6a18
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/README
@@ -0,0 +1,3 @@
+This example is based on the cortex-m-quickstart project avaiable at
+https://github.com/rust-embedded/cortex-m-quickstart under the MIT License or
+the Apache License, Version 2.0.
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/build.rs b/sw/deps/hd44780-driver/examples/stm32f30x/build.rs
new file mode 100644
index 0000000..461e48f
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/build.rs
@@ -0,0 +1,15 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+ let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+ File::create(out.join("memory.x"))
+ .unwrap()
+ .write_all(include_bytes!("memory.x"))
+ .unwrap();
+ println!("cargo:rustc-link-search={}", out.display());
+
+ println!("cargo:rerun-if-changed=memory.x");
+}
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/memory.x b/sw/deps/hd44780-driver/examples/stm32f30x/memory.x
new file mode 100644
index 0000000..c49e4c3
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/memory.x
@@ -0,0 +1,5 @@
+MEMORY
+{
+ FLASH : ORIGIN = 0x08000000, LENGTH = 256K
+ RAM : ORIGIN = 0x20000000, LENGTH = 40K
+}
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/openocd.cfg b/sw/deps/hd44780-driver/examples/stm32f30x/openocd.cfg
new file mode 100644
index 0000000..81551c8
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/openocd.cfg
@@ -0,0 +1,12 @@
+# Sample OpenOCD configuration for the STM32F3DISCOVERY development board
+
+# Depending on the hardware revision you got you'll have to pick ONE of these
+# interfaces. At any time only one interface should be commented out.
+
+# Revision C (newer revision)
+source [find interface/stlink-v2-1.cfg]
+
+# Revision A and B (older revisions)
+# source [find interface/stlink-v2.cfg]
+
+source [find target/stm32f3x.cfg]
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/openocd.gdb b/sw/deps/hd44780-driver/examples/stm32f30x/openocd.gdb
new file mode 100644
index 0000000..a7fd5d1
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/openocd.gdb
@@ -0,0 +1,32 @@
+target extended-remote :3333
+
+# print demangled symbols
+set print asm-demangle on
+
+# detect unhandled exceptions, hard faults and panics
+break DefaultHandler
+break UserHardFault
+break rust_begin_unwind
+
+# *try* to stop at the user entry point (it might be gone due to inlining)
+break main
+
+monitor arm semihosting enable
+
+# # send captured ITM to the file itm.fifo
+# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
+# # 8000000 must match the core clock frequency
+# monitor tpiu config internal itm.txt uart off 8000000
+
+# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
+# # 8000000 must match the core clock frequency
+# # 2000000 is the frequency of the SWO pin
+# monitor tpiu config external uart off 8000000 2000000
+
+# # enable ITM port 0
+# monitor itm port 0 on
+
+load
+
+# start the process but immediately halt the processor
+stepi
diff --git a/sw/deps/hd44780-driver/examples/stm32f30x/src/main.rs b/sw/deps/hd44780-driver/examples/stm32f30x/src/main.rs
new file mode 100644
index 0000000..6b3b602
--- /dev/null
+++ b/sw/deps/hd44780-driver/examples/stm32f30x/src/main.rs
@@ -0,0 +1,55 @@
+#![no_std]
+#![no_main]
+
+extern crate panic_halt;
+
+use cortex_m_rt::entry;
+use hal::gpio::GpioExt;
+use hal::flash::FlashExt;
+use hal::rcc::RccExt;
+use hd44780_driver::{Cursor, CursorBlink, Display, DisplayMode, HD44780};
+
+// Connections:
+// VSS: GND
+// VDD: 5V
+// V0: 10k poti between 5V and GND
+// RS: PD1
+// RW: GND
+// E: PD2
+// D4-D7: PD4-PD7
+// A: 5V
+// K: GND
+
+#[entry]
+fn main() -> ! {
+ let cp = cortex_m::Peripherals::take().unwrap();
+ let dp = hal::stm32f30x::Peripherals::take().unwrap();
+
+ let mut flash = dp.FLASH.constrain();
+ let mut rcc = dp.RCC.constrain();
+ let mut gpiod = dp.GPIOD.split(&mut rcc.ahb);
+
+ let clocks = rcc.cfgr.freeze(&mut flash.acr);
+ let delay = hal::delay::Delay::new(cp.SYST, clocks);
+
+ let rs = gpiod.pd1.into_push_pull_output(&mut gpiod.moder, &mut gpiod.otyper);
+ let en = gpiod.pd2.into_push_pull_output(&mut gpiod.moder, &mut gpiod.otyper);
+ let b4 = gpiod.pd4.into_push_pull_output(&mut gpiod.moder, &mut gpiod.otyper);
+ let b5 = gpiod.pd5.into_push_pull_output(&mut gpiod.moder, &mut gpiod.otyper);
+ let b6 = gpiod.pd6.into_push_pull_output(&mut gpiod.moder, &mut gpiod.otyper);
+ let b7 = gpiod.pd7.into_push_pull_output(&mut gpiod.moder, &mut gpiod.otyper);
+
+ let mut lcd = HD44780::new_4bit(rs, en, b4, b5, b6, b7, delay);
+ lcd.reset();
+ lcd.clear();
+ lcd.set_display_mode(
+ DisplayMode {
+ display: Display::On,
+ cursor_visibility: Cursor::Visible,
+ cursor_blink: CursorBlink::On,
+ }
+ );
+ lcd.write_str("Hello, world!");
+
+ loop {}
+}
diff --git a/sw/deps/hd44780-driver/header.gif b/sw/deps/hd44780-driver/header.gif
new file mode 100644
index 0000000..78b710c
--- /dev/null
+++ b/sw/deps/hd44780-driver/header.gif
Binary files differ
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(...)
+}
diff --git a/sw/deps/hd44780-driver/src/display_mode.rs b/sw/deps/hd44780-driver/src/display_mode.rs
new file mode 100644
index 0000000..8039f7b
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/display_mode.rs
@@ -0,0 +1,95 @@
+use crate::{Cursor, CursorBlink, Display};
+
+pub struct DisplayMode {
+ pub cursor_visibility: Cursor,
+ pub cursor_blink: CursorBlink,
+ pub display: Display,
+}
+
+impl Default for DisplayMode {
+ fn default() -> DisplayMode {
+ DisplayMode {
+ cursor_visibility: Cursor::Visible,
+ cursor_blink: CursorBlink::On,
+ display: Display::On,
+ }
+ }
+}
+
+impl DisplayMode {
+ pub fn as_byte(&self) -> u8 {
+ let cursor_blink_bits = match self.cursor_blink {
+ CursorBlink::On => 0b0000_0001,
+ CursorBlink::Off => 0,
+ };
+
+ let cursor_visible_bits = match self.cursor_visibility {
+ Cursor::Visible => 0b0000_0010,
+ Cursor::Invisible => 0,
+ };
+
+ let display_bits = match self.display {
+ Display::On => 0b0000_0100,
+ Display::Off => 0,
+ };
+
+ 0b0000_1000 | cursor_visible_bits | cursor_blink_bits | display_bits
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+
+ #[test]
+ fn cursor_visible() {
+ let dm = DisplayMode {
+ cursor_visibility: Cursor::Visible,
+ ..Default::default()
+ };
+
+ assert!(dm.as_byte() & 0b0000_0010 != 0);
+
+ let dm = DisplayMode {
+ cursor_visibility: Cursor::Invisible,
+ ..Default::default()
+ };
+
+ assert!(dm.as_byte() & 0b0000_0010 == 0);
+ }
+
+ #[test]
+ fn cursor_blink() {
+ let dm = DisplayMode {
+ cursor_blink: CursorBlink::On,
+ ..Default::default()
+ };
+
+ assert!(dm.as_byte() & 0b0000_0001 != 0);
+
+ let dm = DisplayMode {
+ cursor_blink: CursorBlink::Off,
+ ..Default::default()
+ };
+
+ assert!(dm.as_byte() & 0b0000_0001 == 0);
+ }
+
+ #[test]
+ fn display_visible() {
+ let dm = DisplayMode {
+ display: Display::On,
+ ..Default::default()
+ };
+
+ assert!(dm.as_byte() & 0b0000_0100 != 0);
+
+ let dm = DisplayMode {
+ display: Display::Off,
+ ..Default::default()
+ };
+
+ assert!(dm.as_byte() & 0b0000_0100 == 0);
+ }
+}
diff --git a/sw/deps/hd44780-driver/src/entry_mode.rs b/sw/deps/hd44780-driver/src/entry_mode.rs
new file mode 100644
index 0000000..577c5d0
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/entry_mode.rs
@@ -0,0 +1,97 @@
+/// Determines if the cursor should be incremented or decremented on write
+#[derive(Debug, PartialEq, Eq)]
+pub enum CursorMode {
+ Increment,
+ Decrement,
+}
+
+impl Default for CursorMode {
+ fn default() -> CursorMode {
+ CursorMode::Increment
+ }
+}
+
+/// Determines if the screen should be shifted on write
+#[derive(Debug, PartialEq, Eq)]
+pub enum ShiftMode {
+ Enabled,
+ Disabled,
+}
+
+impl From<bool> for ShiftMode {
+ fn from(b: bool) -> ShiftMode {
+ if b {
+ ShiftMode::Enabled
+ } else {
+ ShiftMode::Disabled
+ }
+ }
+}
+
+impl Default for ShiftMode {
+ fn default() -> ShiftMode {
+ ShiftMode::Disabled
+ }
+}
+
+#[derive(Default)]
+pub struct EntryMode {
+ pub cursor_mode: CursorMode,
+ pub shift_mode: ShiftMode,
+}
+
+impl EntryMode {
+ pub fn as_byte(&self) -> u8 {
+ let cursor_bits = match self.cursor_mode {
+ CursorMode::Increment => 0b0000_0010,
+ CursorMode::Decrement => 0,
+ };
+
+ let shift_bits = match self.shift_mode {
+ ShiftMode::Enabled => 0b0000_0001,
+ ShiftMode::Disabled => 0,
+ };
+
+ 0b0000_0100 | cursor_bits | shift_bits
+ }
+}
+
+#[cfg(test)]
+mod tests {
+
+ use super::*;
+
+ #[test]
+ fn cursor_mode() {
+ let em = EntryMode {
+ cursor_mode: CursorMode::Increment,
+ shift_mode: Default::default(),
+ };
+
+ assert!(em.as_byte() & 0b0000_0010 != 0);
+
+ let em = EntryMode {
+ cursor_mode: CursorMode::Decrement,
+ shift_mode: Default::default(),
+ };
+
+ assert!(em.as_byte() & 0b0000_0010 == 0);
+ }
+
+ #[test]
+ fn shift_mode() {
+ let em = EntryMode {
+ cursor_mode: Default::default(),
+ shift_mode: ShiftMode::Enabled,
+ };
+
+ assert!(em.as_byte() & 0b0000_0001 != 0);
+
+ let em = EntryMode {
+ cursor_mode: Default::default(),
+ shift_mode: ShiftMode::Disabled,
+ };
+
+ assert!(em.as_byte() & 0b0000_0001 == 0);
+ }
+}
diff --git a/sw/deps/hd44780-driver/src/error.rs b/sw/deps/hd44780-driver/src/error.rs
new file mode 100644
index 0000000..2deaf85
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/error.rs
@@ -0,0 +1,3 @@
+#[derive(Debug)]
+pub struct Error;
+pub type Result<T> = core::result::Result<T, Error>;
diff --git a/sw/deps/hd44780-driver/src/lib.rs b/sw/deps/hd44780-driver/src/lib.rs
new file mode 100644
index 0000000..5211346
--- /dev/null
+++ b/sw/deps/hd44780-driver/src/lib.rs
@@ -0,0 +1,552 @@
+#![no_std]
+
+//use core::fmt::Result;
+//use core::fmt::Write;
+
+use embedded_hal::blocking::delay::{DelayMs, DelayUs};
+use embedded_hal::blocking::i2c;
+use embedded_hal::digital::v2::OutputPin;
+
+pub mod bus;
+use bus::{DataBus, EightBitBus, FourBitBus, I2CBus, I2CMCP23008Bus};
+
+pub mod error;
+use error::Result;
+
+pub mod entry_mode;
+
+use entry_mode::{CursorMode, EntryMode};
+
+pub mod display_mode;
+
+pub use display_mode::DisplayMode;
+
+pub struct HD44780<B: DataBus> {
+ bus: B,
+ entry_mode: EntryMode,
+ display_mode: DisplayMode,
+}
+
+/// Used in the direction argument for shifting the cursor and the display
+pub enum Direction {
+ Left,
+ Right,
+}
+
+/// Used in set_display_mode to make the parameters more clear
+pub enum Display {
+ On,
+ Off,
+}
+
+pub enum Cursor {
+ Visible,
+ Invisible,
+}
+
+pub enum CursorBlink {
+ On,
+ Off,
+}
+
+impl<
+ RS: OutputPin,
+ EN: OutputPin,
+ D0: OutputPin,
+ D1: OutputPin,
+ D2: OutputPin,
+ D3: OutputPin,
+ D4: OutputPin,
+ D5: OutputPin,
+ D6: OutputPin,
+ D7: OutputPin,
+ > HD44780<EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>>
+{
+ /// Create an instance of a `HD44780` from 8 data pins, a register select
+ /// pin, an enable pin and a struct implementing the delay trait.
+ /// - The delay instance is used to sleep between commands to
+ /// ensure the `HD44780` has enough time to process commands.
+ /// - The eight db0..db7 pins are used to send and recieve with
+ /// the `HD44780`.
+ /// - The register select pin is used to tell the `HD44780`
+ /// if incoming data is a command or data.
+ /// - The enable pin is used to tell the `HD44780` that there
+ /// is data on the 8 data pins and that it should read them in.
+ ///
+ pub fn new_8bit<D: DelayUs<u16> + DelayMs<u8>>(
+ rs: RS,
+ en: EN,
+ d0: D0,
+ d1: D1,
+ d2: D2,
+ d3: D3,
+ d4: D4,
+ d5: D5,
+ d6: D6,
+ d7: D7,
+ delay: &mut D,
+ ) -> Result<HD44780<EightBitBus<RS, EN, D0, D1, D2, D3, D4, D5, D6, D7>>> {
+ let mut hd = HD44780 {
+ bus: EightBitBus::from_pins(rs, en, d0, d1, d2, d3, d4, d5, d6, d7),
+ entry_mode: EntryMode::default(),
+ display_mode: DisplayMode::default(),
+ };
+
+ hd.init_8bit(delay)?;
+
+ return Ok(hd);
+ }
+}
+
+impl<RS: OutputPin, EN: OutputPin, D4: OutputPin, D5: OutputPin, D6: OutputPin, D7: OutputPin>
+ HD44780<FourBitBus<RS, EN, D4, D5, D6, D7>>
+{
+ /// Create an instance of a `HD44780` from 4 data pins, a register select
+ /// pin, an enable pin and a struct implementing the delay trait.
+ /// - The delay instance is used to sleep between commands to
+ /// ensure the `HD44780` has enough time to process commands.
+ /// - The four db0..db3 pins are used to send and recieve with
+ /// the `HD44780`.
+ /// - The register select pin is used to tell the `HD44780`
+ /// if incoming data is a command or data.
+ /// - The enable pin is used to tell the `HD44780` that there
+ /// is data on the 4 data pins and that it should read them in.
+ ///
+ /// This mode operates differently than 8 bit mode by using 4 less
+ /// pins for data, which is nice on devices with less I/O although
+ /// the I/O takes a 'bit' longer
+ ///
+ /// Instead of commands being sent byte by byte each command is
+ /// broken up into it's upper and lower nibbles (4 bits) before
+ /// being sent over the data bus
+ ///
+ pub fn new_4bit<D: DelayUs<u16> + DelayMs<u8>>(
+ rs: RS,
+ en: EN,
+ d4: D4,
+ d5: D5,
+ d6: D6,
+ d7: D7,
+ delay: &mut D,
+ ) -> Result<HD44780<FourBitBus<RS, EN, D4, D5, D6, D7>>> {
+ let mut hd = HD44780 {
+ bus: FourBitBus::from_pins(rs, en, d4, d5, d6, d7),
+ entry_mode: EntryMode::default(),
+ display_mode: DisplayMode::default(),
+ };
+
+ hd.init_4bit(delay)?;
+
+ return Ok(hd);
+ }
+}
+
+impl<I2C: i2c::Write> HD44780<I2CBus<I2C>> {
+ /// Create an instance of a `HD44780` from an i2c write peripheral,
+ /// I2C address and a struct implementing the delay trait.
+ /// The `HD44780` is driven through a PCF8574 I2C port expander.
+ /// - The delay instance is used to sleep between commands to
+ /// ensure the `HD44780` has enough time to process commands.
+ /// - The i2c peripheral is used to send data to the `HD44780` and to set
+ /// its register select and enable pins.
+ ///
+ /// This mode operates on an I2C bus, using a PCF8574 I2C to port expander
+ /// The IC connections are described in `I2CBus`
+ ///
+ pub fn new_i2c<D: DelayUs<u16> + DelayMs<u8>>(
+ i2c_bus: I2C,
+ address: u8,
+ delay: &mut D,
+ ) -> Result<HD44780<I2CBus<I2C>>> {
+ let mut hd = HD44780 {
+ bus: I2CBus::new(i2c_bus, address),
+ entry_mode: EntryMode::default(),
+ display_mode: DisplayMode::default(),
+ };
+
+ hd.init_4bit(delay)?;
+
+ return Ok(hd);
+ }
+}
+
+impl<I2C: i2c::Write> HD44780<I2CMCP23008Bus<I2C>> {
+ /// Create an instance of a `HD44780` from an i2c write peripheral,
+ /// I2C address and a struct implementing the delay trait.
+ /// The `HD44780` is driven through a MCP23008 I2C port expander.
+ /// - The delay instance is used to sleep between commands to
+ /// ensure the `HD44780` has enough time to process commands.
+ /// - The i2c peripheral is used to send data to the `HD44780` and to set
+ /// its register select and enable pins.
+ ///
+ /// This mode operates on an I2C bus, using an I2C to parallel port expander based on MCP23008.
+ /// The IC connections are described in `I2CMCP23008Bus`
+ ///
+ pub fn new_i2c_mcp23008<D: DelayUs<u16> + DelayMs<u8>>(
+ i2c_bus: I2C,
+ address: u8,
+ delay: &mut D,
+ ) -> Result<HD44780<I2CMCP23008Bus<I2C>>> {
+ let mut hd = HD44780 {
+ bus: I2CMCP23008Bus::new(i2c_bus, address)?,
+ entry_mode: EntryMode::default(),
+ display_mode: DisplayMode::default(),
+ };
+
+ hd.init_4bit(delay)?;
+
+ return Ok(hd);
+ }
+}
+
+impl<B> HD44780<B>
+where
+ B: DataBus,
+{
+ /// Unshifts the display and sets the cursor position to 0
+ ///
+ /// ```rust,ignore
+ /// lcd.reset();
+ /// ```
+ pub fn reset<D: DelayUs<u16> + DelayMs<u8>>(&mut self, delay: &mut D) -> Result<()> {
+ self.write_command(0b0000_0010, delay)?;
+
+ Ok(())
+ }
+
+ /// Set if the display should be on, if the cursor should be
+ /// visible, and if the cursor should blink
+ ///
+ /// Note: This is equivilent to calling all of the other relavent
+ /// methods however this operation does it all in one go to the `HD44780`
+ pub fn set_display_mode<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ display_mode: DisplayMode,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.display_mode = display_mode;
+
+ let cmd_byte = self.display_mode.as_byte();
+
+ self.write_command(cmd_byte, delay)?;
+
+ Ok(())
+ }
+
+ /// Clear the entire display
+ ///
+ /// ```rust,ignore
+ /// lcd.clear();
+ /// ```
+ pub fn clear<D: DelayUs<u16> + DelayMs<u8>>(&mut self, delay: &mut D) -> Result<()> {
+ self.write_command(0b0000_0001, delay)?;
+
+ Ok(())
+ }
+
+ /// If enabled, automatically scroll the display when a new
+ /// character is written to the display
+ ///
+ /// ```rust,ignore
+ /// lcd.set_autoscroll(true);
+ /// ```
+ pub fn set_autoscroll<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ enabled: bool,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.entry_mode.shift_mode = enabled.into();
+
+ let cmd = self.entry_mode.as_byte();
+
+ self.write_command(cmd, delay)?;
+
+ Ok(())
+ }
+
+ /// Set if the cursor should be visible
+ pub fn set_cursor_visibility<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ visibility: Cursor,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.display_mode.cursor_visibility = visibility;
+
+ let cmd = self.display_mode.as_byte();
+
+ self.write_command(cmd, delay)?;
+
+ Ok(())
+ }
+
+ /// Set if the characters on the display should be visible
+ pub fn set_display<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ display: Display,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.display_mode.display = display;
+
+ let cmd = self.display_mode.as_byte();
+
+ self.write_command(cmd, delay)?;
+
+ Ok(())
+ }
+
+ /// Set if the cursor should blink
+ pub fn set_cursor_blink<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ blink: CursorBlink,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.display_mode.cursor_blink = blink;
+
+ let cmd = self.display_mode.as_byte();
+
+ self.write_command(cmd, delay)?;
+
+ Ok(())
+ }
+
+ /// Set which way the cursor will move when a new character is written
+ ///
+ /// ```rust,ignore
+ /// // Move right (Default) when a new character is written
+ /// lcd.set_cursor_mode(CursorMode::Right)
+ ///
+ /// // Move left when a new character is written
+ /// lcd.set_cursor_mode(CursorMode::Left)
+ /// ```
+ pub fn set_cursor_mode<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ mode: CursorMode,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.entry_mode.cursor_mode = mode;
+
+ let cmd = self.entry_mode.as_byte();
+
+ self.write_command(cmd, delay)?;
+
+ Ok(())
+ }
+
+ /// Set the cursor position
+ ///
+ /// ```rust,ignore
+ /// // Move to line 2
+ /// lcd.set_cursor_pos(40)
+ /// ```
+ pub fn set_cursor_pos<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ position: u8,
+ delay: &mut D,
+ ) -> Result<()> {
+ let lower_7_bits = 0b0111_1111 & position;
+
+ self.write_command(0b1000_0000 | lower_7_bits, delay)?;
+
+ Ok(())
+ }
+
+ /// Shift just the cursor to the left or the right
+ ///
+ /// ```rust,ignore
+ /// lcd.shift_cursor(Direction::Left);
+ /// lcd.shift_cursor(Direction::Right);
+ /// ```
+ pub fn shift_cursor<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ dir: Direction,
+ delay: &mut D,
+ ) -> Result<()> {
+ let bits = match dir {
+ Direction::Left => 0b0000_0000,
+ Direction::Right => 0b0000_0100,
+ };
+
+ self.write_command(0b0001_0000 | bits | bits, delay)?;
+
+ Ok(())
+ }
+
+ /// Shift the entire display to the left or the right
+ ///
+ /// ```rust,ignore
+ /// lcd.shift_display(Direction::Left);
+ /// lcd.shift_display(Direction::Right);
+ /// ```
+ pub fn shift_display<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ dir: Direction,
+ delay: &mut D,
+ ) -> Result<()> {
+ let bits = match dir {
+ Direction::Left => 0b0000_0000,
+ Direction::Right => 0b0000_0100,
+ };
+
+ self.write_command(0b0001_1000 | bits, delay)?;
+
+ Ok(())
+ }
+
+ /// Write a single character to the `HD44780`
+ ///
+ /// ```rust,ignore
+ /// lcd.write_char('A');
+ /// ```
+ pub fn write_char<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ data: char,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.bus.write(data as u8, true, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ Ok(())
+ }
+
+ fn write_command<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ cmd: u8,
+ delay: &mut D,
+ ) -> Result<()> {
+ self.bus.write(cmd, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+ Ok(())
+ }
+
+ fn init_4bit<D: DelayUs<u16> + DelayMs<u8>>(&mut self, delay: &mut D) -> Result<()> {
+ // Wait for the LCD to wakeup if it was off
+ delay.delay_ms(15u8);
+
+ // Initialize Lcd in 4-bit mode
+ self.bus.write(0x33, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_ms(5u8);
+
+ // Sets 4-bit operation and enables 5x7 mode for chars
+ self.bus.write(0x32, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ self.bus.write(0x28, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ // Clear Display
+ self.bus.write(0x0E, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ // Move the cursor to beginning of first line
+ self.bus.write(0x01, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ // Set entry mode
+ self.bus.write(self.entry_mode.as_byte(), false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ self.bus.write(0x80, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ Ok(())
+ }
+
+ // Follow the 8-bit setup procedure as specified in the HD44780 datasheet
+ fn init_8bit<D: DelayUs<u16> + DelayMs<u8>>(&mut self, delay: &mut D) -> Result<()> {
+ // Wait for the LCD to wakeup if it was off
+ delay.delay_ms(15u8);
+
+ // Initialize Lcd in 8-bit mode
+ self.bus.write(0b0011_0000, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_ms(5u8);
+
+ // Sets 8-bit operation and enables 5x7 mode for chars
+ self.bus.write(0b0011_1000, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ self.bus.write(0b0000_1110, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ // Clear Display
+ self.bus.write(0b0000_0001, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ // Move the cursor to beginning of first line
+ self.bus.write(0b000_0111, false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ // Set entry mode
+ self.bus.write(self.entry_mode.as_byte(), false, delay)?;
+
+ // Wait for the command to be processed
+ delay.delay_us(100);
+
+ Ok(())
+ }
+
+ pub fn write_str<D: DelayUs<u16> + DelayMs<u8>>(
+ &mut self,
+ string: &str,
+ delay: &mut D,
+ ) -> Result<()> {
+ for c in string.chars() {
+ self.write_char(c, delay)?;
+ }
+ Ok(())
+ }
+
+ // Send a byte to the HD44780 by setting the data on the bus and
+ // also pulsing the enable pin
+ /*fn send_byte(&mut self, data: u8) {
+ // Pulse the enable pin
+ self.set_bus_bits(data);
+ self.pulse_enable();
+ }*/
+
+ // Pulse the enable pin telling the HD44780 that we something for it
+ /*fn pulse_enable(&mut self) {
+ self.en.set_high();
+ self.delay.delay_ms(15u8);
+ self.en.set_low();
+ }*/
+}
+
+//impl<B> Write for HD44780<B>
+//where
+// B: DataBus,
+//{
+// fn write_str(&mut self, string: &str) -> Result {
+// for c in string.chars() {
+// self.write_char(c, delay);
+// }
+// Ok(())
+// }
+//}