All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Set the temperature compensation curve to -0.11%/°C.
336 lines
11 KiB
Rust
336 lines
11 KiB
Rust
use atmega_hal::{
|
|
delay::Delay,
|
|
port::{mode::Output, Pin, PB0, PB1},
|
|
Spi,
|
|
};
|
|
use core::convert::TryInto;
|
|
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 init(&mut self) {
|
|
self.rst.set_high();
|
|
|
|
let init_sequence = [
|
|
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
|
|
nb::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
|
|
];
|
|
|
|
for i in init_sequence.iter() {
|
|
block!(self.spi.send(*i)).unwrap();
|
|
}
|
|
}
|
|
|
|
pub fn set_contrast(&mut self, contrast: u8) {
|
|
assert!(contrast <= 63);
|
|
|
|
block!(self.spi.send(0x81)).unwrap(); // (9) Set Electronic Volume: Set Contrast
|
|
block!(self.spi.send(contrast)).unwrap(); // (9) Set Electronic Volume: Set Contrast
|
|
}
|
|
|
|
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 fill(&mut self, segment: u8, page: u8, width: u8, data: u8) {
|
|
assert!(segment + width <= 102);
|
|
let mut delay = Delay::<DefaultClock>::new();
|
|
|
|
self.move_cursor(segment, page);
|
|
|
|
delay.delay_us(5_u8);
|
|
self.cd.set_high();
|
|
|
|
for _ in 0..width {
|
|
block!(self.spi.send(data)).unwrap();
|
|
}
|
|
|
|
delay.delay_us(5_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::<DefaultClock>::new();
|
|
|
|
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 c in string.chars() {
|
|
for segment in SYMBOL_TABLE[c as usize - 46][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_inverted(&mut self, segment: u8, page: u8, string: &str) {
|
|
let mut delay = Delay::<DefaultClock>::new();
|
|
|
|
for i in 0..2 {
|
|
self.move_cursor(segment, page + i);
|
|
|
|
delay.delay_us(5_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 - 46][i as usize] {
|
|
block!(self.spi.send(!*segment)).unwrap();
|
|
}
|
|
block!(self.spi.send(0xFF)).unwrap();
|
|
}
|
|
block!(self.spi.send(0xFF)).unwrap();
|
|
|
|
delay.delay_us(5_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::<DefaultClock>::new();
|
|
|
|
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);
|
|
|
|
delay.delay_us(5_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();
|
|
|
|
delay.delay_us(5_u8);
|
|
self.cd.set_low();
|
|
}
|
|
}
|
|
|
|
pub fn print_u8_inverted(&mut self, segment: u8, page: u8, digits: u8, data: u8) {
|
|
assert!(digits <= 3);
|
|
let mut delay = Delay::<DefaultClock>::new();
|
|
|
|
let mut array = [0usize; 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);
|
|
|
|
delay.delay_us(5_u8);
|
|
self.cd.set_high();
|
|
|
|
block!(self.spi.send(0xFF)).unwrap();
|
|
block!(self.spi.send(0xFF)).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(0xFF)).unwrap();
|
|
}
|
|
block!(self.spi.send(0xFF)).unwrap();
|
|
|
|
delay.delay_us(5_u8);
|
|
self.cd.set_low();
|
|
}
|
|
}
|
|
|
|
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]) {
|
|
let mut delay = Delay::<DefaultClock>::new();
|
|
self.move_cursor(segment, page);
|
|
|
|
delay.delay_us(5_u8);
|
|
self.cd.set_high();
|
|
|
|
for c in symbol {
|
|
block!(self.spi.send(*c)).unwrap();
|
|
}
|
|
|
|
delay.delay_us(5_u8);
|
|
self.cd.set_low();
|
|
}
|
|
}
|