forked from M-Labs/humpback-dds
dds: add frequency sweep
This commit is contained in:
parent
242e03a8bd
commit
0a3518573a
79
src/dds.rs
79
src/dds.rs
|
@ -4,6 +4,7 @@ use core::mem::size_of;
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use heapless::Vec;
|
use heapless::Vec;
|
||||||
use heapless::consts::*;
|
use heapless::consts::*;
|
||||||
|
use log::{ trace, debug, warn };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
|
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
|
||||||
|
@ -632,6 +633,77 @@ where
|
||||||
|
|
||||||
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Phase,
|
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Phase,
|
||||||
no_dwell_high, zero_crossing, op_mode, playback_rate)
|
no_dwell_high, zero_crossing, op_mode, playback_rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a frequency sweep RAM mode profile
|
||||||
|
*/
|
||||||
|
pub unsafe fn set_frequency_sweep_profile(&mut self, profile: u8, start_addr: u16,
|
||||||
|
lower_boundary: f64, upper_boundary: f64, f_resolution: f64,
|
||||||
|
no_dwell_high: bool, op_mode: RAMOperationMode, playback_rate: f64
|
||||||
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
|
// Check the legality of the profile setup
|
||||||
|
assert!(profile <= 7);
|
||||||
|
assert!(start_addr < 1024);
|
||||||
|
|
||||||
|
// Find out the required RAM size
|
||||||
|
// Frequencies may have to be repeated if the playback rate is too low
|
||||||
|
// Reject impossible setups
|
||||||
|
// E.g. Higher playback rate than f_dds_clk, insufficient RAM allocation
|
||||||
|
let nominal_step_rate = self.f_sys_clk/(4.0 * playback_rate);
|
||||||
|
if nominal_step_rate < 1.0 {
|
||||||
|
return Err(Error::DDSRAMError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Handle unfortunate scenario: step_rate / 0xFFFF gives a round number
|
||||||
|
// Current implmentation unnecessarily allocates 1 extra RAM space for each data
|
||||||
|
let duplication = (nominal_step_rate / (0xFFFF as f64)) as u64 + 1;
|
||||||
|
|
||||||
|
// Acquire the RAM size needed by multiplying duplication.
|
||||||
|
// All data needs to be duplicated such that a desired step_rate can be reached
|
||||||
|
// Return DDS RAM Error if it does not fix into the RAM
|
||||||
|
let span = upper_boundary - lower_boundary;
|
||||||
|
let data_size = if core::intrinsics::roundf64(span/f_resolution) == (span/f_resolution) {
|
||||||
|
(span/f_resolution) as u64 + 1
|
||||||
|
} else {
|
||||||
|
(span/f_resolution) as u64
|
||||||
|
};
|
||||||
|
let ram_size = data_size * duplication;
|
||||||
|
|
||||||
|
let end_addr = (start_addr as u64) + ram_size - 1;
|
||||||
|
trace!("Required RAM size: {}", ram_size);
|
||||||
|
if end_addr >= 1024 {
|
||||||
|
warn!("RAM address out of bound");
|
||||||
|
return Err(Error::DDSRAMError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear RAM vector, and add address byte
|
||||||
|
RAM_VEC.clear();
|
||||||
|
RAM_VEC.push(0x16)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
|
||||||
|
// Drop in the data into RAM_VEC
|
||||||
|
for data_index in 0..data_size {
|
||||||
|
let freq = lower_boundary + f_resolution * (data_index as f64);
|
||||||
|
for _ in 0..duplication {
|
||||||
|
let ftw = self.frequency_to_ftw(freq);
|
||||||
|
RAM_VEC.push(((ftw >> 24) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((ftw >> 16) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((ftw >> 8) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((ftw >> 0) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("start_addr: {}\nend_addr: {}\n, duplication: {}\n, data_size: {}\n",
|
||||||
|
start_addr, end_addr, duplication, data_size);
|
||||||
|
|
||||||
|
self.set_ram_profile(profile, start_addr, end_addr.try_into().unwrap(), RAMDestination::Frequency,
|
||||||
|
no_dwell_high, true, op_mode, playback_rate * (duplication as f64))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -650,6 +722,7 @@ where
|
||||||
|
|
||||||
// Calculate address step rate, and check legality
|
// Calculate address step rate, and check legality
|
||||||
let step_rate = (self.f_sys_clk/(4.0 * playback_rate)) as u64;
|
let step_rate = (self.f_sys_clk/(4.0 * playback_rate)) as u64;
|
||||||
|
trace!("Setting up RAM profile, step_rate: {}", step_rate);
|
||||||
if step_rate == 0 || step_rate > 0xFFFF {
|
if step_rate == 0 || step_rate > 0xFFFF {
|
||||||
return Err(Error::DDSRAMError);
|
return Err(Error::DDSRAMError);
|
||||||
}
|
}
|
||||||
|
@ -729,9 +802,9 @@ where
|
||||||
|
|
||||||
// Setter function for f_sys_clk
|
// Setter function for f_sys_clk
|
||||||
// Warning: This does not setup the chip to generate this actual f_sys_clk
|
// Warning: This does not setup the chip to generate this actual f_sys_clk
|
||||||
pub(crate) fn set_f_sys_clk(&mut self, f_sys_clk: f64) {
|
// pub(crate) fn set_f_sys_clk(&mut self, f_sys_clk: f64) {
|
||||||
self.f_sys_clk = f_sys_clk;
|
// self.f_sys_clk = f_sys_clk;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Getter function for f_sys_clk
|
// Getter function for f_sys_clk
|
||||||
pub fn get_f_sys_clk(&mut self) -> f64 {
|
pub fn get_f_sys_clk(&mut self) -> f64 {
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::config_register::ConfigRegister;
|
||||||
use crate::config_register::CFGMask;
|
use crate::config_register::CFGMask;
|
||||||
use crate::config_register::StatusMask;
|
use crate::config_register::StatusMask;
|
||||||
use crate::attenuator::Attenuator;
|
use crate::attenuator::Attenuator;
|
||||||
use crate::dds::DDS;
|
use crate::dds::{ DDS, RAMOperationMode };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enum for structuring error
|
* Enum for structuring error
|
||||||
|
@ -90,17 +90,17 @@ where
|
||||||
])?;
|
])?;
|
||||||
// Set 0 to all fields on configuration register.
|
// Set 0 to all fields on configuration register.
|
||||||
self.config_register.set_configurations(&mut [
|
self.config_register.set_configurations(&mut [
|
||||||
(CFGMask::RF_SW, 0),
|
(CFGMask::RF_SW, 0),
|
||||||
(CFGMask::LED, 0),
|
(CFGMask::LED, 0),
|
||||||
(CFGMask::PROFILE, 0),
|
(CFGMask::PROFILE, 0),
|
||||||
(CFGMask::IO_UPDATE, 0),
|
(CFGMask::IO_UPDATE, 0),
|
||||||
(CFGMask::MASK_NU, 0),
|
(CFGMask::MASK_NU, 0),
|
||||||
(CFGMask::CLK_SEL0, 0),
|
(CFGMask::CLK_SEL0, 0),
|
||||||
(CFGMask::SYNC_SEL, 0),
|
(CFGMask::SYNC_SEL, 0),
|
||||||
(CFGMask::RST, 0),
|
(CFGMask::RST, 0),
|
||||||
(CFGMask::IO_RST, 0),
|
(CFGMask::IO_RST, 0),
|
||||||
(CFGMask::CLK_SEL1, 0),
|
(CFGMask::CLK_SEL1, 0),
|
||||||
(CFGMask::DIV, 0),
|
(CFGMask::DIV, 0),
|
||||||
])?;
|
])?;
|
||||||
// Init all DDS chips. Configure SDIO as input only.
|
// Init all DDS chips. Configure SDIO as input only.
|
||||||
for chip_no in 0..4 {
|
for chip_no in 0..4 {
|
||||||
|
@ -278,6 +278,16 @@ where
|
||||||
self.dds[usize::from(channel)].set_single_tone_profile_amplitude(profile, amplitude)
|
self.dds[usize::from(channel)].set_single_tone_profile_amplitude(profile, amplitude)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_channel_frequency_sweep_profile(&mut self, channel: u8, profile: u8, start_addr: u16, lower_boundary: f64,
|
||||||
|
upper_boundary: f64, f_resolution: f64, playback_rate: f64) -> Result<(), Error<E>>
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
self.dds[usize::from(channel)]
|
||||||
|
.set_frequency_sweep_profile(profile, start_addr, lower_boundary, upper_boundary,
|
||||||
|
f_resolution, true, RAMOperationMode::ContinuousRecirculate, playback_rate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_channel_sys_clk(&mut self, channel: u8, f_sys_clk: f64) -> Result<(), Error<E>> {
|
pub fn set_channel_sys_clk(&mut self, channel: u8, f_sys_clk: f64) -> Result<(), Error<E>> {
|
||||||
self.dds[usize::from(channel)].set_sys_clk_frequency(f_sys_clk).map(|_| ())
|
self.dds[usize::from(channel)].set_sys_clk_frequency(f_sys_clk).map(|_| ())
|
||||||
}
|
}
|
||||||
|
@ -320,8 +330,7 @@ where
|
||||||
}
|
}
|
||||||
self.multi_dds.set_sys_clk_frequency(reported_f_sys_clk)?;
|
self.multi_dds.set_sys_clk_frequency(reported_f_sys_clk)?;
|
||||||
self.multi_dds.set_single_tone_profile(profile, frequency, phase, amplitude)?;
|
self.multi_dds.set_single_tone_profile(profile, frequency, phase, amplitude)?;
|
||||||
self.invoke_io_update()?;
|
self.invoke_io_update()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a pulse for io_update bit in configuration register
|
// Generate a pulse for io_update bit in configuration register
|
||||||
|
|
Loading…
Reference in New Issue