finga
343b95dc78
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Pass iterators for control and display data to the printing function instead of just printing it.
266 lines
9.1 KiB
Rust
266 lines
9.1 KiB
Rust
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<Output, PB0>,
|
|
rst: Pin<Output, PB1>,
|
|
}
|
|
|
|
impl Lcd {
|
|
pub fn new(spi: Spi, cd: Pin<Output, PB0>, rst: Pin<Output, PB1>) -> Self {
|
|
Self { spi, cd, rst }
|
|
}
|
|
|
|
pub fn control<'a>(&mut self, data: impl Iterator<Item = &'a u8>) {
|
|
data.for_each(|d| block!(self.spi.send(*d)).unwrap());
|
|
}
|
|
|
|
pub fn display<'a>(&mut self, invert: bool, data: impl Iterator<Item = &'a u8>) {
|
|
let mut delay = Delay::<DefaultClock>::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::<DefaultClock>::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::<DefaultClock>::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());
|
|
}
|
|
}
|