From e0439791d9ddebfd56820b39da16c95607995614 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 25 May 2024 17:06:19 +0200 Subject: [PATCH] Added function to apply settings to PLL Fixed naming in the protocol --- firmware/src/main.rs | 133 +++++++++++++++++++++++++++++++++++------ firmware/src/si5153.rs | 27 +++++++-- protocol/src/lib.rs | 20 +++---- 3 files changed, 149 insertions(+), 31 deletions(-) diff --git a/firmware/src/main.rs b/firmware/src/main.rs index fceefc3..1c997d7 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -26,26 +26,30 @@ mod app { use stm32f1xx_hal::{ flash::{self, FlashWriter}, - gpio::{self, gpioa, gpioc, Alternate, Output, PushPull}, - i2c, pac, - pac::{RCC, TIM2, TIM3, TIM4}, + gpio::{self, gpioa, gpioc, Alternate, OpenDrain, Output, Pin, PushPull}, + i2c, + pac::{self, I2C1, RCC, TIM2, TIM3, TIM4}, prelude::*, - rcc::Enable, - rcc::Reset, + rcc::{Enable, Reset}, timer::{self, Channel, PwmHz, Tim4NoRemap}, }; use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType}; use usb_device::prelude::*; - use heapless::Vec; + use heapless::{String, Vec}; use postcard::{from_bytes_cobs, to_vec_cobs}; - use cheapsdo_protocol::{DeviceMessage, HostMessage, PLLSettings, StatusMessage}; + use cheapsdo_protocol::{DeviceMessage, HostMessage, PLLSettings, StatusMessage, PLL}; use crate::nvstate::{self, NVState}; use crate::si5153; + use core::{ + fmt::Write, + iter::{zip, Zip}, + }; + const USB_BUFFER_SIZE: usize = 64; #[local] @@ -56,6 +60,14 @@ mod app { pwm: PwmHz, gpio::Pin<'B', 6, Alternate>>, } + type AppI2C1 = i2c::BlockingI2c< + I2C1, + ( + Pin<'B', 8, Alternate>, + Pin<'B', 9, Alternate>, + ), + >; + #[shared] struct Shared { usb_dev: UsbDevice<'static, UsbBusType>, @@ -64,6 +76,7 @@ mod app { buffer: Vec, nvstate: NVState, flash: flash::Parts, + i2c1: AppI2C1, } const TARGET_FREQ: u64 = 10_000_000_000; // in millihertz @@ -207,6 +220,9 @@ mod app { .device_class(usbd_serial::USB_CLASS_CDC) .build(); + let mut nvstate = nvstate::load(&mut flash); + defmt::info!("read nvstate from flash"); + let scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh); let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh); let mut i2c1 = i2c::BlockingI2c::i2c1( @@ -225,19 +241,22 @@ mod app { ); defmt::info!("I2C Setup done"); - let mut si_pll = si5153::Si5153::new(&i2c1); - si_pll.init(&mut i2c1, 10_000_000, 800_000_000, 800_000_000); - si_pll.set_ms_source(&mut i2c1, si5153::Multisynth::MS0, si5153::PLL::A); + match apply_pll_settings(nvstate.pll_settings.clone(), &mut si_pll, &mut i2c1) { + Ok(pll_settings) => { + if pll_settings != nvstate.pll_settings { + nvstate.save(&mut flash); + } + } + Err(_) => { + defmt::error!("Applying PLL settings failed. Falling back to safe default."); + nvstate.pll_settings = PLLSettings::default(); + nvstate.save(&mut flash); + } + }; + defmt::info!("si5153 Setup done"); - si_pll.set_ms_freq(&mut i2c1, si5153::Multisynth::MS0, 100_000_000); - si_pll.enable_ms_output(&mut i2c1, si5153::Multisynth::MS0); - - let nvstate = nvstate::load(&mut flash); - - defmt::info!("read nvstate from flash"); - update_pwm::spawn().unwrap(); ( @@ -248,6 +267,7 @@ mod app { buffer: Vec::new(), nvstate, flash, + i2c1, }, Local { board_led, @@ -476,4 +496,83 @@ mod app { } } } + + const MIN_PLL_FREQ: u32 = 600_000_000; + const MAX_PLL_FREQ: u32 = 900_000_000; + const MIN_OUTPUT_FREQ: u32 = 500_000; + const MAX_OUTPUT_FREQ: u32 = 225_000_000; + + fn apply_pll_settings( + mut settings: PLLSettings, + si_pll: &mut si5153::Si5153, + i2c: &mut AppI2C1, + ) -> Result> { + let mut err_msg = String::<128>::new(); + + if settings.pll_a_frequency < MIN_PLL_FREQ || settings.pll_a_frequency > MAX_PLL_FREQ { + write!( + err_msg, + "PLL A frequency {}Hz is below 600MHz or above 900MHz", + settings.pll_a_frequency + ) + .unwrap(); + defmt::error!("Error applying PLL settings: {}", err_msg); + return Err(err_msg); + } + + if settings.pll_b_frequency < MIN_PLL_FREQ || settings.pll_b_frequency > MAX_PLL_FREQ { + write!( + err_msg, + "PLL B frequency {}Hz is below 600MHz or above 900MHz", + settings.pll_b_frequency + ) + .unwrap(); + defmt::error!("Error applying PLL settings: {}", err_msg); + return Err(err_msg); + } + + for i in 0..settings.outputs.len() { + if !settings.outputs[i].enable { + continue; + } + + if settings.outputs[i].frequency < MIN_OUTPUT_FREQ + || settings.outputs[i].frequency > MAX_OUTPUT_FREQ + { + write!( + err_msg, + "MS{} frequency {}Hz is below 500kHz or above 225MHz", + i, settings.pll_b_frequency + ) + .unwrap(); + defmt::error!("Error applying PLL settings: {}", err_msg); + return Err(err_msg); + } + } + + settings.pll_a_frequency = + si_pll.set_pll_freq(i2c, si5153::PLL::A, settings.pll_a_frequency); + settings.pll_b_frequency = + si_pll.set_pll_freq(i2c, si5153::PLL::B, settings.pll_a_frequency); + + let multisynths = [ + si5153::Multisynth::MS0, + si5153::Multisynth::MS1, + si5153::Multisynth::MS2, + ]; + for (ms, output_settings) in zip(multisynths, &mut settings.outputs) { + if !output_settings.enable { + si_pll.disable_ms_output(i2c, ms); + } + + si_pll.set_ms_source(i2c, ms, output_settings.source.into()); + output_settings.frequency = si_pll.set_ms_freq(i2c, ms, output_settings.frequency); + + if output_settings.enable { + si_pll.enable_ms_output(i2c, ms); + } + } + + Ok(settings) + } } diff --git a/firmware/src/si5153.rs b/firmware/src/si5153.rs index 757513b..faab3db 100644 --- a/firmware/src/si5153.rs +++ b/firmware/src/si5153.rs @@ -14,6 +14,15 @@ pub enum PLL { B, } +impl From for PLL { + fn from(other: cheapsdo_protocol::PLL) -> Self { + match other { + cheapsdo_protocol::PLL::A => PLL::A, + cheapsdo_protocol::PLL::B => PLL::B, + } + } +} + const PLL_BASE_ADDR: [u8; 2] = [26, 34]; impl PLL { @@ -99,11 +108,14 @@ where self.write_byte_reg(i2c, PLL_RESET, 0xA0); // Reset both PLLs } - pub fn set_pll_freq(&mut self, i2c: &mut I2C, pll: PLL, freq: u32) { - // Divider is a + (b/c) + pub fn set_pll_freq(&mut self, i2c: &mut I2C, pll: PLL, freq: u32) -> u32 { + // PLL frequency is xtal_freq * (a + b/c) let (a, b, c) = as_fraction(freq, self.freq_xtal); + let actual_freq = + (self.freq_xtal as u64 * a as u64 + self.freq_xtal as u64 * b as u64 / c as u64) as u32; + let params = PllParams { p1: 128 * a + (128 * b / c) - 512, p2: 128 * b - c * (128 * b / c), @@ -112,6 +124,8 @@ where self.write_params(i2c, pll.base_address(), ¶ms); self.pll_freqs[pll as usize] = freq; + + actual_freq } pub fn enable_ms_output(&mut self, i2c: &mut I2C, synth: Multisynth) { @@ -136,18 +150,23 @@ where self.write_byte_reg(i2c, synth.ctrl_address(), value); } - pub fn set_ms_freq(&mut self, i2c: &mut I2C, synth: Multisynth, freq: u32) { + pub fn set_ms_freq(&mut self, i2c: &mut I2C, synth: Multisynth, freq: u32) -> u32 { let pll = self.ms_srcs[synth as usize]; let pll_freq = self.pll_freqs[pll as usize]; + // Output frequency is pll_freq / (a + (b/c)) let (a, b, c) = as_fraction(pll_freq, freq); + let actual_freq = ((pll_freq as u64 * c as u64) / (c as u64 * a as u64 + b as u64)) as u32; + let params = PllParams { p1: 128 * a + (128 * b / c) - 512, p2: 128 * b - c * (128 * b / c), p3: c, }; - self.write_params(i2c, synth.base_address(), ¶ms) + self.write_params(i2c, synth.base_address(), ¶ms); + + actual_freq } pub fn set_ms_phase(&mut self, i2c: &mut I2C, synth: Multisynth, phase: u8) { diff --git a/protocol/src/lib.rs b/protocol/src/lib.rs index af472c8..993b989 100644 --- a/protocol/src/lib.rs +++ b/protocol/src/lib.rs @@ -36,16 +36,16 @@ impl Default for StatusMessage { #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] pub struct PLLSettings { - pub ms1_frequency: u32, - pub ms2_frequency: u32, + pub pll_a_frequency: u32, + pub pll_b_frequency: u32, pub outputs: [OutputSettings; 3], } impl Default for PLLSettings { fn default() -> Self { Self { - ms1_frequency: 800_000_000, - ms2_frequency: 800_000_000, + pll_a_frequency: 800_000_000, + pll_b_frequency: 800_000_000, outputs: [ OutputSettings::default(), OutputSettings::default(), @@ -59,7 +59,7 @@ impl Default for PLLSettings { pub struct OutputSettings { pub frequency: u32, pub enable: bool, - pub source: Multisynth, + pub source: PLL, } impl Default for OutputSettings { @@ -67,15 +67,15 @@ impl Default for OutputSettings { Self { frequency: 10_000_000, enable: false, - source: Multisynth::MS1, + source: PLL::A, } } } -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -pub enum Multisynth { - MS1, - MS2, +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)] +pub enum PLL { + A, + B, } #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]