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::{
|
use stm32f1xx_hal::{
|
||||||
flash::{self, FlashWriter},
|
flash::{self, FlashWriter},
|
||||||
gpio::{self, gpioa, gpioc, Alternate, Output, PushPull},
|
gpio::{self, gpioa, gpioc, Alternate, OpenDrain, Output, Pin, PushPull},
|
||||||
i2c, pac,
|
i2c,
|
||||||
pac::{RCC, TIM2, TIM3, TIM4},
|
pac::{self, I2C1, RCC, TIM2, TIM3, TIM4},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
rcc::Enable,
|
rcc::{Enable, Reset},
|
||||||
rcc::Reset,
|
|
||||||
timer::{self, Channel, PwmHz, Tim4NoRemap},
|
timer::{self, Channel, PwmHz, Tim4NoRemap},
|
||||||
};
|
};
|
||||||
|
|
||||||
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
|
use stm32f1xx_hal::usb::{Peripheral, UsbBus, UsbBusType};
|
||||||
use usb_device::prelude::*;
|
use usb_device::prelude::*;
|
||||||
|
|
||||||
use heapless::Vec;
|
use heapless::{String, Vec};
|
||||||
use postcard::{from_bytes_cobs, to_vec_cobs};
|
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::nvstate::{self, NVState};
|
||||||
use crate::si5153;
|
use crate::si5153;
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
fmt::Write,
|
||||||
|
iter::{zip, Zip},
|
||||||
|
};
|
||||||
|
|
||||||
const USB_BUFFER_SIZE: usize = 64;
|
const USB_BUFFER_SIZE: usize = 64;
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
|
@ -56,6 +60,14 @@ mod app {
|
||||||
pwm: PwmHz<TIM4, Tim4NoRemap, timer::Ch<0>, gpio::Pin<'B', 6, Alternate>>,
|
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]
|
#[shared]
|
||||||
struct Shared {
|
struct Shared {
|
||||||
usb_dev: UsbDevice<'static, UsbBusType>,
|
usb_dev: UsbDevice<'static, UsbBusType>,
|
||||||
|
@ -64,6 +76,7 @@ mod app {
|
||||||
buffer: Vec<u8, USB_BUFFER_SIZE>,
|
buffer: Vec<u8, USB_BUFFER_SIZE>,
|
||||||
nvstate: NVState,
|
nvstate: NVState,
|
||||||
flash: flash::Parts,
|
flash: flash::Parts,
|
||||||
|
i2c1: AppI2C1,
|
||||||
}
|
}
|
||||||
|
|
||||||
const TARGET_FREQ: u64 = 10_000_000_000; // in millihertz
|
const TARGET_FREQ: u64 = 10_000_000_000; // in millihertz
|
||||||
|
@ -207,6 +220,9 @@ mod app {
|
||||||
.device_class(usbd_serial::USB_CLASS_CDC)
|
.device_class(usbd_serial::USB_CLASS_CDC)
|
||||||
.build();
|
.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 scl = gpiob.pb8.into_alternate_open_drain(&mut gpiob.crh);
|
||||||
let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);
|
let sda = gpiob.pb9.into_alternate_open_drain(&mut gpiob.crh);
|
||||||
let mut i2c1 = i2c::BlockingI2c::i2c1(
|
let mut i2c1 = i2c::BlockingI2c::i2c1(
|
||||||
|
@ -225,19 +241,22 @@ mod app {
|
||||||
);
|
);
|
||||||
|
|
||||||
defmt::info!("I2C Setup done");
|
defmt::info!("I2C Setup done");
|
||||||
|
|
||||||
let mut si_pll = si5153::Si5153::new(&i2c1);
|
let mut si_pll = si5153::Si5153::new(&i2c1);
|
||||||
si_pll.init(&mut i2c1, 10_000_000, 800_000_000, 800_000_000);
|
match apply_pll_settings(nvstate.pll_settings.clone(), &mut si_pll, &mut i2c1) {
|
||||||
si_pll.set_ms_source(&mut i2c1, si5153::Multisynth::MS0, si5153::PLL::A);
|
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");
|
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();
|
update_pwm::spawn().unwrap();
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -248,6 +267,7 @@ mod app {
|
||||||
buffer: Vec::new(),
|
buffer: Vec::new(),
|
||||||
nvstate,
|
nvstate,
|
||||||
flash,
|
flash,
|
||||||
|
i2c1,
|
||||||
},
|
},
|
||||||
Local {
|
Local {
|
||||||
board_led,
|
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,
|
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];
|
const PLL_BASE_ADDR: [u8; 2] = [26, 34];
|
||||||
|
|
||||||
impl PLL {
|
impl PLL {
|
||||||
|
@ -99,11 +108,14 @@ where
|
||||||
self.write_byte_reg(i2c, PLL_RESET, 0xA0); // Reset both PLLs
|
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) {
|
pub fn set_pll_freq(&mut self, i2c: &mut I2C, pll: PLL, freq: u32) -> u32 {
|
||||||
// Divider is a + (b/c)
|
// PLL frequency is xtal_freq * (a + b/c)
|
||||||
|
|
||||||
let (a, b, c) = as_fraction(freq, self.freq_xtal);
|
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 {
|
let params = PllParams {
|
||||||
p1: 128 * a + (128 * b / c) - 512,
|
p1: 128 * a + (128 * b / c) - 512,
|
||||||
p2: 128 * b - c * (128 * b / c),
|
p2: 128 * b - c * (128 * b / c),
|
||||||
|
@ -112,6 +124,8 @@ where
|
||||||
|
|
||||||
self.write_params(i2c, pll.base_address(), ¶ms);
|
self.write_params(i2c, pll.base_address(), ¶ms);
|
||||||
self.pll_freqs[pll as usize] = freq;
|
self.pll_freqs[pll as usize] = freq;
|
||||||
|
|
||||||
|
actual_freq
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_ms_output(&mut self, i2c: &mut I2C, synth: Multisynth) {
|
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);
|
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 = self.ms_srcs[synth as usize];
|
||||||
let pll_freq = self.pll_freqs[pll 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 (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 {
|
let params = PllParams {
|
||||||
p1: 128 * a + (128 * b / c) - 512,
|
p1: 128 * a + (128 * b / c) - 512,
|
||||||
p2: 128 * b - c * (128 * b / c),
|
p2: 128 * b - c * (128 * b / c),
|
||||||
p3: 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) {
|
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)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
pub struct PLLSettings {
|
pub struct PLLSettings {
|
||||||
pub ms1_frequency: u32,
|
pub pll_a_frequency: u32,
|
||||||
pub ms2_frequency: u32,
|
pub pll_b_frequency: u32,
|
||||||
pub outputs: [OutputSettings; 3],
|
pub outputs: [OutputSettings; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PLLSettings {
|
impl Default for PLLSettings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
ms1_frequency: 800_000_000,
|
pll_a_frequency: 800_000_000,
|
||||||
ms2_frequency: 800_000_000,
|
pll_b_frequency: 800_000_000,
|
||||||
outputs: [
|
outputs: [
|
||||||
OutputSettings::default(),
|
OutputSettings::default(),
|
||||||
OutputSettings::default(),
|
OutputSettings::default(),
|
||||||
|
@ -59,7 +59,7 @@ impl Default for PLLSettings {
|
||||||
pub struct OutputSettings {
|
pub struct OutputSettings {
|
||||||
pub frequency: u32,
|
pub frequency: u32,
|
||||||
pub enable: bool,
|
pub enable: bool,
|
||||||
pub source: Multisynth,
|
pub source: PLL,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for OutputSettings {
|
impl Default for OutputSettings {
|
||||||
|
@ -67,15 +67,15 @@ impl Default for OutputSettings {
|
||||||
Self {
|
Self {
|
||||||
frequency: 10_000_000,
|
frequency: 10_000_000,
|
||||||
enable: false,
|
enable: false,
|
||||||
source: Multisynth::MS1,
|
source: PLL::A,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum Multisynth {
|
pub enum PLL {
|
||||||
MS1,
|
A,
|
||||||
MS2,
|
B,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
|
|
Loading…
Reference in New Issue