fw-rust: Refactor everything
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Remove avr-eeprom dependency for now and introduce events.
This commit is contained in:
parent
6cd8df515d
commit
fdd1f4636d
9 changed files with 459 additions and 263 deletions
10
firmware/rust/Cargo.lock
generated
10
firmware/rust/Cargo.lock
generated
|
@ -32,15 +32,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "avr-eeprom"
|
|
||||||
version = "0.1.0-dev"
|
|
||||||
source = "git+https://git.onders.org/finga/avr-eeprom-rs.git?branch=main#96397b5fbbaaa8531842db301127c1346f6e05f9"
|
|
||||||
dependencies = [
|
|
||||||
"avr-device",
|
|
||||||
"nb 1.0.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "avr-hal-generic"
|
name = "avr-hal-generic"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -76,7 +67,6 @@ version = "0.1.0-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atmega-hal",
|
"atmega-hal",
|
||||||
"avr-device",
|
"avr-device",
|
||||||
"avr-eeprom",
|
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"nb 1.0.0",
|
"nb 1.0.0",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
|
|
|
@ -15,7 +15,6 @@ panic-halt = "0.2"
|
||||||
nb = "1.0"
|
nb = "1.0"
|
||||||
embedded-hal = "0.2"
|
embedded-hal = "0.2"
|
||||||
avr-device = { version = "0.3", features = ["atmega328p"] }
|
avr-device = { version = "0.3", features = ["atmega328p"] }
|
||||||
avr-eeprom = { git = "https://git.onders.org/finga/avr-eeprom-rs.git", branch = "main" }
|
|
||||||
|
|
||||||
[dependencies.atmega-hal]
|
[dependencies.atmega-hal]
|
||||||
git = "https://github.com/rahix/avr-hal"
|
git = "https://github.com/rahix/avr-hal"
|
||||||
|
|
48
firmware/rust/src/eeprom.rs
Normal file
48
firmware/rust/src/eeprom.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
use atmega_hal::Peripherals;
|
||||||
|
use avr_device::interrupt;
|
||||||
|
use core::convert::Infallible;
|
||||||
|
use nb::Error::WouldBlock;
|
||||||
|
|
||||||
|
pub fn read_byte(p_addr: *const u8) -> nb::Result<u8, Infallible> {
|
||||||
|
let dp = unsafe { Peripherals::steal() };
|
||||||
|
let eeprom = dp.EEPROM;
|
||||||
|
|
||||||
|
// Wait for completion of previous access
|
||||||
|
if eeprom.eecr.read().eepe().bit_is_set() {
|
||||||
|
return Err(WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt::free(|_cs| {
|
||||||
|
// Write address into EEPROM address register
|
||||||
|
eeprom.eear.write(|w| unsafe { w.bits(p_addr as u16) });
|
||||||
|
// Start to read from EEPROM by setting EERE
|
||||||
|
eeprom.eecr.write(|w| w.eere().set_bit());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return data from EEPROM data register
|
||||||
|
Ok(eeprom.eedr.read().bits())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_byte(p_addr: *const u8, data: u8) -> nb::Result<(), Infallible> {
|
||||||
|
let dp = unsafe { Peripherals::steal() };
|
||||||
|
let eeprom = dp.EEPROM;
|
||||||
|
|
||||||
|
// Wait for completion of previous access
|
||||||
|
if eeprom.eecr.read().eepe().bit_is_set() {
|
||||||
|
return Err(WouldBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt::free(|_cs| {
|
||||||
|
// Write address into EEPROM address register
|
||||||
|
eeprom.eear.write(|w| unsafe { w.bits(p_addr as u16) });
|
||||||
|
// Write data into EEPROM data register
|
||||||
|
eeprom.eedr.write(|w| unsafe { w.bits(data) });
|
||||||
|
// Enable writing to the EEPROM by setting EEMPE
|
||||||
|
eeprom.eecr.write(|w| w.eempe().set_bit());
|
||||||
|
// Start to write to EEPROM by setting EEPE
|
||||||
|
eeprom.eecr.write(|w| w.eepe().set_bit());
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return data from EEPROM data register
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -4,15 +4,11 @@ use atmega_hal::{
|
||||||
port::{mode::Output, Pin, PB0, PB1},
|
port::{mode::Output, Pin, PB0, PB1},
|
||||||
Spi,
|
Spi,
|
||||||
};
|
};
|
||||||
use avr_device::interrupt;
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use embedded_hal::{blocking::delay::DelayMs, spi::FullDuplex};
|
use embedded_hal::{blocking::delay::DelayMs, spi::FullDuplex};
|
||||||
use nb::block;
|
use nb::block;
|
||||||
|
|
||||||
use crate::{
|
use crate::{assets::SYMBOL_TABLE, eeprom, CONTRAST};
|
||||||
assets::SYMBOL_TABLE,
|
|
||||||
screen::{Screen, Screens},
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Make `cd` and `rst` pins generic pins
|
// TODO: Make `cd` and `rst` pins generic pins
|
||||||
pub struct Lcd {
|
pub struct Lcd {
|
||||||
|
@ -26,7 +22,7 @@ impl Lcd {
|
||||||
Self { spi, cd, rst }
|
Self { spi, cd, rst }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&mut self, contrast: u8) {
|
pub fn init(&mut self) {
|
||||||
let mut delay = Delay::<MHz8>::new();
|
let mut delay = Delay::<MHz8>::new();
|
||||||
|
|
||||||
// TODO: Test if delay is really needed
|
// TODO: Test if delay is really needed
|
||||||
|
@ -40,13 +36,13 @@ impl Lcd {
|
||||||
0xA1, // (13) Set SEG direction: SEG reverse
|
0xA1, // (13) Set SEG direction: SEG reverse
|
||||||
0xC0, // (14) Set COM direction: Normal COM0 - COM63
|
0xC0, // (14) Set COM direction: Normal COM0 - COM63
|
||||||
// 0xA4, // (10) Set All Pixel On: Disable -> Set All Pixel to ON
|
// 0xA4, // (10) Set All Pixel On: Disable -> Set All Pixel to ON
|
||||||
0xA6, // (11) Set Inverse Display: Display inverse off
|
0xA6, // (11) Set Inverse Display: Display inverse off
|
||||||
0xA2, // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65)
|
0xA2, // (17) Set LCD Bias Ratio: Set Bias 1/9 (Duty 1/65)
|
||||||
0x2F, // (5) Set Power Control: Booster, Regulator and Follower on
|
0x2F, // (5) Set Power Control: Booster, Regulator and Follower on
|
||||||
0x27, // (8) Set VLCD Resistor Ratio: Set Contrast
|
0x27, // (8) Set VLCD Resistor Ratio: Set Contrast
|
||||||
0xEE, // (18) Reset Cursor Update Mode
|
0xEE, // (18) Reset Cursor Update Mode
|
||||||
0x81, // (9) Set Electronic Volume: Set Contrast
|
0x81, // (9) Set Electronic Volume: Set Contrast
|
||||||
contrast, // (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
|
// 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
|
// 0x90, // (25) Set Adv. Program Control 0: Set Temperature compensation curve to -0.11%/°C
|
||||||
0xAF, // (12) Set Display Enable: Display on
|
0xAF, // (12) Set Display Enable: Display on
|
||||||
|
@ -60,6 +56,13 @@ impl Lcd {
|
||||||
delay.delay_ms(1_u8);
|
delay.delay_ms(1_u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
pub fn move_cursor(&mut self, segment: u8, page: u8) {
|
||||||
assert!(segment < 102);
|
assert!(segment < 102);
|
||||||
assert!(page < 8);
|
assert!(page < 8);
|
||||||
|
@ -181,21 +184,36 @@ impl Lcd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self, screen: &Screens) {
|
pub fn print_u8_inverted(&mut self, segment: u8, page: u8, digits: u8, data: u8) {
|
||||||
interrupt::free(|_cs| {
|
assert!(digits <= 3);
|
||||||
self.fill_area(0, 0, 102, 8, 0x00);
|
let mut delay = Delay::<MHz8>::new();
|
||||||
|
|
||||||
match screen {
|
let mut array = [0usize; 3];
|
||||||
Screens::Splash(splash) => {
|
for (i, item) in array.iter_mut().enumerate() {
|
||||||
splash.draw(self);
|
*item = ((data / 10_u8.pow(i.try_into().unwrap())) % 10).into();
|
||||||
}
|
}
|
||||||
Screens::Home(home) => {
|
array.reverse();
|
||||||
home.draw(self);
|
|
||||||
}
|
for i in 0..2 {
|
||||||
Screens::Setup(setup) => {
|
self.move_cursor(segment, page + i);
|
||||||
setup.draw(self);
|
|
||||||
|
// 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 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();
|
||||||
|
|
||||||
|
// TODO: This delay fixes issues, try find a better solution
|
||||||
|
delay.delay_ms(1_u8);
|
||||||
|
self.cd.set_low();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
use atmega_hal::{
|
use atmega_hal::{
|
||||||
clock::MHz8,
|
clock::MHz8,
|
||||||
delay::Delay,
|
delay::Delay,
|
||||||
|
pac::{EXINT, TC1},
|
||||||
pins,
|
pins,
|
||||||
|
port::{self, mode::PullUp, Pin, PB6, PB7, PC0},
|
||||||
spi::{DataOrder, SerialClockRate, Settings, Spi},
|
spi::{DataOrder, SerialClockRate, Settings, Spi},
|
||||||
Peripherals,
|
Peripherals,
|
||||||
};
|
};
|
||||||
use avr_device::interrupt;
|
use avr_device::interrupt;
|
||||||
use avr_eeprom::{eeprom, Eeprom};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
|
|
||||||
use embedded_hal::{
|
use embedded_hal::{
|
||||||
blocking::delay::DelayMs,
|
blocking::delay::DelayMs,
|
||||||
spi::{Mode, Phase, Polarity},
|
spi::{Mode, Phase, Polarity},
|
||||||
|
@ -19,18 +20,21 @@ use embedded_hal::{
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
|
mod eeprom;
|
||||||
mod lcd;
|
mod lcd;
|
||||||
mod rotary;
|
mod rotary;
|
||||||
mod screen;
|
mod screen;
|
||||||
|
|
||||||
use lcd::Lcd;
|
|
||||||
use rotary::{Direction, Rotary};
|
use rotary::{Direction, Rotary};
|
||||||
use screen::Screens;
|
use screen::{Screen, Screens};
|
||||||
|
|
||||||
eeprom! {
|
#[used]
|
||||||
static eeprom EEPROM_CONTRAST: u8 = 8;
|
#[link_section = ".eeprom"]
|
||||||
static eeprom EEPROM_BACKLIGHT: u8 = 1;
|
static BACKLIGHT: u8 = 0;
|
||||||
}
|
|
||||||
|
#[used]
|
||||||
|
#[link_section = ".eeprom"]
|
||||||
|
static CONTRAST: u8 = 8;
|
||||||
|
|
||||||
pub enum Input {
|
pub enum Input {
|
||||||
Next,
|
Next,
|
||||||
|
@ -39,11 +43,122 @@ pub enum Input {
|
||||||
Back,
|
Back,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ClockGenerator {
|
||||||
|
screen: Screen,
|
||||||
|
tc1: TC1,
|
||||||
|
exint: EXINT,
|
||||||
|
encoder: Rotary<Pin<port::mode::Input<PullUp>, PB6>, Pin<port::mode::Input<PullUp>, PB7>>,
|
||||||
|
button: Pin<port::mode::Input<PullUp>, PC0>,
|
||||||
|
delay: Delay<MHz8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClockGenerator {
|
||||||
|
fn new() -> Self {
|
||||||
|
// Get peripherals, pins and eeprom
|
||||||
|
let dp = Peripherals::take().unwrap();
|
||||||
|
let pins = pins!(dp);
|
||||||
|
|
||||||
|
// Set display PWM backlight pin as output
|
||||||
|
pins.pd5.into_output();
|
||||||
|
|
||||||
|
// Init SPI
|
||||||
|
let (spi, _) = Spi::new(
|
||||||
|
dp.SPI,
|
||||||
|
pins.pb5.into_output(),
|
||||||
|
pins.pb3.into_output(),
|
||||||
|
pins.pb4.into_pull_up_input(),
|
||||||
|
pins.pb2.into_output(),
|
||||||
|
Settings {
|
||||||
|
data_order: DataOrder::MostSignificantFirst,
|
||||||
|
clock: SerialClockRate::OscfOver2,
|
||||||
|
mode: Mode {
|
||||||
|
polarity: Polarity::IdleLow,
|
||||||
|
phase: Phase::CaptureOnFirstTransition,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
screen: Screen::new(dp.TC0, spi, pins.pb0.into_output(), pins.pb1.into_output()),
|
||||||
|
tc1: dp.TC1,
|
||||||
|
exint: dp.EXINT,
|
||||||
|
delay: Delay::<MHz8>::new(),
|
||||||
|
encoder: Rotary::new(pins.pb6.into_pull_up_input(), pins.pb7.into_pull_up_input()),
|
||||||
|
button: pins.pc0.into_pull_up_input(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
// Init Timer/Counter1
|
||||||
|
self.tc1.ocr1a.write(|w| unsafe { w.bits(65535) });
|
||||||
|
|
||||||
|
// Enable interrupts for encoder, button and timer
|
||||||
|
self.exint.pcicr.write(|w| w.pcie().bits(0b0000_0011));
|
||||||
|
self.exint.pcmsk0.write(|w| w.pcint().bits(0b1100_0000));
|
||||||
|
self.exint.pcmsk1.write(|w| w.pcint().bits(0b0000_0001));
|
||||||
|
self.tc1.timsk1.write(|w| w.ocie1a().set_bit());
|
||||||
|
|
||||||
|
// Init screen
|
||||||
|
self.screen.init();
|
||||||
|
|
||||||
|
// Show splash screen for a moment
|
||||||
|
self.delay.delay_ms(2000_u16);
|
||||||
|
|
||||||
|
// Set home screen
|
||||||
|
self.screen.change(Screens::Home(screen::Home::new()));
|
||||||
|
|
||||||
|
// Enable interrupts globally
|
||||||
|
unsafe { interrupt::enable() };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self) {
|
||||||
|
if UPDATE_ENCODER.load(Ordering::SeqCst) {
|
||||||
|
interrupt::free(|_cs| {
|
||||||
|
self.delay.delay_ms(3_u8);
|
||||||
|
|
||||||
|
match self.encoder.update() {
|
||||||
|
Direction::Clockwise => {
|
||||||
|
self.screen.input(&Input::Next);
|
||||||
|
}
|
||||||
|
Direction::CounterClockwise => {
|
||||||
|
self.screen.input(&Input::Previous);
|
||||||
|
}
|
||||||
|
Direction::None => {}
|
||||||
|
}
|
||||||
|
UPDATE_ENCODER.store(false, Ordering::SeqCst);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if UPDATE_TIMER.load(Ordering::SeqCst) {
|
||||||
|
self.tc1.tccr1b.write(|w| w.cs1().no_clock());
|
||||||
|
self.screen.input(&Input::Back);
|
||||||
|
UPDATE_TIMER.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if UPDATE_BUTTON.load(Ordering::SeqCst) {
|
||||||
|
self.delay.delay_ms(2_u8);
|
||||||
|
|
||||||
|
if self.button.is_low() {
|
||||||
|
// Press
|
||||||
|
if self.tc1.tccr1b.read().cs1().is_no_clock() {
|
||||||
|
self.tc1.tcnt1.write(|w| unsafe { w.bits(0) });
|
||||||
|
self.tc1.tccr1b.write(|w| w.cs1().prescale_64());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Release
|
||||||
|
if self.tc1.tccr1b.read().cs1().is_prescale_64() {
|
||||||
|
self.tc1.tccr1b.write(|w| w.cs1().no_clock());
|
||||||
|
self.screen.input(&Input::Select);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UPDATE_BUTTON.store(false, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static UPDATE_ENCODER: AtomicBool = AtomicBool::new(false);
|
static UPDATE_ENCODER: AtomicBool = AtomicBool::new(false);
|
||||||
static UPDATE_BUTTON: AtomicBool = AtomicBool::new(false);
|
static UPDATE_BUTTON: AtomicBool = AtomicBool::new(false);
|
||||||
static UPDATE_TIMER: AtomicBool = AtomicBool::new(false);
|
static UPDATE_TIMER: AtomicBool = AtomicBool::new(false);
|
||||||
static CONTRAST: AtomicU8 = AtomicU8::new(0);
|
|
||||||
static BACKLIGHT: AtomicU8 = AtomicU8::new(0);
|
|
||||||
|
|
||||||
#[interrupt(atmega328p)]
|
#[interrupt(atmega328p)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -71,142 +186,10 @@ fn TIMER1_COMPA() {
|
||||||
|
|
||||||
#[atmega_hal::entry]
|
#[atmega_hal::entry]
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
// Get peripherals, pins, eeprom and delay
|
let mut cg = ClockGenerator::new();
|
||||||
let dp = Peripherals::take().unwrap();
|
cg.init();
|
||||||
let pins = pins!(dp);
|
|
||||||
let eeprom = Eeprom::new(dp.EEPROM);
|
|
||||||
let mut delay = Delay::<MHz8>::new();
|
|
||||||
|
|
||||||
// Get contrast and backlight from EEPROM
|
|
||||||
CONTRAST.store(eeprom.read_value(&EEPROM_CONTRAST), Ordering::SeqCst);
|
|
||||||
BACKLIGHT.store(eeprom.read_value(&EEPROM_BACKLIGHT), Ordering::SeqCst);
|
|
||||||
|
|
||||||
// Init display backlight
|
|
||||||
let tc0 = dp.TC0;
|
|
||||||
tc0.tccr0a.write(|w| {
|
|
||||||
w.wgm0().pwm_fast();
|
|
||||||
w.com0b().match_clear();
|
|
||||||
w
|
|
||||||
});
|
|
||||||
tc0.tccr0b.write(|w| {
|
|
||||||
w.wgm02().set_bit();
|
|
||||||
w.cs0().prescale_64();
|
|
||||||
w
|
|
||||||
});
|
|
||||||
tc0.ocr0a.write(|w| unsafe { w.bits(255) });
|
|
||||||
tc0.ocr0b
|
|
||||||
.write(|w| unsafe { w.bits(BACKLIGHT.load(Ordering::SeqCst)) });
|
|
||||||
pins.pd5.into_output();
|
|
||||||
|
|
||||||
// Init SPI
|
|
||||||
let (spi, _) = Spi::new(
|
|
||||||
dp.SPI,
|
|
||||||
pins.pb5.into_output(),
|
|
||||||
pins.pb3.into_output(),
|
|
||||||
pins.pb4.into_pull_up_input(),
|
|
||||||
pins.pb2.into_output(),
|
|
||||||
Settings {
|
|
||||||
data_order: DataOrder::MostSignificantFirst,
|
|
||||||
clock: SerialClockRate::OscfOver2,
|
|
||||||
mode: Mode {
|
|
||||||
polarity: Polarity::IdleLow,
|
|
||||||
phase: Phase::CaptureOnFirstTransition,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Init LCD
|
|
||||||
let mut lcd = Lcd::new(spi, pins.pb0.into_output(), pins.pb1.into_output());
|
|
||||||
lcd.init(CONTRAST.load(Ordering::SeqCst));
|
|
||||||
|
|
||||||
// Init encoder
|
|
||||||
let mut encoder = Rotary::new(pins.pb6.into_pull_up_input(), pins.pb7.into_pull_up_input());
|
|
||||||
encoder.update();
|
|
||||||
|
|
||||||
// Init button
|
|
||||||
let button = pins.pc0.into_pull_up_input();
|
|
||||||
|
|
||||||
// Init Timer/Counter1
|
|
||||||
let tc1 = dp.TC1;
|
|
||||||
tc1.ocr1a.write(|w| unsafe { w.bits(65535) });
|
|
||||||
|
|
||||||
// Enable interrupts for encoder, button and timer
|
|
||||||
dp.EXINT.pcicr.write(|w| w.pcie().bits(0b0000_0011));
|
|
||||||
dp.EXINT.pcmsk0.write(|w| w.pcint().bits(0b1100_0000));
|
|
||||||
dp.EXINT.pcmsk1.write(|w| w.pcint().bits(0b0000_0001));
|
|
||||||
tc1.timsk1.write(|w| w.ocie1a().set_bit());
|
|
||||||
|
|
||||||
// Create screen
|
|
||||||
let mut screen = Screens::Splash(screen::Splash);
|
|
||||||
|
|
||||||
// Draw splash screen
|
|
||||||
lcd.draw(&screen);
|
|
||||||
|
|
||||||
// Show splash screen for a moment
|
|
||||||
delay.delay_ms(2000_u16);
|
|
||||||
|
|
||||||
// Set home screen
|
|
||||||
screen = Screens::Home(screen::Home::new());
|
|
||||||
|
|
||||||
// Draw screen
|
|
||||||
lcd.draw(&screen);
|
|
||||||
|
|
||||||
let mut update_screen = false;
|
|
||||||
|
|
||||||
// Enable interrupts globally
|
|
||||||
unsafe { interrupt::enable() };
|
|
||||||
|
|
||||||
#[allow(clippy::empty_loop)]
|
|
||||||
loop {
|
loop {
|
||||||
if UPDATE_ENCODER.load(Ordering::SeqCst) {
|
cg.update();
|
||||||
interrupt::free(|_cs| {
|
|
||||||
delay.delay_ms(3_u8);
|
|
||||||
|
|
||||||
match encoder.update() {
|
|
||||||
Direction::Clockwise => {
|
|
||||||
screen.input(&Input::Next);
|
|
||||||
update_screen = true;
|
|
||||||
}
|
|
||||||
Direction::CounterClockwise => {
|
|
||||||
screen.input(&Input::Previous);
|
|
||||||
update_screen = true;
|
|
||||||
}
|
|
||||||
Direction::None => {}
|
|
||||||
}
|
|
||||||
UPDATE_ENCODER.store(false, Ordering::SeqCst);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if UPDATE_TIMER.load(Ordering::SeqCst) {
|
|
||||||
tc1.tccr1b.write(|w| w.cs1().no_clock());
|
|
||||||
screen.input(&Input::Back);
|
|
||||||
update_screen = true;
|
|
||||||
UPDATE_TIMER.store(false, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if UPDATE_BUTTON.load(Ordering::SeqCst) {
|
|
||||||
delay.delay_ms(2_u8);
|
|
||||||
|
|
||||||
if button.is_low() {
|
|
||||||
// Press
|
|
||||||
if tc1.tccr1b.read().cs1().is_no_clock() {
|
|
||||||
tc1.tcnt1.write(|w| unsafe { w.bits(0) });
|
|
||||||
tc1.tccr1b.write(|w| w.cs1().prescale_64());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Release
|
|
||||||
if tc1.tccr1b.read().cs1().is_prescale_64() {
|
|
||||||
tc1.tccr1b.write(|w| w.cs1().no_clock());
|
|
||||||
screen.input(&Input::Select);
|
|
||||||
update_screen = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UPDATE_BUTTON.store(false, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if update_screen {
|
|
||||||
lcd.draw(&screen);
|
|
||||||
update_screen = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Screen, Screens, Setup, Splash};
|
use super::{Draw, Event, Screens, Setup, Splash};
|
||||||
use crate::{lcd::Lcd, Input};
|
use crate::{lcd::Lcd, Input};
|
||||||
|
|
||||||
enum Selection {
|
enum Selection {
|
||||||
|
@ -19,39 +19,39 @@ impl Home {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&self, input: &Input) -> Screens {
|
pub fn input(&mut self, input: &Input) -> Event {
|
||||||
Screens::Home(Self {
|
self.active = match self.active {
|
||||||
active: match self.active {
|
Selection::Ch1 => match input {
|
||||||
Selection::Ch1 => match input {
|
Input::Next => Selection::Ch2,
|
||||||
Input::Next => Selection::Ch2,
|
Input::Previous => Selection::Setup,
|
||||||
Input::Previous => Selection::Setup,
|
Input::Select => return Event::Screen(Screens::Splash(Splash)),
|
||||||
Input::Select => return Screens::Splash(Splash),
|
Input::Back => Selection::Ch1,
|
||||||
Input::Back => Selection::Ch1,
|
|
||||||
},
|
|
||||||
Selection::Ch2 => match input {
|
|
||||||
Input::Next => Selection::Ch3,
|
|
||||||
Input::Previous => Selection::Ch1,
|
|
||||||
Input::Select => return Screens::Splash(Splash),
|
|
||||||
Input::Back => Selection::Ch2,
|
|
||||||
},
|
|
||||||
Selection::Ch3 => match input {
|
|
||||||
Input::Next => Selection::Setup,
|
|
||||||
Input::Previous => Selection::Ch2,
|
|
||||||
Input::Select => return Screens::Splash(Splash),
|
|
||||||
Input::Back => Selection::Ch3,
|
|
||||||
},
|
|
||||||
Selection::Setup => match input {
|
|
||||||
Input::Next => Selection::Ch1,
|
|
||||||
Input::Previous => Selection::Ch3,
|
|
||||||
Input::Select => return Screens::Setup(Setup::new()),
|
|
||||||
Input::Back => Selection::Setup,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
Selection::Ch2 => match input {
|
||||||
|
Input::Next => Selection::Ch3,
|
||||||
|
Input::Previous => Selection::Ch1,
|
||||||
|
Input::Select => return Event::Screen(Screens::Splash(Splash)),
|
||||||
|
Input::Back => Selection::Ch2,
|
||||||
|
},
|
||||||
|
Selection::Ch3 => match input {
|
||||||
|
Input::Next => Selection::Setup,
|
||||||
|
Input::Previous => Selection::Ch2,
|
||||||
|
Input::Select => return Event::Screen(Screens::Splash(Splash)),
|
||||||
|
Input::Back => Selection::Ch3,
|
||||||
|
},
|
||||||
|
Selection::Setup => match input {
|
||||||
|
Input::Next => Selection::Ch1,
|
||||||
|
Input::Previous => Selection::Ch3,
|
||||||
|
Input::Select => return Event::Screen(Screens::Setup(Setup::new())),
|
||||||
|
Input::Back => Selection::Setup,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Event::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Screen for Home {
|
impl Draw for Home {
|
||||||
fn draw(&self, lcd: &mut Lcd) {
|
fn draw(&self, lcd: &mut Lcd) {
|
||||||
match &self.active {
|
match &self.active {
|
||||||
Selection::Ch1 => {
|
Selection::Ch1 => {
|
||||||
|
|
|
@ -1,15 +1,28 @@
|
||||||
|
use atmega_hal::{
|
||||||
|
pac::TC0,
|
||||||
|
port::{mode::Output, Pin, PB0, PB1},
|
||||||
|
Spi,
|
||||||
|
};
|
||||||
|
|
||||||
mod home;
|
mod home;
|
||||||
mod setup;
|
mod setup;
|
||||||
mod splash;
|
mod splash;
|
||||||
|
|
||||||
use crate::{lcd::Lcd, Input};
|
use crate::{eeprom, lcd::Lcd, Input, BACKLIGHT};
|
||||||
pub use home::Home;
|
pub use home::Home;
|
||||||
pub use setup::Setup;
|
pub use setup::Setup;
|
||||||
pub use splash::Splash;
|
pub use splash::Splash;
|
||||||
|
|
||||||
// TODO: Only update changes instead of whole screen
|
// TODO: Only update changes instead of whole screen
|
||||||
|
|
||||||
pub trait Screen {
|
pub enum Event {
|
||||||
|
Screen(Screens),
|
||||||
|
Backlight(u8),
|
||||||
|
Contrast(u8),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Draw {
|
||||||
fn draw(&self, lcd: &mut Lcd);
|
fn draw(&self, lcd: &mut Lcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,11 +33,76 @@ pub enum Screens {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Screens {
|
impl Screens {
|
||||||
pub fn input(&mut self, input: &Input) {
|
pub fn input(&mut self, input: &Input) -> Event {
|
||||||
match self {
|
match self {
|
||||||
Screens::Splash(_) => {}
|
Screens::Splash(_) => Event::None,
|
||||||
Screens::Home(home) => *self = home.input(input),
|
Screens::Home(home) => home.input(input),
|
||||||
Screens::Setup(setup) => *self = setup.input(input),
|
Screens::Setup(setup) => setup.input(input),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Screen {
|
||||||
|
lcd: Lcd,
|
||||||
|
tc0: TC0,
|
||||||
|
screen: Screens,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Screen {
|
||||||
|
pub fn new(tc0: TC0, spi: Spi, cd: Pin<Output, PB0>, rst: Pin<Output, PB1>) -> Self {
|
||||||
|
Self {
|
||||||
|
lcd: Lcd::new(spi, cd, rst),
|
||||||
|
tc0,
|
||||||
|
screen: Screens::Splash(Splash),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
// Init display backlight
|
||||||
|
self.tc0.tccr0a.write(|w| {
|
||||||
|
w.wgm0().pwm_fast();
|
||||||
|
w.com0b().match_clear();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
self.tc0.tccr0b.write(|w| {
|
||||||
|
w.wgm02().set_bit();
|
||||||
|
w.cs0().prescale_64();
|
||||||
|
w
|
||||||
|
});
|
||||||
|
self.tc0.ocr0a.write(|w| unsafe { w.bits(255) });
|
||||||
|
self.tc0
|
||||||
|
.ocr0b
|
||||||
|
.write(|w| unsafe { w.bits(nb::block!(eeprom::read_byte(&BACKLIGHT)).unwrap()) });
|
||||||
|
|
||||||
|
// Init lcd display
|
||||||
|
self.lcd.init();
|
||||||
|
|
||||||
|
self.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&mut self) {
|
||||||
|
self.lcd.fill_area(0, 0, 102, 8, 0x00);
|
||||||
|
|
||||||
|
match &self.screen {
|
||||||
|
Screens::Splash(splash) => splash.draw(&mut self.lcd),
|
||||||
|
Screens::Home(home) => home.draw(&mut self.lcd),
|
||||||
|
Screens::Setup(setup) => setup.draw(&mut self.lcd),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(&mut self, input: &Input) {
|
||||||
|
match self.screen.input(input) {
|
||||||
|
Event::Screen(screen) => self.screen = screen,
|
||||||
|
Event::Backlight(backlight) => self.tc0.ocr0b.write(|w| unsafe { w.bits(backlight) }),
|
||||||
|
Event::Contrast(contrast) => self.lcd.set_contrast(contrast),
|
||||||
|
Event::None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn change(&mut self, screen: Screens) {
|
||||||
|
self.screen = screen;
|
||||||
|
self.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,84 +1,164 @@
|
||||||
use super::{Home, Screen, Screens, Splash};
|
use super::{Draw, Event, Home, Screens};
|
||||||
use crate::{lcd::Lcd, Input, BACKLIGHT, CONTRAST};
|
use crate::{eeprom, lcd::Lcd, Input, BACKLIGHT, CONTRAST};
|
||||||
use core::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
enum Selection {
|
enum Selection {
|
||||||
Contrast,
|
|
||||||
Backlight,
|
Backlight,
|
||||||
|
BacklightEdit,
|
||||||
|
Contrast,
|
||||||
|
ContrastEdit,
|
||||||
Back,
|
Back,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Setup {
|
pub struct Setup {
|
||||||
active: Selection,
|
active: Selection,
|
||||||
|
backlight: u8,
|
||||||
|
contrast: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Setup {
|
impl Setup {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
active: Selection::Contrast,
|
active: Selection::Backlight,
|
||||||
|
backlight: nb::block!(eeprom::read_byte(&BACKLIGHT)).unwrap(),
|
||||||
|
contrast: nb::block!(eeprom::read_byte(&CONTRAST)).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&self, input: &Input) -> Screens {
|
pub fn input(&mut self, input: &Input) -> Event {
|
||||||
Screens::Setup(Self {
|
self.active = match self.active {
|
||||||
active: match self.active {
|
Selection::Backlight => match input {
|
||||||
Selection::Contrast => match input {
|
Input::Next => Selection::Contrast,
|
||||||
Input::Next => Selection::Backlight,
|
Input::Previous => Selection::Back,
|
||||||
Input::Previous => Selection::Back,
|
Input::Select => Selection::BacklightEdit,
|
||||||
Input::Select => return Screens::Splash(Splash),
|
Input::Back => return Event::Screen(Screens::Home(Home::new())),
|
||||||
Input::Back => return Screens::Home(Home::new()),
|
|
||||||
},
|
|
||||||
Selection::Backlight => match input {
|
|
||||||
Input::Next => Selection::Back,
|
|
||||||
Input::Previous => Selection::Contrast,
|
|
||||||
Input::Select => return Screens::Splash(Splash),
|
|
||||||
Input::Back => return Screens::Home(Home::new()),
|
|
||||||
},
|
|
||||||
Selection::Back => match input {
|
|
||||||
Input::Next => Selection::Contrast,
|
|
||||||
Input::Previous => Selection::Backlight,
|
|
||||||
Input::Select => return Screens::Home(Home::new()),
|
|
||||||
Input::Back => return Screens::Home(Home::new()),
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
Selection::BacklightEdit => match input {
|
||||||
|
Input::Next => {
|
||||||
|
self.backlight = if self.backlight == u8::MAX {
|
||||||
|
u8::MIN
|
||||||
|
} else {
|
||||||
|
self.backlight + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return Event::Backlight(self.backlight);
|
||||||
|
}
|
||||||
|
Input::Previous => {
|
||||||
|
self.backlight = if self.backlight == u8::MIN {
|
||||||
|
u8::MAX
|
||||||
|
} else {
|
||||||
|
self.backlight - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return Event::Backlight(self.backlight);
|
||||||
|
}
|
||||||
|
Input::Select => {
|
||||||
|
nb::block!(eeprom::write_byte(&BACKLIGHT, self.backlight)).unwrap();
|
||||||
|
Selection::Backlight
|
||||||
|
}
|
||||||
|
Input::Back => {
|
||||||
|
self.active = Selection::Backlight;
|
||||||
|
self.backlight = nb::block!(eeprom::read_byte(&BACKLIGHT)).unwrap();
|
||||||
|
return Event::Backlight(self.backlight);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Selection::Contrast => match input {
|
||||||
|
Input::Next => Selection::Back,
|
||||||
|
Input::Previous => Selection::Backlight,
|
||||||
|
Input::Select => Selection::ContrastEdit,
|
||||||
|
Input::Back => return Event::Screen(Screens::Home(Home::new())),
|
||||||
|
},
|
||||||
|
Selection::ContrastEdit => match input {
|
||||||
|
Input::Next => {
|
||||||
|
self.contrast = if self.contrast >= 63 {
|
||||||
|
u8::MIN
|
||||||
|
} else {
|
||||||
|
self.contrast + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return Event::Contrast(self.contrast);
|
||||||
|
}
|
||||||
|
Input::Previous => {
|
||||||
|
self.contrast = if self.contrast == u8::MIN {
|
||||||
|
63
|
||||||
|
} else {
|
||||||
|
self.contrast - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
return Event::Contrast(self.contrast);
|
||||||
|
}
|
||||||
|
Input::Select => {
|
||||||
|
nb::block!(eeprom::write_byte(&CONTRAST, self.contrast)).unwrap();
|
||||||
|
Selection::Contrast
|
||||||
|
}
|
||||||
|
Input::Back => {
|
||||||
|
self.active = Selection::Contrast;
|
||||||
|
self.contrast = nb::block!(eeprom::read_byte(&CONTRAST)).unwrap();
|
||||||
|
return Event::Contrast(self.contrast);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Selection::Back => match input {
|
||||||
|
Input::Next => Selection::Backlight,
|
||||||
|
Input::Previous => Selection::Contrast,
|
||||||
|
Input::Select => return Event::Screen(Screens::Home(Home::new())),
|
||||||
|
Input::Back => return Event::Screen(Screens::Home(Home::new())),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Event::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Screen for Setup {
|
impl Draw for Setup {
|
||||||
fn draw(&self, lcd: &mut Lcd) {
|
fn draw(&self, lcd: &mut Lcd) {
|
||||||
let contrast = CONTRAST.load(Ordering::SeqCst);
|
|
||||||
let backlight = BACKLIGHT.load(Ordering::SeqCst);
|
|
||||||
|
|
||||||
match &self.active {
|
match &self.active {
|
||||||
Selection::Contrast => {
|
Selection::Contrast => {
|
||||||
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
||||||
lcd.print_inverted(33, 0, "SETUP");
|
lcd.print_inverted(33, 0, "SETUP");
|
||||||
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
||||||
lcd.print_inverted(0, 2, "CONTRAST:");
|
lcd.print(0, 2, "BACKLIGHT:");
|
||||||
lcd.print_u8(89, 2, 2, contrast);
|
lcd.print_u8(81, 2, 3, self.backlight);
|
||||||
lcd.print(0, 4, "BACKLIGHT:");
|
lcd.print_inverted(0, 4, "CONTRAST:");
|
||||||
lcd.print_u8(83, 2, 3, backlight);
|
lcd.print_u8(87, 4, 2, self.contrast);
|
||||||
|
lcd.print(36, 6, "BACK");
|
||||||
|
}
|
||||||
|
Selection::ContrastEdit => {
|
||||||
|
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
||||||
|
lcd.print_inverted(33, 0, "SETUP");
|
||||||
|
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
||||||
|
lcd.print(0, 2, "BACKLIGHT:");
|
||||||
|
lcd.print_u8(81, 2, 3, self.backlight);
|
||||||
|
lcd.print(0, 4, "CONTRAST:");
|
||||||
|
lcd.print_u8_inverted(87, 4, 2, self.contrast);
|
||||||
lcd.print(36, 6, "BACK");
|
lcd.print(36, 6, "BACK");
|
||||||
}
|
}
|
||||||
Selection::Backlight => {
|
Selection::Backlight => {
|
||||||
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
||||||
lcd.print_inverted(33, 0, "SETUP");
|
lcd.print_inverted(33, 0, "SETUP");
|
||||||
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
||||||
lcd.print(0, 2, "CONTRAST:");
|
lcd.print_inverted(0, 2, "BACKLIGHT:");
|
||||||
lcd.print_u8(89, 2, 2, contrast);
|
lcd.print_u8(81, 2, 3, self.backlight);
|
||||||
lcd.print_inverted(0, 4, "BACKLIGHT:");
|
lcd.print(0, 4, "CONTRAST:");
|
||||||
lcd.print_u8(83, 2, 3, backlight);
|
lcd.print_u8(87, 4, 2, self.contrast);
|
||||||
|
lcd.print(36, 6, "BACK");
|
||||||
|
}
|
||||||
|
Selection::BacklightEdit => {
|
||||||
|
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
||||||
|
lcd.print_inverted(33, 0, "SETUP");
|
||||||
|
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
||||||
|
lcd.print(0, 2, "BACKLIGHT:");
|
||||||
|
lcd.print_u8_inverted(81, 2, 3, self.backlight);
|
||||||
|
lcd.print(0, 4, "CONTRAST:");
|
||||||
|
lcd.print_u8(87, 4, 2, self.contrast);
|
||||||
lcd.print(36, 6, "BACK");
|
lcd.print(36, 6, "BACK");
|
||||||
}
|
}
|
||||||
Selection::Back => {
|
Selection::Back => {
|
||||||
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
lcd.fill_area(0, 0, 33, 2, 0xFF);
|
||||||
lcd.print_inverted(33, 0, "SETUP");
|
lcd.print_inverted(33, 0, "SETUP");
|
||||||
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
lcd.fill_area(69, 0, 33, 2, 0xFF);
|
||||||
lcd.print(0, 2, "CONTRAST:");
|
lcd.print(0, 2, "BACKLIGHT:");
|
||||||
lcd.print_u8(89, 2, 2, contrast);
|
lcd.print_u8(81, 2, 3, self.backlight);
|
||||||
lcd.print(0, 4, "BACKLIGHT:");
|
lcd.print(0, 4, "CONTRAST:");
|
||||||
lcd.print_u8(83, 2, 3, backlight);
|
lcd.print_u8(87, 4, 2, self.contrast);
|
||||||
lcd.print_inverted(36, 6, "BACK");
|
lcd.print_inverted(36, 6, "BACK");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::Screen;
|
use super::Draw;
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::{ONDERS_ORG, SACRED_CHAO},
|
assets::{ONDERS_ORG, SACRED_CHAO},
|
||||||
lcd::Lcd,
|
lcd::Lcd,
|
||||||
|
@ -9,7 +9,7 @@ use nb::block;
|
||||||
|
|
||||||
pub struct Splash;
|
pub struct Splash;
|
||||||
|
|
||||||
impl Screen for Splash {
|
impl Draw for Splash {
|
||||||
fn draw(&self, lcd: &mut Lcd) {
|
fn draw(&self, lcd: &mut Lcd) {
|
||||||
let mut delay = Delay::<MHz8>::new();
|
let mut delay = Delay::<MHz8>::new();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue