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 heapless::Vec;
|
||||
use heapless::consts::*;
|
||||
use log::{ trace, debug, warn };
|
||||
|
||||
/*
|
||||
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
|
||||
@ -632,6 +633,77 @@ where
|
||||
|
||||
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Phase,
|
||||
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
|
||||
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 {
|
||||
|
@ -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
|
||||
@ -90,17 +90,17 @@ where
|
||||
])?;
|
||||
// Set 0 to all fields on configuration register.
|
||||
self.config_register.set_configurations(&mut [
|
||||
(CFGMask::RF_SW, 0),
|
||||
(CFGMask::LED, 0),
|
||||
(CFGMask::PROFILE, 0),
|
||||
(CFGMask::IO_UPDATE, 0),
|
||||
(CFGMask::MASK_NU, 0),
|
||||
(CFGMask::RF_SW, 0),
|
||||
(CFGMask::LED, 0),
|
||||
(CFGMask::PROFILE, 0),
|
||||
(CFGMask::IO_UPDATE, 0),
|
||||
(CFGMask::MASK_NU, 0),
|
||||
(CFGMask::CLK_SEL0, 0),
|
||||
(CFGMask::SYNC_SEL, 0),
|
||||
(CFGMask::RST, 0),
|
||||
(CFGMask::IO_RST, 0),
|
||||
(CFGMask::RST, 0),
|
||||
(CFGMask::IO_RST, 0),
|
||||
(CFGMask::CLK_SEL1, 0),
|
||||
(CFGMask::DIV, 0),
|
||||
(CFGMask::DIV, 0),
|
||||
])?;
|
||||
// Init all DDS chips. Configure SDIO as input only.
|
||||
for chip_no in 0..4 {
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user