use atmega_hal::{ delay::Delay, port::{mode::Output, Pin, PB0, PB1}, Spi, }; use core::{convert::TryInto, iter}; use embedded_hal::{blocking::delay::DelayUs, spi::FullDuplex}; use nb::block; use crate::{assets::SYMBOL_TABLE, eeprom, DefaultClock, CONTRAST}; // 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 control<'a>(&mut self, data: impl Iterator) { data.for_each(|d| block!(self.spi.send(*d)).unwrap()); } pub fn display<'a>(&mut self, invert: bool, data: impl Iterator) { let mut delay = Delay::::new(); delay.delay_us(5_u8); self.cd.set_high(); if invert { data.for_each(|d| block!(self.spi.send(!*d)).unwrap()); } else { data.for_each(|d| block!(self.spi.send(*d)).unwrap()); } delay.delay_us(5_u8); self.cd.set_low(); } fn init_sequence() -> [u8; 13] { [ 0x40, // (6) Set Scroll Line: Display start line 0 0xA1, // (13) Set SEG direction: SEG reverse 0xC0, // (14) Set COM direction: Normal COM0 - COM63 0xA6, // (11) Set Inverse Display: Display inverse off 0xA2, // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65) 0x2F, // (5) Set Power Control: Booster, Regulator and Follower on 0x27, // (8) Set VLCD Resistor Ratio: Set Contrast 0xEE, // (18) Reset Cursor Update Mode 0x81, // (9) Set Electronic Volume: Set Contrast block!(eeprom::read_byte(&CONTRAST)).unwrap(), // (9) Set Electronic Volume: Set Contrast 0xFA, // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C 0x90, // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C 0xAF, // (12) Set Display Enable: Display on ] } pub fn init(&mut self) { self.rst.set_high(); self.control(Lcd::init_sequence().iter()); } pub fn set_contrast(&mut self, contrast: u8) { assert!(contrast <= 63); self.control([0x81, contrast].iter()); } pub fn move_cursor(&mut self, segment: u8, page: u8) { assert!(segment < 102); assert!(page < 8); self.control([0x0F & segment, 0x10 + (segment >> 4), 0xB0 + page].iter()); } fn fill(&mut self, segment: u8, page: u8, width: u8, data: u8) { assert!(segment + width <= 102); self.move_cursor(segment, page); self.display(false, iter::repeat(&data).take(width.into())); } pub fn fill_area(&mut self, segment: u8, page: u8, width: u8, height: u8, data: u8) { assert!(segment + width <= 102); 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, invert: bool, string: &str) { for i in 0..2 { self.move_cursor(segment, page + i); self.display( invert, [0x00, 0x00] .iter() .chain(string.chars().flat_map(|c| { SYMBOL_TABLE[c as usize - 46][i as usize] .iter() .chain(&[0x00]) })) .chain(&[0x00]), ); } } pub fn print_u8(&mut self, segment: u8, page: u8, digits: u8, invert: bool, data: u8) { assert!(digits <= 3); let mut array = [0_usize; 3]; for (i, item) in array.iter_mut().enumerate() { *item = (((data / 10_u8.pow(i.try_into().unwrap())) % 10) + 2).into(); } array.reverse(); for i in 0..2 { self.move_cursor(segment, page + i); self.display( invert, [0x00, 0x00] .iter() .chain(array.iter().flat_map(|c| { SYMBOL_TABLE[array[*c as usize]][i as usize] .iter() .chain(&[0x00]) })) .chain(&[0x00]), ); } } pub fn print_freq(&mut self, segment: u8, page: u8, data: u32) { let mut delay = Delay::::new(); let mut array = [0usize; 9]; for (i, item) in array.iter_mut().enumerate() { *item = (((data / 10_u32.pow(i.try_into().unwrap())) % 10) + 2) .try_into() .unwrap(); } array.reverse(); for i in 0..2 { self.move_cursor(segment, page + i); delay.delay_us(5_u8); self.cd.set_high(); block!(self.spi.send(0x00)).unwrap(); block!(self.spi.send(0x00)).unwrap(); for j in 0..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(); } for segment in SYMBOL_TABLE[0][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); for j in 3..6 { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); } for segment in SYMBOL_TABLE[0][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); for j in 6..9 { 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(); delay.delay_us(5_u8); self.cd.set_low(); } } pub fn print_freq_digit(&mut self, segment: u8, page: u8, data: u32, digit: u8) { let mut delay = Delay::::new(); let mut array = [0usize; 9]; for (i, item) in array.iter_mut().enumerate() { *item = (((data / 10_u32.pow(i.try_into().unwrap())) % 10) + 2) .try_into() .unwrap(); } array.reverse(); let digit = 8 - digit; for i in 0..2 { self.move_cursor(segment, page + i); delay.delay_us(5_u8); self.cd.set_high(); block!(self.spi.send(0x00)).unwrap(); block!(self.spi.send(0x00)).unwrap(); for j in 0..3 { if j == digit { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(!*segment)).unwrap(); } } else { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(*segment)).unwrap(); } } block!(self.spi.send(0x00)).unwrap(); } for segment in SYMBOL_TABLE[0][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); for j in 3..6 { if j == digit { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(!*segment)).unwrap(); } } else { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(*segment)).unwrap(); } } block!(self.spi.send(0x00)).unwrap(); } for segment in SYMBOL_TABLE[0][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); for j in 6..9 { if j == digit { for segment in SYMBOL_TABLE[array[j as usize]][i as usize] { block!(self.spi.send(!*segment)).unwrap(); } } else { 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(); delay.delay_us(5_u8); self.cd.set_low(); } } pub fn print_icon(&mut self, segment: u8, page: u8, symbol: &[u8]) { self.move_cursor(segment, page); self.display(false, symbol.iter()); } }