Added function to apply settings to PLL
Fixed naming in the protocol
This commit is contained in:
parent
bf611e99f2
commit
e0439791d9
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(), ¶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) {
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue