From de8f789e63e7092889732fb389e0a7c5c69706e5 Mon Sep 17 00:00:00 2001 From: finga Date: Sat, 12 Mar 2022 18:11:58 +0100 Subject: [PATCH] fw-rust: Create `Lcd` struct to handle the screen To improve screen handling create the `Lcd` struct and implement some first helper functions. --- firmware/rust/src/main.rs | 174 ++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 63 deletions(-) diff --git a/firmware/rust/src/main.rs b/firmware/rust/src/main.rs index d16b397..ef10494 100644 --- a/firmware/rust/src/main.rs +++ b/firmware/rust/src/main.rs @@ -5,7 +5,7 @@ use atmega_hal::{ clock::MHz8, delay::Delay, pins, - port::{mode::Output, Pin, PB0}, + port::{mode::Output, Pin, PB0, PB1}, spi::{DataOrder, SerialClockRate, Settings, Spi}, Peripherals, }; @@ -68,78 +68,134 @@ const ONDERS_ORG: [[u8; 48]; 2] = [ ], ]; -fn clear_screen(spi: &mut Spi, cd: &mut Pin) { - let mut delay = Delay::::new(); +pub struct Lcd { + spi: Spi, + cd: Pin, + rst: Pin, +} - for page in 0..8 { - block!(spi.send(0x00)).unwrap(); - block!(spi.send(0x10)).unwrap(); - block!(spi.send(0xB0 + page)).unwrap(); +impl Lcd { + fn init(&mut self, contrast: u8) { + let mut delay = Delay::::new(); + + // TODO: Test if delay is really needed + delay.delay_ms(1_u8); + self.rst.set_high(); + // TODO: Try to reduce delay to a minimum + delay.delay_ms(1_u8); + + block!(self.spi.send(0x40)).unwrap(); // (6) Set Scroll Line: Display start line 0 + block!(self.spi.send(0xA1)).unwrap(); // (13) Set SEG direction: SEG reverse + block!(self.spi.send(0xC0)).unwrap(); // (14) Set COM direction: Normal COM0 - COM63 + // block!(spi.send(0xA4)).unwrap(); // (10) Set All Pixel On: Disable -> Set All Pixel to ON */ + block!(self.spi.send(0xA6)).unwrap(); // (11) Set Inverse Display: Display inverse off + block!(self.spi.send(0xA2)).unwrap(); // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65) + block!(self.spi.send(0x2F)).unwrap(); // (5) Set Power Control: Booster, Regulator and Follower on + block!(self.spi.send(0x27)).unwrap(); // (8) Set VLCD Resistor Ratio: Set Contrast + // block!(spi.send(0xEE)).unwrap(); // (18) Reset Cursor Update Mode + block!(self.spi.send(0x81)).unwrap(); // (9) Set Electronic Volume: Set Contrast + block!(self.spi.send(contrast)).unwrap(); // (9) Set Electronic Volume: Set Contrast + // block!(spi.send(0xFA)).unwrap(); // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C + // block!(spi.send(0x90)).unwrap(); // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C + block!(self.spi.send(0xAF)).unwrap(); // (12) Set Display Enable: Display on // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); - cd.set_high(); + } - for _ in 0..102 { - block!(spi.send(0x00)).unwrap(); + fn move_cursor(&mut self, segment: u8, page: u8) { + assert!(segment < 102); + assert!(page < 8); + + block!(self.spi.send(0x0F & segment)).unwrap(); + block!(self.spi.send(0x10 + (segment >> 4))).unwrap(); + block!(self.spi.send(0xB0 + page)).unwrap(); + } + + fn clear(&mut self) { + let mut delay = Delay::::new(); + + for page in 0..8 { + self.move_cursor(0, page as u8); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_high(); + + for _ in 0..102 { + block!(self.spi.send(0x00)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); } + } - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - cd.set_low(); + fn screen(&mut self, screen: &Screens) { + self.clear(); + + match screen { + Screens::Splash(splash) => splash.draw(self), + } } } -fn draw_splash(spi: &mut Spi, cd: &mut Pin) { - clear_screen(spi, cd); +pub trait Draw { + fn draw(&self, lcd: &mut Lcd); +} - let mut delay = Delay::::new(); +struct SplashScreen; - for (i, page) in SACRED_CHAO.iter().enumerate() { - block!(spi.send(0x0F)).unwrap(); - block!(spi.send(0x11)).unwrap(); - block!(spi.send(0xB1 + i as u8)).unwrap(); +impl Draw for SplashScreen { + fn draw(&self, lcd: &mut Lcd) { + let mut delay = Delay::::new(); - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - cd.set_high(); + for (i, page) in SACRED_CHAO.iter().enumerate() { + lcd.move_cursor(31, 1 + i as u8); - for segment in page { - block!(spi.send(*segment)).unwrap(); + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_high(); + + for segment in page { + block!(lcd.spi.send(*segment)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_low(); } - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - cd.set_low(); - } + for (i, page) in ONDERS_ORG.iter().enumerate() { + lcd.move_cursor(27, 6 + i as u8); - for (i, page) in ONDERS_ORG.iter().enumerate() { - block!(spi.send(0x0A)).unwrap(); - block!(spi.send(0x11)).unwrap(); - block!(spi.send(0xB6 + i as u8)).unwrap(); + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_high(); - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - cd.set_high(); + for segment in page { + block!(lcd.spi.send(*segment)).unwrap(); + } - for segment in page { - block!(spi.send(*segment)).unwrap(); + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + lcd.cd.set_low(); } - - // TODO: This delay fixes issues, try find a better solution - delay.delay_ms(1_u8); - cd.set_low(); } } +enum Screens { + Splash(SplashScreen), +} + #[atmega_hal::entry] fn main() -> ! { interrupt::free(|_cs| { - // Get peripherals, pins, eeprom and delay + // Get peripherals, pins and eeprom let dp = Peripherals::take().unwrap(); let pins = pins!(dp); let eeprom = Eeprom::new(dp.EEPROM); - let mut delay = Delay::::new(); // Get contrast and backlight from EEPROM let contrast = eeprom.read_value(&CONTRAST); @@ -162,7 +218,7 @@ fn main() -> ! { pins.pd5.into_output(); // Init SPI - let (mut spi, _) = Spi::new( + let (spi, _) = Spi::new( dp.SPI, pins.pb5.into_output(), pins.pb3.into_output(), @@ -179,27 +235,19 @@ fn main() -> ! { ); // Init LCD - let mut lcd_cd = pins.pb0.into_output(); - let mut lcd_rst = pins.pb1.into_output(); - // TODO: Test if delay is really needed - delay.delay_ms(1_u8); - lcd_rst.set_high(); - // TODO: Try to reduce delay to a minimum - delay.delay_ms(5_u8); + let mut lcd = Lcd { + spi, + cd: pins.pb0.into_output(), + rst: pins.pb1.into_output(), + }; + lcd.init(contrast); - block!(spi.send(0x40)).unwrap(); // (6) Set Scroll Line: Display start line 0 - block!(spi.send(0xA1)).unwrap(); // (13) Set SEG direction: SEG reverse - block!(spi.send(0xC0)).unwrap(); // (14) Set COM direction: Normal COM0 - COM63 - block!(spi.send(0xA6)).unwrap(); // (11) Set Inverse Display: Display inverse off - block!(spi.send(0xA2)).unwrap(); // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65) - block!(spi.send(0x2F)).unwrap(); // (5) Set Power Control: Booster, Regulator and Follower on - block!(spi.send(0x27)).unwrap(); // (8) Set VLCD Resistor Ratio: Set Contrast - block!(spi.send(0x81)).unwrap(); // (9) Set Electronic Volume: Set Contrast - block!(spi.send(contrast)).unwrap(); // (9) Set Electronic Volume: Set Contrast - block!(spi.send(0xAF)).unwrap(); // (12) Set Display Enable: Display on + // Create screen + // TODO: This should use volatile and probably be somehow globally accessible + let screen = Screens::Splash(SplashScreen); // Draw splash screen - draw_splash(&mut spi, &mut lcd_cd); + lcd.screen(&screen); }); #[allow(clippy::empty_loop)]