forked from M-Labs/humpback-dds
dds: closure param for ram set
This commit is contained in:
parent
25f8363e54
commit
883e821794
135
src/dds.rs
135
src/dds.rs
|
@ -64,7 +64,7 @@ construct_bitmask!(DDSCFRMask; u32;
|
||||||
const WRITE_MASK :u8 = 0x00;
|
const WRITE_MASK :u8 = 0x00;
|
||||||
const READ_MASK :u8 = 0x80;
|
const READ_MASK :u8 = 0x80;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum RAMDestination {
|
pub enum RAMDestination {
|
||||||
Frequency = 0,
|
Frequency = 0,
|
||||||
Phase = 1,
|
Phase = 1,
|
||||||
|
@ -355,14 +355,9 @@ where
|
||||||
assert!(phase_offset >= 0.0 && phase_offset < 360.0);
|
assert!(phase_offset >= 0.0 && phase_offset < 360.0);
|
||||||
assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0);
|
assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0);
|
||||||
|
|
||||||
let resolutions :[u64; 3] = [1 << 32, 1 << 16, 1 << 14];
|
let ftw = self.frequency_to_ftw(f_out);
|
||||||
let ftw = ((resolutions[0] as f64) * f_out / self.f_sys_clk) as u32;
|
let pow = self.degree_to_pow(phase_offset);
|
||||||
let pow = ((resolutions[1] as f64) * phase_offset / 360.0) as u16;
|
let asf = self.amplitude_to_asf(amp_scale_factor);
|
||||||
let asf :u16 = if amp_scale_factor == 1.0 {
|
|
||||||
0x3FFF
|
|
||||||
} else {
|
|
||||||
((resolutions[2] as f64) * amp_scale_factor) as u16
|
|
||||||
};
|
|
||||||
|
|
||||||
// Setup configuration registers before writing single tone register
|
// Setup configuration registers before writing single tone register
|
||||||
self.enable_single_tone_configuration()?;
|
self.enable_single_tone_configuration()?;
|
||||||
|
@ -390,9 +385,7 @@ where
|
||||||
// Setup configuration registers before writing single tone register
|
// Setup configuration registers before writing single tone register
|
||||||
self.enable_single_tone_configuration()?;
|
self.enable_single_tone_configuration()?;
|
||||||
|
|
||||||
// Calculate frequency tuning work (FTW)
|
let ftw = self.frequency_to_ftw(f_out);
|
||||||
let f_res: u64 = 1 << 32;
|
|
||||||
let ftw = ((f_res as f64) * f_out / self.f_sys_clk) as u32;
|
|
||||||
|
|
||||||
// Read existing amplitude/phase data
|
// Read existing amplitude/phase data
|
||||||
let mut register: [u8; 8] = [0; 8];
|
let mut register: [u8; 8] = [0; 8];
|
||||||
|
@ -418,9 +411,7 @@ where
|
||||||
// Setup configuration registers before writing single tone register
|
// Setup configuration registers before writing single tone register
|
||||||
self.enable_single_tone_configuration()?;
|
self.enable_single_tone_configuration()?;
|
||||||
|
|
||||||
// Calculate phase offset work (POW)
|
let pow = self.degree_to_pow(phase_offset);
|
||||||
let phase_res: u64 = 1 << 16;
|
|
||||||
let pow = ((phase_res as f64) * phase_offset / 360.0) as u16;
|
|
||||||
|
|
||||||
// Read existing amplitude/frequency data
|
// Read existing amplitude/frequency data
|
||||||
let mut register: [u8; 8] = [0; 8];
|
let mut register: [u8; 8] = [0; 8];
|
||||||
|
@ -445,12 +436,7 @@ where
|
||||||
self.enable_single_tone_configuration()?;
|
self.enable_single_tone_configuration()?;
|
||||||
|
|
||||||
// Calculate amplitude_scale_factor (ASF)
|
// Calculate amplitude_scale_factor (ASF)
|
||||||
let amp_res: u64 = 1 << 14;
|
let asf = self.amplitude_to_asf(amp_scale_factor);
|
||||||
let asf :u16 = if amp_scale_factor == 1.0 {
|
|
||||||
0x3FFF
|
|
||||||
} else {
|
|
||||||
((amp_res as f64) * amp_scale_factor) as u16
|
|
||||||
};
|
|
||||||
|
|
||||||
// Read existing frequency/phase data
|
// Read existing frequency/phase data
|
||||||
let mut register: [u8; 8] = [0; 8];
|
let mut register: [u8; 8] = [0; 8];
|
||||||
|
@ -496,16 +482,91 @@ where
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a RAM mode profile, but with RAM data generated by a closure
|
||||||
|
*/
|
||||||
|
pub fn set_ram_profile_with_closure<F>(&mut self, profile: u8, start_addr: u16,
|
||||||
|
ram_dst: RAMDestination, no_dwell_high: bool, zero_crossing: bool,
|
||||||
|
op_mode: RAMOperationMode, playback_rate: f64, f: F) -> Result<(), Error<E>>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> ArrayVec::<[f64; 2048]>
|
||||||
|
{
|
||||||
|
// Check the legality of the profile setup
|
||||||
|
assert!(profile < 7);
|
||||||
|
assert!(start_addr < 1024);
|
||||||
|
let mut vec = f();
|
||||||
|
if (ram_dst != RAMDestination::Polar && ((vec.len() as u16) + start_addr) < 1024) ||
|
||||||
|
((((vec.len()/2) as u16) + start_addr) < 1024) {
|
||||||
|
return Err(Error::DDSRAMError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Convert argument into bytes for RAM
|
||||||
|
let mut byte_vec: ArrayVec<[u8; 8192]> = ArrayVec::new();
|
||||||
|
match ram_dst {
|
||||||
|
RAMDestination::Frequency => {
|
||||||
|
for freq in vec.into_iter() {
|
||||||
|
let ftw = self.frequency_to_ftw(freq);
|
||||||
|
byte_vec.push(((ftw >> 24) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((ftw >> 16) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((ftw >> 8) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((ftw >> 0) & 0xFF) as u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RAMDestination::Phase => {
|
||||||
|
for deg in vec.into_iter() {
|
||||||
|
let pow = self.degree_to_pow(deg);
|
||||||
|
byte_vec.push(((pow >> 8) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((pow >> 0) & 0xFF) as u8);
|
||||||
|
byte_vec.push(0);
|
||||||
|
byte_vec.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RAMDestination::Amplitude => {
|
||||||
|
for amp in vec.into_iter() {
|
||||||
|
let asf = self.amplitude_to_asf(amp);
|
||||||
|
byte_vec.push(((asf >> 8) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((asf << 2) & 0xFC) as u8);
|
||||||
|
byte_vec.push(0);
|
||||||
|
byte_vec.push(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RAMDestination::Polar => {
|
||||||
|
// Alternate phase and amplitude
|
||||||
|
let mut phase = true;
|
||||||
|
for pol in vec.into_iter() {
|
||||||
|
if phase {
|
||||||
|
let pow = self.degree_to_pow(pol);
|
||||||
|
byte_vec.push(((pow >> 8) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((pow >> 0) & 0xFF) as u8);
|
||||||
|
phase = false;
|
||||||
|
} else {
|
||||||
|
let asf = self.amplitude_to_asf(pol);
|
||||||
|
byte_vec.push(((asf >> 8) & 0xFF) as u8);
|
||||||
|
byte_vec.push(((asf << 2) & 0xFC) as u8);
|
||||||
|
phase = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if phase {
|
||||||
|
return Err(Error::DDSRAMError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let data = byte_vec.as_slice();
|
||||||
|
self.set_ram_profile(profile, start_addr, start_addr + (((data.len()/4) - 1) as u16),
|
||||||
|
ram_dst, no_dwell_high, zero_crossing, op_mode, playback_rate, data)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure a RAM mode profile
|
* Configure a RAM mode profile
|
||||||
*
|
* TODO: Possibly remove redundant end_addr parameter.
|
||||||
|
* This can be inferred by start_addr and data size.
|
||||||
*/
|
*/
|
||||||
pub fn set_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
pub fn set_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
||||||
ram_dst: RAMDestination, no_dwell_high: bool, zero_crossing: bool,
|
ram_dst: RAMDestination, no_dwell_high: bool, zero_crossing: bool,
|
||||||
op_mode: RAMOperationMode, playback_rate: f64, data: &[u8]
|
op_mode: RAMOperationMode, playback_rate: f64, data: &[u8]
|
||||||
) -> Result<(), Error<E>> {
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
// Check the legality of this setup
|
// Check the legality of the profile setup
|
||||||
assert!(profile < 7);
|
assert!(profile < 7);
|
||||||
assert!(end_addr >= start_addr);
|
assert!(end_addr >= start_addr);
|
||||||
assert!(end_addr < 1024);
|
assert!(end_addr < 1024);
|
||||||
|
@ -513,8 +574,8 @@ 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;
|
||||||
if (step_rate == 0 || step_rate > 0xFFFF) {
|
if step_rate == 0 || step_rate > 0xFFFF {
|
||||||
return Err(Error::ParameterError);
|
return Err(Error::DDSRAMError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before setting up RAM, disable RAM_ENABLE
|
// Before setting up RAM, disable RAM_ENABLE
|
||||||
|
@ -533,7 +594,7 @@ where
|
||||||
])?;
|
])?;
|
||||||
|
|
||||||
// Temporarily disable RAM mode while accessing into RAM
|
// Temporarily disable RAM mode while accessing into RAM
|
||||||
self.disable_ram_configuration();
|
self.disable_ram_configuration()?;
|
||||||
self.write_ram(data)?;
|
self.write_ram(data)?;
|
||||||
|
|
||||||
// Properly configure start_addr and end_addr
|
// Properly configure start_addr and end_addr
|
||||||
|
@ -541,8 +602,26 @@ where
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to write data in RAM
|
// Calculate ftw (frequency tuning word)
|
||||||
// Need address range for data size check
|
fn frequency_to_ftw(&mut self, f_out: f64) -> u32 {
|
||||||
|
let f_res: u64 = 1 << 32;
|
||||||
|
((f_res as f64) * f_out / self.f_sys_clk) as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate pow (Phase Offset Word)
|
||||||
|
fn degree_to_pow(&mut self, phase_offset: f64) -> u16 {
|
||||||
|
// Calculate phase offset word (POW)
|
||||||
|
let phase_res: u64 = 1 << 16;
|
||||||
|
((phase_res as f64) * phase_offset / 360.0) as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate asf (Amplitude Scale Factor)
|
||||||
|
fn amplitude_to_asf(&mut self, amplitude: f64) -> u16 {
|
||||||
|
let amp_res: u64 = 0x3FFF;
|
||||||
|
((amp_res as f64) * amplitude) as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data in RAM
|
||||||
fn write_ram(&mut self, data: &[u8]) -> Result<(), Error<E>> {
|
fn write_ram(&mut self, data: &[u8]) -> Result<(), Error<E>> {
|
||||||
let mut vec: ArrayVec<[u8; 8192]> = ArrayVec::new();
|
let mut vec: ArrayVec<[u8; 8192]> = ArrayVec::new();
|
||||||
vec.try_push(0x16)
|
vec.try_push(0x16)
|
||||||
|
|
Loading…
Reference in New Issue