dds: add frequency sweep

This commit is contained in:
occheung 2020-09-25 17:07:52 +08:00
parent 242e03a8bd
commit 0a3518573a
2 changed files with 96 additions and 14 deletions

View File

@ -4,6 +4,7 @@ use core::mem::size_of;
use core::convert::TryInto;
use heapless::Vec;
use heapless::consts::*;
use log::{ trace, debug, warn };
/*
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
@ -634,6 +635,77 @@ where
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))
}
/*
* Configure a RAM mode profile, w.r.t static vector (RAM_VEC)
*/
@ -650,6 +722,7 @@ where
// Calculate address step rate, and check legality
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 {
return Err(Error::DDSRAMError);
}
@ -729,9 +802,9 @@ where
// Setter function for 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) {
self.f_sys_clk = f_sys_clk;
}
// pub(crate) fn set_f_sys_clk(&mut self, f_sys_clk: f64) {
// self.f_sys_clk = f_sys_clk;
// }
// Getter function for f_sys_clk
pub fn get_f_sys_clk(&mut self) -> f64 {

View File

@ -7,7 +7,7 @@ use crate::config_register::ConfigRegister;
use crate::config_register::CFGMask;
use crate::config_register::StatusMask;
use crate::attenuator::Attenuator;
use crate::dds::DDS;
use crate::dds::{ DDS, RAMOperationMode };
/*
* Enum for structuring error
@ -278,6 +278,16 @@ where
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>> {
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_single_tone_profile(profile, frequency, phase, amplitude)?;
self.invoke_io_update()?;
Ok(())
self.invoke_io_update()
}
// Generate a pulse for io_update bit in configuration register