Added function to apply settings to PLL

Fixed naming in the protocol
This commit is contained in:
Sebastian 2024-05-25 17:06:19 +02:00
parent bf611e99f2
commit e0439791d9
3 changed files with 149 additions and 31 deletions

View File

@ -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<TIM4, Tim4NoRemap, timer::Ch<0>, gpio::Pin<'B', 6, Alternate>>,
}
type AppI2C1 = i2c::BlockingI2c<
I2C1,
(
Pin<'B', 8, Alternate<OpenDrain>>,
Pin<'B', 9, Alternate<OpenDrain>>,
),
>;
#[shared]
struct Shared {
usb_dev: UsbDevice<'static, UsbBusType>,
@ -64,6 +76,7 @@ mod app {
buffer: Vec<u8, USB_BUFFER_SIZE>,
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<AppI2C1>,
i2c: &mut AppI2C1,
) -> Result<PLLSettings, String<128>> {
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)
}
}

View File

@ -14,6 +14,15 @@ pub enum PLL {
B,
}
impl From<cheapsdo_protocol::PLL> 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(), &params);
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(), &params)
self.write_params(i2c, synth.base_address(), &params);
actual_freq
}
pub fn set_ms_phase(&mut self, i2c: &mut I2C, synth: Multisynth, phase: u8) {

View File

@ -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)]