use atmega_hal::{ clock::MHz8, delay::Delay, port::{mode::Output, Pin, PB0, PB1}, Spi, }; use avr_device::interrupt; use core::convert::TryInto; use embedded_hal::{blocking::delay::DelayMs, spi::FullDuplex}; use nb::block; use crate::{ assets::SYMBOL_TABLE, screen::{Screen, Screens}, }; // TODO: Make `cd` and `rst` pins generic pins pub struct Lcd { pub spi: Spi, pub cd: Pin, rst: Pin, } impl Lcd { pub fn new(spi: Spi, cd: Pin, rst: Pin) -> Self { Self { spi, cd, rst } } pub 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); } pub 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(); } } fn fill(&mut self, segment: u8, page: u8, width: u8, data: u8) { assert!(segment + width <= 102); let mut delay = Delay::::new(); self.move_cursor(segment, page); // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); self.cd.set_high(); for _ in 0..width { block!(self.spi.send(data)).unwrap(); } // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); self.cd.set_low(); } pub fn fill_area(&mut self, segment: u8, page: u8, width: u8, height: u8, data: u8) { assert!(page + height <= 8); for i in 0..height { self.fill(segment, page + i, width, data); } } pub fn print(&mut self, segment: u8, page: u8, string: &str) { let mut delay = Delay::::new(); for i in 0..2 { self.move_cursor(segment, page + i); // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); self.cd.set_high(); block!(self.spi.send(0x00)).unwrap(); block!(self.spi.send(0x00)).unwrap(); for c in string.chars() { for segment in SYMBOL_TABLE[c as usize - 48][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); } 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(); } } pub fn print_inverted(&mut self, segment: u8, page: u8, string: &str) { let mut delay = Delay::::new(); for i in 0..2 { self.move_cursor(segment, page + i); // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); self.cd.set_high(); block!(self.spi.send(0xFF)).unwrap(); block!(self.spi.send(0xFF)).unwrap(); for c in string.chars() { for segment in SYMBOL_TABLE[c as usize - 48][i as usize] { block!(self.spi.send(!*segment)).unwrap(); } block!(self.spi.send(0xFF)).unwrap(); } block!(self.spi.send(0xFF)).unwrap(); // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); self.cd.set_low(); } } pub fn print_u8(&mut self, segment: u8, page: u8, digits: u8, data: u8) { assert!(digits <= 3); let mut delay = Delay::::new(); let mut array = [0usize; 3]; for (i, item) in array.iter_mut().enumerate() { *item = ((data / 10_u8.pow(i.try_into().unwrap())) % 10).into(); } array.reverse(); for i in 0..2 { self.move_cursor(segment, page + i); // TODO: This delay fixes issues, try find a better solution delay.delay_ms(1_u8); self.cd.set_high(); block!(self.spi.send(0x00)).unwrap(); block!(self.spi.send(0x00)).unwrap(); for j in 3 - digits..3 { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); } 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(); } } pub fn draw(&mut self, screen: &Screens) { interrupt::free(|_cs| { self.clear(); match screen { Screens::Splash(splash) => { splash.draw(self); } Screens::Home(home) => { home.draw(self); } Screens::Setup(setup) => { setup.draw(self); } } }); } }