From 52bf0e6eec0d667304289e862825f4a4ef02a28b Mon Sep 17 00:00:00 2001 From: finga Date: Fri, 1 Apr 2022 01:12:51 +0200 Subject: [PATCH] fw-rust: Prepare to implement Si5351 commands Show settings of Si5351 channels on home screen. Initialize I2c and Si5351. --- firmware/rust/.cargo/config.toml | 1 + firmware/rust/Cargo.lock | 17 +++++++ firmware/rust/Cargo.toml | 1 + firmware/rust/src/assets.rs | 20 +++++++- firmware/rust/src/lcd.rs | 84 +++++++++++++++++++++++++++++--- firmware/rust/src/main.rs | 10 +++- firmware/rust/src/screen/home.rs | 58 +++++++++++++++++++++- firmware/rust/src/screen/mod.rs | 10 +++- 8 files changed, 188 insertions(+), 13 deletions(-) diff --git a/firmware/rust/.cargo/config.toml b/firmware/rust/.cargo/config.toml index e04df30..bdea107 100644 --- a/firmware/rust/.cargo/config.toml +++ b/firmware/rust/.cargo/config.toml @@ -3,3 +3,4 @@ target = "avr-specs/avr-atmega328p.json" [unstable] build-std = ["core"] +build-std-features = ["compiler-builtins-mangled-names"] diff --git a/firmware/rust/Cargo.lock b/firmware/rust/Cargo.lock index c856d14..74b8068 100644 --- a/firmware/rust/Cargo.lock +++ b/firmware/rust/Cargo.lock @@ -55,6 +55,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "cfg-if" version = "0.1.10" @@ -70,6 +76,7 @@ dependencies = [ "embedded-hal", "nb 1.0.0", "panic-halt", + "si5351", ] [[package]] @@ -157,6 +164,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "si5351" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06c1f1f280165963ce5fdff953a5303ac186b2b723aa1ed33916db70ceabfb8" +dependencies = [ + "bitflags", + "embedded-hal", +] + [[package]] name = "syn" version = "1.0.86" diff --git a/firmware/rust/Cargo.toml b/firmware/rust/Cargo.toml index aee0597..50a1fe9 100644 --- a/firmware/rust/Cargo.toml +++ b/firmware/rust/Cargo.toml @@ -15,6 +15,7 @@ panic-halt = "0.2" nb = "1.0" embedded-hal = "0.2" avr-device = { version = "0.3", features = ["atmega328p"] } +si5351 = "0.2" [dependencies.atmega-hal] git = "https://github.com/rahix/avr-hal" diff --git a/firmware/rust/src/assets.rs b/firmware/rust/src/assets.rs index 9892e41..6be82da 100644 --- a/firmware/rust/src/assets.rs +++ b/firmware/rust/src/assets.rs @@ -43,6 +43,22 @@ pub const ONDERS_ORG: [[u8; 48]; 2] = [ ], ]; +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +pub const ON: [u8; 11] = [ + 0x00, 0x7E, 0x66, 0x7E, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00, +]; + +pub const OFF: [u8; 11] = [ + 0x7E, 0x66, 0x7E, 0x00, 0x7E, 0x16, 0x16, 0x00, 0x7E, 0x16, 0x16, +]; + +pub const PLL_A: [u8; 6] = [0x00, 0x7C, 0x12, 0x12, 0x7C, 0x00]; + +pub const PLL_B: [u8; 6] = [0x00, 0x7E, 0x4A, 0x4A, 0x74, 0x00]; + +// TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized +const SYM_DOT: [&[u8]; 2] = [&[0x00, 0x00], &[0x30, 0x30]]; + // TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized const SYM_0: [&[u8]; 2] = [ &[0xF8, 0xFC, 0x0C, 0xFC, 0xF8], @@ -206,7 +222,9 @@ const SYM_INVALID: [&[u8]; 2] = [ ]; // TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized -pub const SYMBOL_TABLE: [&[&[u8]; 2]; 48] = [ +pub const SYMBOL_TABLE: [&[&[u8]; 2]; 50] = [ + &SYM_DOT, // '.' + &SYM_INVALID, // '/' &SYM_0, // '0' &SYM_1, // '1' &SYM_2, // '2' diff --git a/firmware/rust/src/lcd.rs b/firmware/rust/src/lcd.rs index 53dee58..02bee27 100644 --- a/firmware/rust/src/lcd.rs +++ b/firmware/rust/src/lcd.rs @@ -32,10 +32,9 @@ impl Lcd { delay.delay_ms(1_u8); let init_sequence = [ - 0x40, // (6) Set Scroll Line: Display start line 0 + 0x40, // (6) Set Scroll Line: Display start line 0 0xA1, // (13) Set SEG direction: SEG reverse 0xC0, // (14) Set COM direction: Normal COM0 - COM63 - // 0xA4, // (10) Set All Pixel On: Disable -> Set All Pixel to ON 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 @@ -43,8 +42,6 @@ impl Lcd { 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 ]; @@ -112,7 +109,7 @@ impl Lcd { 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] { + for segment in SYMBOL_TABLE[c as usize - 46][i as usize] { block!(self.spi.send(*segment)).unwrap(); } block!(self.spi.send(0x00)).unwrap(); @@ -138,7 +135,7 @@ impl Lcd { 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] { + for segment in SYMBOL_TABLE[c as usize - 46][i as usize] { block!(self.spi.send(!*segment)).unwrap(); } block!(self.spi.send(0xFF)).unwrap(); @@ -157,7 +154,7 @@ impl Lcd { let mut array = [0usize; 3]; for (i, item) in array.iter_mut().enumerate() { - *item = ((data / 10_u8.pow(i.try_into().unwrap())) % 10).into(); + *item = (((data / 10_u8.pow(i.try_into().unwrap())) % 10) + 2).into(); } array.reverse(); @@ -190,7 +187,7 @@ impl Lcd { let mut array = [0usize; 3]; for (i, item) in array.iter_mut().enumerate() { - *item = ((data / 10_u8.pow(i.try_into().unwrap())) % 10).into(); + *item = (((data / 10_u8.pow(i.try_into().unwrap())) % 10) + 2).into(); } array.reverse(); @@ -216,4 +213,75 @@ impl Lcd { self.cd.set_low(); } } + + 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); + + // 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 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(); + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); + } + } + + pub fn print_icon(&mut self, segment: u8, page: u8, symbol: &[u8]) { + 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 c in symbol { + block!(self.spi.send(*c)).unwrap(); + } + + // TODO: This delay fixes issues, try find a better solution + delay.delay_ms(1_u8); + self.cd.set_low(); + } } diff --git a/firmware/rust/src/main.rs b/firmware/rust/src/main.rs index 505fc8b..8f377a5 100644 --- a/firmware/rust/src/main.rs +++ b/firmware/rust/src/main.rs @@ -28,6 +28,9 @@ mod screen; use rotary::{Direction, Rotary}; use screen::{Screen, Screens}; +pub type DefaultClock = MHz8; +pub type I2c = atmega_hal::i2c::I2c; + #[used] #[link_section = ".eeprom"] static BACKLIGHT: u8 = 0; @@ -54,7 +57,6 @@ struct ClockGenerator { impl ClockGenerator { fn new() -> Self { - // Get peripherals, pins and eeprom let dp = Peripherals::take().unwrap(); let pins = pins!(dp); @@ -82,6 +84,12 @@ impl ClockGenerator { pins.pd5.into_output(), pins.pb0.into_output(), pins.pb1.into_output(), + I2c::new( + dp.TWI, + pins.pc4.into_pull_up_input(), + pins.pc5.into_pull_up_input(), + 50000, + ), ), tc1: dp.TC1, exint: dp.EXINT, diff --git a/firmware/rust/src/screen/home.rs b/firmware/rust/src/screen/home.rs index 3fe84ba..b54c704 100644 --- a/firmware/rust/src/screen/home.rs +++ b/firmware/rust/src/screen/home.rs @@ -1,5 +1,10 @@ use super::{Draw, Event, Screens, Setup, Splash}; -use crate::{lcd::Lcd, Input}; +use crate::{ + assets::{OFF, ON, PLL_A, PLL_B}, + lcd::Lcd, + Input, +}; +use si5351::PLL; enum Selection { Ch1, @@ -8,14 +13,53 @@ enum Selection { Setup, } +struct Channel { + freq: u32, + enabled: bool, + pll: PLL, +} + +impl Channel { + fn print(&self, lcd: &mut Lcd, page: u8) { + lcd.print_freq(25, page, self.freq); + lcd.print_icon(91, page, if self.enabled { &ON } else { &OFF }); + lcd.print_icon( + 94, + page + 1, + match self.pll { + PLL::A => &PLL_A, + PLL::B => &PLL_B, + }, + ); + } +} + pub struct Home { active: Selection, + channels: [Channel; 3], } impl Home { pub fn new() -> Self { Self { active: Selection::Ch1, + channels: [ + Channel { + freq: 0, + enabled: false, + pll: PLL::A, + }, + Channel { + freq: 0, + enabled: false, + pll: PLL::A, + }, + Channel { + freq: 0, + enabled: false, + pll: PLL::A, + }, + ], } } @@ -56,26 +100,38 @@ impl Draw for Home { match &self.active { Selection::Ch1 => { lcd.print_inverted(0, 0, "CH1"); + self.channels[0].print(lcd, 0); lcd.print(0, 2, "CH2"); + self.channels[1].print(lcd, 2); lcd.print(0, 4, "CH3"); + self.channels[2].print(lcd, 4); lcd.print(33, 6, "SETUP"); } Selection::Ch2 => { lcd.print(0, 0, "CH1"); + self.channels[0].print(lcd, 0); lcd.print_inverted(0, 2, "CH2"); + self.channels[1].print(lcd, 2); lcd.print(0, 4, "CH3"); + self.channels[2].print(lcd, 4); lcd.print(33, 6, "SETUP"); } Selection::Ch3 => { lcd.print(0, 0, "CH1"); + self.channels[0].print(lcd, 0); lcd.print(0, 2, "CH2"); + self.channels[1].print(lcd, 2); lcd.print_inverted(0, 4, "CH3"); + self.channels[2].print(lcd, 4); lcd.print(33, 6, "SETUP"); } Selection::Setup => { lcd.print(0, 0, "CH1"); + self.channels[0].print(lcd, 0); lcd.print(0, 2, "CH2"); + self.channels[1].print(lcd, 2); lcd.print(0, 4, "CH3"); + self.channels[2].print(lcd, 4); lcd.print_inverted(33, 6, "SETUP"); } } diff --git a/firmware/rust/src/screen/mod.rs b/firmware/rust/src/screen/mod.rs index 621ca51..80a5181 100644 --- a/firmware/rust/src/screen/mod.rs +++ b/firmware/rust/src/screen/mod.rs @@ -3,12 +3,13 @@ use atmega_hal::{ port::{mode::Output, Pin, PB0, PB1, PD5}, Spi, }; +use si5351::{Si5351, Si5351Device}; mod home; mod setup; mod splash; -use crate::{eeprom, lcd::Lcd, Input, BACKLIGHT}; +use crate::{eeprom, lcd::Lcd, I2c, Input, BACKLIGHT}; pub use home::Home; pub use setup::Setup; pub use splash::Splash; @@ -47,6 +48,7 @@ pub struct Screen { tc0: TC0, pwm: Pin, screen: Screens, + si5351: Si5351Device, } impl Screen { @@ -56,12 +58,14 @@ impl Screen { pwm: Pin, cd: Pin, rst: Pin, + i2c: I2c, ) -> Self { Self { lcd: Lcd::new(spi, cd, rst), tc0, pwm, screen: Screens::Splash(Splash), + si5351: Si5351Device::new_adafruit_module(i2c), } } @@ -76,8 +80,10 @@ impl Screen { // Init lcd display self.lcd.init(); - self.draw(); + + // Init Si5351 + self.si5351.init_adafruit_module().unwrap(); } fn set_backlight(&mut self, backlight: u8) {