Adding updates for QSPI streaming
This commit is contained in:
parent
055c92c684
commit
6c2bc22b7a
|
@ -501,52 +501,8 @@ impl<I: Interface> Ad9959<I> {
|
||||||
/ (1u64 << 32) as f32)
|
/ (1u64 << 32) as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_profile(
|
pub fn free(self) -> I {
|
||||||
&self,
|
self.interface
|
||||||
channel: Channel,
|
|
||||||
freq: f32,
|
|
||||||
turns: f32,
|
|
||||||
amplitude: f32,
|
|
||||||
) -> Result<[u32; 4], Error> {
|
|
||||||
let csr: u8 = *0x00_u8
|
|
||||||
.set_bits(1..=2, self.communication_mode as u8)
|
|
||||||
.set_bit(4 + channel as usize, true);
|
|
||||||
|
|
||||||
// The function for channel frequency is `f_out = FTW * f_s / 2^32`, where FTW is the
|
|
||||||
// frequency tuning word and f_s is the system clock rate.
|
|
||||||
let tuning_word: u32 = ((freq * (1u64 << 32) as f32)
|
|
||||||
/ self.system_clock_frequency())
|
|
||||||
as u32;
|
|
||||||
|
|
||||||
let phase_offset: u16 = (turns * (1 << 14) as f32) as u16 & 0x3FFFu16;
|
|
||||||
let pow: u32 = *0u32
|
|
||||||
.set_bits(24..32, Register::CPOW0 as u32)
|
|
||||||
.set_bits(8..24, phase_offset as u32)
|
|
||||||
.set_bits(0..8, Register::CFTW0 as u32);
|
|
||||||
|
|
||||||
// Enable the amplitude multiplier for the channel if required. The amplitude control has
|
|
||||||
// full-scale at 0x3FF (amplitude of 1), so the multiplier should be disabled whenever
|
|
||||||
// full-scale is used.
|
|
||||||
let amplitude_control: u16 = (amplitude * (1 << 10) as f32) as u16;
|
|
||||||
|
|
||||||
let acr: u32 = *0u32
|
|
||||||
.set_bits(24..32, Register::ACR as u32)
|
|
||||||
.set_bits(0..10, amplitude_control as u32 & 0x3FF)
|
|
||||||
.set_bit(12, amplitude_control < (1 << 10));
|
|
||||||
|
|
||||||
let serialized: [u32; 4] = [
|
|
||||||
u32::from_le_bytes([
|
|
||||||
Register::CSR as u8,
|
|
||||||
csr,
|
|
||||||
Register::CSR as u8,
|
|
||||||
csr,
|
|
||||||
]),
|
|
||||||
acr.to_be(),
|
|
||||||
pow.to_be(),
|
|
||||||
tuning_word.to_be(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Ok(serialized)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,7 +534,12 @@ impl ProfileSerializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_profile(channel: Channel, ftw: u32, pow: u16, acr: Option<u16>) -> [u32; 4] {
|
pub fn serialize_profile(
|
||||||
|
channel: Channel,
|
||||||
|
ftw: u32,
|
||||||
|
pow: u16,
|
||||||
|
acr: Option<u16>,
|
||||||
|
) -> [u32; 4] {
|
||||||
let mut serializer = ProfileSerializer::new();
|
let mut serializer = ProfileSerializer::new();
|
||||||
|
|
||||||
let csr: u8 = *0x00_u8
|
let csr: u8 = *0x00_u8
|
||||||
|
|
148
src/main.rs
148
src/main.rs
|
@ -55,7 +55,7 @@ use heapless::{consts::*, String};
|
||||||
const SAMPLE_FREQUENCY_KHZ: u32 = 500;
|
const SAMPLE_FREQUENCY_KHZ: u32 = 500;
|
||||||
|
|
||||||
// The desired ADC sample processing buffer size.
|
// The desired ADC sample processing buffer size.
|
||||||
const SAMPLE_BUFFER_SIZE: usize = 8;
|
const SAMPLE_BUFFER_SIZE: usize = 1;
|
||||||
|
|
||||||
#[link_section = ".sram3.eth"]
|
#[link_section = ".sram3.eth"]
|
||||||
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
|
static mut DES_RING: ethernet::DesRing = ethernet::DesRing::new();
|
||||||
|
@ -194,7 +194,7 @@ const APP: () = {
|
||||||
|
|
||||||
eeprom_i2c: hal::i2c::I2c<hal::stm32::I2C2>,
|
eeprom_i2c: hal::i2c::I2c<hal::stm32::I2C2>,
|
||||||
|
|
||||||
dds_output: DdsOutput,
|
dds_output: Option<DdsOutput>,
|
||||||
|
|
||||||
// Note: It appears that rustfmt generates a format that GDB cannot recognize, which
|
// Note: It appears that rustfmt generates a format that GDB cannot recognize, which
|
||||||
// results in GDB breakpoints being set improperly.
|
// results in GDB breakpoints being set improperly.
|
||||||
|
@ -460,8 +460,9 @@ const APP: () = {
|
||||||
// Measure the Pounder PGOOD output to detect if pounder is present on Stabilizer.
|
// Measure the Pounder PGOOD output to detect if pounder is present on Stabilizer.
|
||||||
let pounder_pgood = gpiob.pb13.into_pull_down_input();
|
let pounder_pgood = gpiob.pb13.into_pull_down_input();
|
||||||
delay.delay_ms(2u8);
|
delay.delay_ms(2u8);
|
||||||
let pounder_devices = if pounder_pgood.is_high().unwrap() {
|
let (pounder_devices, dds_output) = if pounder_pgood.is_high().unwrap()
|
||||||
let ad9959 = {
|
{
|
||||||
|
let mut ad9959 = {
|
||||||
let qspi_interface = {
|
let qspi_interface = {
|
||||||
// Instantiate the QUADSPI pins and peripheral interface.
|
// Instantiate the QUADSPI pins and peripheral interface.
|
||||||
let qspi_pins = {
|
let qspi_pins = {
|
||||||
|
@ -592,20 +593,60 @@ const APP: () = {
|
||||||
let adc1_in_p = gpiof.pf11.into_analog();
|
let adc1_in_p = gpiof.pf11.into_analog();
|
||||||
let adc2_in_p = gpiof.pf14.into_analog();
|
let adc2_in_p = gpiof.pf14.into_analog();
|
||||||
|
|
||||||
Some(
|
let pounder_devices = pounder::PounderDevices::new(
|
||||||
pounder::PounderDevices::new(
|
io_expander,
|
||||||
io_expander,
|
&mut ad9959,
|
||||||
ad9959,
|
spi,
|
||||||
spi,
|
adc1,
|
||||||
adc1,
|
adc2,
|
||||||
adc2,
|
adc1_in_p,
|
||||||
adc1_in_p,
|
adc2_in_p,
|
||||||
adc2_in_p,
|
|
||||||
)
|
|
||||||
.unwrap(),
|
|
||||||
)
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let dds_output = {
|
||||||
|
let io_update_trigger = {
|
||||||
|
let _io_update = gpiog
|
||||||
|
.pg7
|
||||||
|
.into_alternate_af2()
|
||||||
|
.set_speed(hal::gpio::Speed::VeryHigh);
|
||||||
|
|
||||||
|
// Configure the IO_Update signal for the DDS.
|
||||||
|
let mut hrtimer = hrtimer::HighResTimerE::new(
|
||||||
|
dp.HRTIM_TIME,
|
||||||
|
dp.HRTIM_MASTER,
|
||||||
|
dp.HRTIM_COMMON,
|
||||||
|
ccdr.clocks,
|
||||||
|
ccdr.peripheral.HRTIM,
|
||||||
|
);
|
||||||
|
|
||||||
|
// IO_Update should be latched for 50ns after the QSPI profile write. Profile writes
|
||||||
|
// are always 16 bytes, with 2 cycles required per byte, coming out to a total of 32
|
||||||
|
// QSPI clock cycles. The QSPI is configured for 40MHz, so this comes out to an
|
||||||
|
// offset of 800nS. We use 900ns to be safe - note that the timer is triggered after
|
||||||
|
// the QSPI write, which can take approximately 120nS, so there is additional
|
||||||
|
// margin.
|
||||||
|
hrtimer.configure_single_shot(
|
||||||
|
hrtimer::Channel::Two,
|
||||||
|
50_e-9,
|
||||||
|
900_e-9,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure that we have enough time for an IO-update every sample.
|
||||||
|
assert!(
|
||||||
|
1.0 / (1000 * SAMPLE_FREQUENCY_KHZ) as f32 > 900_e-9
|
||||||
|
);
|
||||||
|
|
||||||
|
hrtimer
|
||||||
|
};
|
||||||
|
|
||||||
|
let qspi = ad9959.free();
|
||||||
|
DdsOutput::new(qspi, io_update_trigger)
|
||||||
|
};
|
||||||
|
|
||||||
|
(Some(pounder_devices), Some(dds_output))
|
||||||
} else {
|
} else {
|
||||||
None
|
(None, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut eeprom_i2c = {
|
let mut eeprom_i2c = {
|
||||||
|
@ -728,49 +769,6 @@ const APP: () = {
|
||||||
// Utilize the cycle counter for RTIC scheduling.
|
// Utilize the cycle counter for RTIC scheduling.
|
||||||
cp.DWT.enable_cycle_counter();
|
cp.DWT.enable_cycle_counter();
|
||||||
|
|
||||||
let dds_output = {
|
|
||||||
let io_update_trigger = {
|
|
||||||
let _io_update = gpiog
|
|
||||||
.pg7
|
|
||||||
.into_alternate_af2()
|
|
||||||
.set_speed(hal::gpio::Speed::VeryHigh);
|
|
||||||
|
|
||||||
// Configure the IO_Update signal for the DDS.
|
|
||||||
let mut hrtimer = hrtimer::HighResTimerE::new(
|
|
||||||
dp.HRTIM_TIME,
|
|
||||||
dp.HRTIM_MASTER,
|
|
||||||
dp.HRTIM_COMMON,
|
|
||||||
ccdr.clocks,
|
|
||||||
ccdr.peripheral.HRTIM,
|
|
||||||
);
|
|
||||||
|
|
||||||
// IO_Update should be latched for 50ns after the QSPI profile write. Profile writes
|
|
||||||
// are always 16 bytes, with 2 cycles required per byte, coming out to a total of 32
|
|
||||||
// QSPI clock cycles. The QSPI is configured for 40MHz, so this comes out to an
|
|
||||||
// offset of 800nS. We use 900ns to be safe - note that the timer is triggered after
|
|
||||||
// the QSPI write, which can take approximately 120nS, so there is additional
|
|
||||||
// margin.
|
|
||||||
hrtimer.configure_single_shot(
|
|
||||||
hrtimer::Channel::Two,
|
|
||||||
50_e-9,
|
|
||||||
900_e-9,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Ensure that we have enough time for an IO-update every sample.
|
|
||||||
assert!(1.0 / (1000 * SAMPLE_FREQUENCY_KHZ) as f32 > 900_e-9);
|
|
||||||
|
|
||||||
hrtimer
|
|
||||||
};
|
|
||||||
|
|
||||||
let timer3 = dp.TIM3.timer(
|
|
||||||
SAMPLE_FREQUENCY_KHZ.khz(),
|
|
||||||
ccdr.peripheral.TIM3,
|
|
||||||
&ccdr.clocks,
|
|
||||||
);
|
|
||||||
|
|
||||||
DdsOutput::new(timer3, io_update_trigger)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Start sampling ADCs.
|
// Start sampling ADCs.
|
||||||
sampling_timer.start();
|
sampling_timer.start();
|
||||||
|
|
||||||
|
@ -781,7 +779,6 @@ const APP: () = {
|
||||||
adcs,
|
adcs,
|
||||||
dacs,
|
dacs,
|
||||||
dds_output,
|
dds_output,
|
||||||
|
|
||||||
pounder: pounder_devices,
|
pounder: pounder_devices,
|
||||||
|
|
||||||
eeprom_i2c,
|
eeprom_i2c,
|
||||||
|
@ -791,13 +788,8 @@ const APP: () = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task(binds = TIM3, resources=[dds_output], priority = 3)]
|
#[task(binds=DMA1_STR3, resources=[adcs, dacs, dds_output, iir_state, iir_ch], priority=2)]
|
||||||
fn dds_update(c: dds_update::Context) {
|
fn adc_update(c: adc_update::Context) {
|
||||||
c.resources.dds_output.update_handler();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[task(binds=DMA1_STR3, resources=[adcs, dacs, pounder, dds_output, iir_state, iir_ch], priority=2)]
|
|
||||||
fn adc_update(mut c: adc_update::Context) {
|
|
||||||
let (adc0_samples, adc1_samples) =
|
let (adc0_samples, adc1_samples) =
|
||||||
c.resources.adcs.transfer_complete_handler();
|
c.resources.adcs.transfer_complete_handler();
|
||||||
|
|
||||||
|
@ -820,25 +812,23 @@ const APP: () = {
|
||||||
.update(&mut c.resources.iir_state[1], x1);
|
.update(&mut c.resources.iir_state[1], x1);
|
||||||
y1 as i16 as u16 ^ 0x8000
|
y1 as i16 as u16 ^ 0x8000
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if c.resources.pounder.is_some() {
|
if let Some(dds_output) = c.resources.dds_output {
|
||||||
let profile = ad9959::serialize_profile(
|
let profile = ad9959::serialize_profile(
|
||||||
pounder::Channel::Out0.into(),
|
pounder::Channel::Out0.into(),
|
||||||
u32::MAX / 4,
|
u32::MAX / 4,
|
||||||
0,
|
0,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
c.resources.dds_output.lock(|dds_output| {
|
dds_output.write_profile(profile);
|
||||||
dds_output.push(profile);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.resources.dacs.next_data(&dac0, &dac1);
|
c.resources.dacs.next_data(&dac0, &dac1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[idle(resources=[net_interface, pounder, mac_addr, eth_mac, iir_state, iir_ch, afe0, afe1])]
|
#[idle(resources=[net_interface, mac_addr, eth_mac, iir_state, iir_ch, afe0, afe1])]
|
||||||
fn idle(mut c: idle::Context) -> ! {
|
fn idle(mut c: idle::Context) -> ! {
|
||||||
let mut socket_set_entries: [_; 8] = Default::default();
|
let mut socket_set_entries: [_; 8] = Default::default();
|
||||||
let mut sockets =
|
let mut sockets =
|
||||||
|
|
|
@ -1,43 +1,21 @@
|
||||||
|
use super::QspiInterface;
|
||||||
use crate::hrtimer::HighResTimerE;
|
use crate::hrtimer::HighResTimerE;
|
||||||
use stm32h7xx_hal as hal;
|
use stm32h7xx_hal as hal;
|
||||||
|
|
||||||
pub struct DdsOutput {
|
pub struct DdsOutput {
|
||||||
profiles: heapless::spsc::Queue<[u32; 4], heapless::consts::U32>,
|
_qspi: QspiInterface,
|
||||||
update_timer: hal::timer::Timer<hal::stm32::TIM3>,
|
|
||||||
io_update_trigger: HighResTimerE,
|
io_update_trigger: HighResTimerE,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DdsOutput {
|
impl DdsOutput {
|
||||||
pub fn new(
|
pub fn new(_qspi: QspiInterface, io_update_trigger: HighResTimerE) -> Self {
|
||||||
mut timer: hal::timer::Timer<hal::stm32::TIM3>,
|
|
||||||
io_update_trigger: HighResTimerE,
|
|
||||||
) -> Self {
|
|
||||||
timer.pause();
|
|
||||||
timer.reset_counter();
|
|
||||||
timer.clear_uif_bit();
|
|
||||||
timer.listen(hal::timer::Event::TimeOut);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
update_timer: timer,
|
_qspi,
|
||||||
io_update_trigger,
|
io_update_trigger,
|
||||||
profiles: heapless::spsc::Queue::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_handler(&mut self) {
|
pub fn write_profile(&mut self, profile: [u32; 4]) {
|
||||||
self.update_timer.clear_uif_bit();
|
|
||||||
match self.profiles.dequeue() {
|
|
||||||
Some(profile) => self.write_profile(profile),
|
|
||||||
None => self.update_timer.pause(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push(&mut self, profile: [u32; 4]) {
|
|
||||||
self.profiles.enqueue(profile).unwrap();
|
|
||||||
self.update_timer.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_profile(&mut self, profile: [u32; 4]) {
|
|
||||||
let regs = unsafe { &*hal::stm32::QUADSPI::ptr() };
|
let regs = unsafe { &*hal::stm32::QUADSPI::ptr() };
|
||||||
unsafe {
|
unsafe {
|
||||||
core::ptr::write_volatile(
|
core::ptr::write_volatile(
|
||||||
|
|
|
@ -262,7 +262,6 @@ impl ad9959::Interface for QspiInterface {
|
||||||
|
|
||||||
/// A structure containing implementation for Pounder hardware.
|
/// A structure containing implementation for Pounder hardware.
|
||||||
pub struct PounderDevices {
|
pub struct PounderDevices {
|
||||||
pub ad9959: ad9959::Ad9959<QspiInterface>,
|
|
||||||
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
|
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
|
||||||
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
|
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
|
||||||
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
|
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
|
||||||
|
@ -283,7 +282,7 @@ impl PounderDevices {
|
||||||
/// * `adc2_in_p` - The input channel for the RF power measurement on IN1.
|
/// * `adc2_in_p` - The input channel for the RF power measurement on IN1.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
|
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
|
||||||
ad9959: ad9959::Ad9959<QspiInterface>,
|
ad9959: &mut ad9959::Ad9959<QspiInterface>,
|
||||||
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
|
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
|
||||||
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
|
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
|
||||||
adc2: hal::adc::Adc<hal::stm32::ADC2, hal::adc::Enabled>,
|
adc2: hal::adc::Adc<hal::stm32::ADC2, hal::adc::Enabled>,
|
||||||
|
@ -292,7 +291,6 @@ impl PounderDevices {
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut devices = Self {
|
let mut devices = Self {
|
||||||
mcp23017,
|
mcp23017,
|
||||||
ad9959,
|
|
||||||
attenuator_spi,
|
attenuator_spi,
|
||||||
adc1,
|
adc1,
|
||||||
adc2,
|
adc2,
|
||||||
|
@ -317,87 +315,18 @@ impl PounderDevices {
|
||||||
.map_err(|_| Error::I2c)?;
|
.map_err(|_| Error::I2c)?;
|
||||||
|
|
||||||
// Select the on-board clock with a 4x prescaler (400MHz).
|
// Select the on-board clock with a 4x prescaler (400MHz).
|
||||||
devices.select_onboard_clock(4u8)?;
|
devices
|
||||||
|
.mcp23017
|
||||||
// Run the DDS in stream-only mode (no read support).
|
|
||||||
devices.ad9959.interface.start_stream().unwrap();
|
|
||||||
|
|
||||||
Ok(devices)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Select the an external for the DDS reference clock source.
|
|
||||||
///
|
|
||||||
/// Args:
|
|
||||||
/// * `frequency` - The frequency of the external clock source.
|
|
||||||
/// * `multiplier` - The multiplier of the reference clock to use in the DDS.
|
|
||||||
fn select_external_clock(
|
|
||||||
&mut self,
|
|
||||||
frequency: f32,
|
|
||||||
prescaler: u8,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
self.mcp23017
|
|
||||||
.digital_write(EXT_CLK_SEL_PIN, true)
|
|
||||||
.map_err(|_| Error::I2c)?;
|
|
||||||
self.ad9959
|
|
||||||
.configure_system_clock(frequency, prescaler)
|
|
||||||
.map_err(|_| Error::Dds)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Select the onboard oscillator for the DDS reference clock source.
|
|
||||||
///
|
|
||||||
/// Args:
|
|
||||||
/// * `multiplier` - The multiplier of the reference clock to use in the DDS.
|
|
||||||
fn select_onboard_clock(&mut self, multiplier: u8) -> Result<(), Error> {
|
|
||||||
self.mcp23017
|
|
||||||
.digital_write(EXT_CLK_SEL_PIN, false)
|
.digital_write(EXT_CLK_SEL_PIN, false)
|
||||||
.map_err(|_| Error::I2c)?;
|
.map_err(|_| Error::I2c)?;
|
||||||
self.ad9959
|
ad9959
|
||||||
.configure_system_clock(100_000_000f32, multiplier)
|
.configure_system_clock(100_000_000f32, 4)
|
||||||
.map_err(|_| Error::Dds)?;
|
.map_err(|_| Error::Dds)?;
|
||||||
|
|
||||||
Ok(())
|
// Run the DDS in stream-only mode (no read support).
|
||||||
}
|
ad9959.interface.start_stream().unwrap();
|
||||||
|
|
||||||
/// Configure the Pounder DDS clock.
|
Ok(devices)
|
||||||
///
|
|
||||||
/// Args:
|
|
||||||
/// * `config` - The configuration of the DDS clock desired.
|
|
||||||
pub fn configure_dds_clock(
|
|
||||||
&mut self,
|
|
||||||
config: DdsClockConfig,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
if config.external_clock {
|
|
||||||
self.select_external_clock(
|
|
||||||
config.reference_clock,
|
|
||||||
config.multiplier,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
self.select_onboard_clock(config.multiplier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the pounder DDS clock configuration
|
|
||||||
///
|
|
||||||
/// Returns:
|
|
||||||
/// The current pounder DDS clock configuration.
|
|
||||||
pub fn get_dds_clock_config(&mut self) -> Result<DdsClockConfig, Error> {
|
|
||||||
let external_clock = self
|
|
||||||
.mcp23017
|
|
||||||
.digital_read(EXT_CLK_SEL_PIN)
|
|
||||||
.map_err(|_| Error::I2c)?;
|
|
||||||
let multiplier = self
|
|
||||||
.ad9959
|
|
||||||
.get_reference_clock_multiplier()
|
|
||||||
.map_err(|_| Error::Dds)?;
|
|
||||||
let reference_clock = self.ad9959.get_reference_clock_frequency();
|
|
||||||
|
|
||||||
Ok(DdsClockConfig {
|
|
||||||
multiplier,
|
|
||||||
reference_clock,
|
|
||||||
external_clock,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue