fw-rust: Prepare to implement Si5351 commands
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

Show settings of Si5351 channels on home screen. Initialize I2c and
Si5351.
This commit is contained in:
finga 2022-04-01 01:12:51 +02:00
parent 134db298f6
commit 52bf0e6eec
8 changed files with 188 additions and 13 deletions

View file

@ -3,3 +3,4 @@ target = "avr-specs/avr-atmega328p.json"
[unstable] [unstable]
build-std = ["core"] build-std = ["core"]
build-std-features = ["compiler-builtins-mangled-names"]

View file

@ -55,6 +55,12 @@ dependencies = [
"rustc_version", "rustc_version",
] ]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.10" version = "0.1.10"
@ -70,6 +76,7 @@ dependencies = [
"embedded-hal", "embedded-hal",
"nb 1.0.0", "nb 1.0.0",
"panic-halt", "panic-halt",
"si5351",
] ]
[[package]] [[package]]
@ -157,6 +164,16 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 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]] [[package]]
name = "syn" name = "syn"
version = "1.0.86" version = "1.0.86"

View file

@ -15,6 +15,7 @@ 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"] }
si5351 = "0.2"
[dependencies.atmega-hal] [dependencies.atmega-hal]
git = "https://github.com/rahix/avr-hal" git = "https://github.com/rahix/avr-hal"

View file

@ -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 // TODO: Use https://github.com/rust-lang/rust/issues/85077 when stabilized
const SYM_0: [&[u8]; 2] = [ const SYM_0: [&[u8]; 2] = [
&[0xF8, 0xFC, 0x0C, 0xFC, 0xF8], &[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 // 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_0, // '0'
&SYM_1, // '1' &SYM_1, // '1'
&SYM_2, // '2' &SYM_2, // '2'

View file

@ -32,10 +32,9 @@ impl Lcd {
delay.delay_ms(1_u8); delay.delay_ms(1_u8);
let init_sequence = [ 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 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
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
@ -43,8 +42,6 @@ impl Lcd {
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
nb::block!(eeprom::read_byte(&CONTRAST)).unwrap(), // (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 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();
block!(self.spi.send(0x00)).unwrap(); block!(self.spi.send(0x00)).unwrap();
for c in string.chars() { 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(*segment)).unwrap();
} }
block!(self.spi.send(0x00)).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();
block!(self.spi.send(0xFF)).unwrap(); block!(self.spi.send(0xFF)).unwrap();
for c in string.chars() { 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(!*segment)).unwrap();
} }
block!(self.spi.send(0xFF)).unwrap(); block!(self.spi.send(0xFF)).unwrap();
@ -157,7 +154,7 @@ impl Lcd {
let mut array = [0usize; 3]; let mut array = [0usize; 3];
for (i, item) in array.iter_mut().enumerate() { 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(); array.reverse();
@ -190,7 +187,7 @@ impl Lcd {
let mut array = [0usize; 3]; let mut array = [0usize; 3];
for (i, item) in array.iter_mut().enumerate() { 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(); array.reverse();
@ -216,4 +213,75 @@ impl Lcd {
self.cd.set_low(); self.cd.set_low();
} }
} }
pub fn print_freq(&mut self, segment: u8, page: u8, data: u32) {
let mut delay = Delay::<MHz8>::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::<MHz8>::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();
}
} }

View file

@ -28,6 +28,9 @@ mod screen;
use rotary::{Direction, Rotary}; use rotary::{Direction, Rotary};
use screen::{Screen, Screens}; use screen::{Screen, Screens};
pub type DefaultClock = MHz8;
pub type I2c = atmega_hal::i2c::I2c<DefaultClock>;
#[used] #[used]
#[link_section = ".eeprom"] #[link_section = ".eeprom"]
static BACKLIGHT: u8 = 0; static BACKLIGHT: u8 = 0;
@ -54,7 +57,6 @@ struct ClockGenerator {
impl ClockGenerator { impl ClockGenerator {
fn new() -> Self { fn new() -> Self {
// Get peripherals, pins and eeprom
let dp = Peripherals::take().unwrap(); let dp = Peripherals::take().unwrap();
let pins = pins!(dp); let pins = pins!(dp);
@ -82,6 +84,12 @@ impl ClockGenerator {
pins.pd5.into_output(), pins.pd5.into_output(),
pins.pb0.into_output(), pins.pb0.into_output(),
pins.pb1.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, tc1: dp.TC1,
exint: dp.EXINT, exint: dp.EXINT,

View file

@ -1,5 +1,10 @@
use super::{Draw, Event, Screens, Setup, Splash}; 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 { enum Selection {
Ch1, Ch1,
@ -8,14 +13,53 @@ enum Selection {
Setup, 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 { pub struct Home {
active: Selection, active: Selection,
channels: [Channel; 3],
} }
impl Home { impl Home {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
active: Selection::Ch1, 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 { match &self.active {
Selection::Ch1 => { Selection::Ch1 => {
lcd.print_inverted(0, 0, "CH1"); lcd.print_inverted(0, 0, "CH1");
self.channels[0].print(lcd, 0);
lcd.print(0, 2, "CH2"); lcd.print(0, 2, "CH2");
self.channels[1].print(lcd, 2);
lcd.print(0, 4, "CH3"); lcd.print(0, 4, "CH3");
self.channels[2].print(lcd, 4);
lcd.print(33, 6, "SETUP"); lcd.print(33, 6, "SETUP");
} }
Selection::Ch2 => { Selection::Ch2 => {
lcd.print(0, 0, "CH1"); lcd.print(0, 0, "CH1");
self.channels[0].print(lcd, 0);
lcd.print_inverted(0, 2, "CH2"); lcd.print_inverted(0, 2, "CH2");
self.channels[1].print(lcd, 2);
lcd.print(0, 4, "CH3"); lcd.print(0, 4, "CH3");
self.channels[2].print(lcd, 4);
lcd.print(33, 6, "SETUP"); lcd.print(33, 6, "SETUP");
} }
Selection::Ch3 => { Selection::Ch3 => {
lcd.print(0, 0, "CH1"); lcd.print(0, 0, "CH1");
self.channels[0].print(lcd, 0);
lcd.print(0, 2, "CH2"); lcd.print(0, 2, "CH2");
self.channels[1].print(lcd, 2);
lcd.print_inverted(0, 4, "CH3"); lcd.print_inverted(0, 4, "CH3");
self.channels[2].print(lcd, 4);
lcd.print(33, 6, "SETUP"); lcd.print(33, 6, "SETUP");
} }
Selection::Setup => { Selection::Setup => {
lcd.print(0, 0, "CH1"); lcd.print(0, 0, "CH1");
self.channels[0].print(lcd, 0);
lcd.print(0, 2, "CH2"); lcd.print(0, 2, "CH2");
self.channels[1].print(lcd, 2);
lcd.print(0, 4, "CH3"); lcd.print(0, 4, "CH3");
self.channels[2].print(lcd, 4);
lcd.print_inverted(33, 6, "SETUP"); lcd.print_inverted(33, 6, "SETUP");
} }
} }

View file

@ -3,12 +3,13 @@ use atmega_hal::{
port::{mode::Output, Pin, PB0, PB1, PD5}, port::{mode::Output, Pin, PB0, PB1, PD5},
Spi, Spi,
}; };
use si5351::{Si5351, Si5351Device};
mod home; mod home;
mod setup; mod setup;
mod splash; mod splash;
use crate::{eeprom, lcd::Lcd, Input, BACKLIGHT}; use crate::{eeprom, lcd::Lcd, I2c, 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;
@ -47,6 +48,7 @@ pub struct Screen {
tc0: TC0, tc0: TC0,
pwm: Pin<Output, PD5>, pwm: Pin<Output, PD5>,
screen: Screens, screen: Screens,
si5351: Si5351Device<I2c>,
} }
impl Screen { impl Screen {
@ -56,12 +58,14 @@ impl Screen {
pwm: Pin<Output, PD5>, pwm: Pin<Output, PD5>,
cd: Pin<Output, PB0>, cd: Pin<Output, PB0>,
rst: Pin<Output, PB1>, rst: Pin<Output, PB1>,
i2c: I2c,
) -> Self { ) -> Self {
Self { Self {
lcd: Lcd::new(spi, cd, rst), lcd: Lcd::new(spi, cd, rst),
tc0, tc0,
pwm, pwm,
screen: Screens::Splash(Splash), screen: Screens::Splash(Splash),
si5351: Si5351Device::new_adafruit_module(i2c),
} }
} }
@ -76,8 +80,10 @@ impl Screen {
// Init lcd display // Init lcd display
self.lcd.init(); self.lcd.init();
self.draw(); self.draw();
// Init Si5351
self.si5351.init_adafruit_module().unwrap();
} }
fn set_backlight(&mut self, backlight: u8) { fn set_backlight(&mut self, backlight: u8) {