From e6974cffb2476cc97f691ae850831833f5c140a3 Mon Sep 17 00:00:00 2001 From: kirbylife Date: Tue, 4 Apr 2023 14:29:28 -0600 Subject: [PATCH] Add the STN 16x2 screen display driver --- Cargo.toml | 1 + src/screen.rs | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/screen.rs diff --git a/Cargo.toml b/Cargo.toml index db604a6..96518d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ sha1_smol = "1.0.0" binascii = { version = "0.1", default-features = false, features = ["decode"] } ds323x = "0.5.0" ufmt = "0.2.0" +embedded-hal = "0.2.7" [profile.release] lto = true diff --git a/src/screen.rs b/src/screen.rs new file mode 100644 index 0000000..6062191 --- /dev/null +++ b/src/screen.rs @@ -0,0 +1,109 @@ +use arduino_hal::delay_ms; +use arduino_hal::delay_us; +use embedded_hal::digital::v2::OutputPin; + +const INIT_CMD: u8 = 0x03; // 0b00000011 +const MODE_4_BITS_CMD: u8 = 0x02; // 0b00000010 +const DISPLAY_MODE_CMD: u8 = 0x28; // 0b00101000 +const ENABLE_SCREEN_CMD: u8 = 0x0C; // 0b00001100 +const CLEAN_SCREEN_CMD: u8 = 0x01; // 0b00000001 + +pub struct StnScreen<'a, RS, EN, D4, D5, D6, D7> { + rs: &'a mut RS, + en: &'a mut EN, + d4: &'a mut D4, + d5: &'a mut D5, + d6: &'a mut D6, + d7: &'a mut D7, +} + +impl< + 'a, + RS: OutputPin, + EN: OutputPin, + D4: OutputPin, + D5: OutputPin, + D6: OutputPin, + D7: OutputPin, + > StnScreen<'a, RS, EN, D4, D5, D6, D7> +{ + pub fn new( + rs: &'a mut RS, + en: &'a mut EN, + d4: &'a mut D4, + d5: &'a mut D5, + d6: &'a mut D6, + d7: &'a mut D7, + ) -> Self { + let mut display = StnScreen { + rs, + en, + d4, + d5, + d6, + d7, + }; + + // Initializing of LCM on page 16 + // https://z3d9b7u8.stackpathcdn.com/pdf-down/L/C/D/LCD-1602A_CA.pdf + delay_ms(16); + display.write_nibble(INIT_CMD, false); + delay_ms(5); + display.write_nibble(INIT_CMD, false); + delay_us(100); + display.write_nibble(INIT_CMD, false); + delay_us(100); + display.write_nibble(MODE_4_BITS_CMD, false); + delay_us(100); + display.send_cmd(DISPLAY_MODE_CMD, false); + display.send_cmd(ENABLE_SCREEN_CMD, false); + + display + } + + fn pulse_enable(&mut self) { + self.en.set_low().ok(); + delay_us(1); + self.en.set_high().ok(); + delay_us(1); + self.en.set_low().ok(); + delay_us(100); + } + + fn send_cmd(&mut self, cmd: u8, is_data: bool) { + self.write_nibble((cmd >> 4) & 0x0F, is_data); + self.write_nibble(cmd & 0x0F, is_data); + delay_ms(10); + } + + fn write_nibble(&mut self, nibble: u8, is_data: bool) { + self.rs.set_state(is_data.into()).ok(); + self.d4.set_state(last_bit(nibble >> 0).into()).ok(); + self.d5.set_state(last_bit(nibble >> 1).into()).ok(); + self.d6.set_state(last_bit(nibble >> 2).into()).ok(); + self.d7.set_state(last_bit(nibble >> 3).into()).ok(); + self.pulse_enable(); + } + + fn clear(&mut self) { + display.send_cmd(CLEAN_SCREEN_CMD, false); + } + + pub fn write_char(&mut self, c: char) { + let c = c as u8; + self.write_nibble((c >> 4) & 0x0F, true); + self.write_nibble(c & 0x0F, true); + delay_us(100); + } + + pub fn write_str>(&mut self, s: S) { + let s = s.as_ref(); + for c in s.chars() { + self.write_char(c); + } + } +} + +fn last_bit(n: u8) -> bool { + (n & 1) != 0 +}