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 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 {

View File

@ -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