From 649b5b498b5c4e95fce9aed3ef40d0ad63572de2 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 26 Aug 2020 17:39:33 +0800 Subject: [PATCH] dds: add single tone control --- src/dds.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/dds.rs b/src/dds.rs index 5a39308..df3b618 100644 --- a/src/dds.rs +++ b/src/dds.rs @@ -66,6 +66,7 @@ const READ_MASK :u8 = 0x80; pub struct DDS { spi: SPI, f_ref_clk: u64, + f_sys_clk: u64, } impl DDS @@ -76,6 +77,7 @@ where DDS { spi, f_ref_clk, + f_sys_clk: f_ref_clk, } } } @@ -119,7 +121,9 @@ where (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0), // Ensure divider is not reset (DDSCFRMask::REFCLK_IN_DIV_RESETB, 1), - ]) + ])?; + self.f_sys_clk = self.f_ref_clk / 2; + Ok(()) } pub fn enable_normal_ref_clk(&mut self) -> Result<(), Error> { @@ -130,7 +134,9 @@ where (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 1), // Reset does not matter (DDSCFRMask::REFCLK_IN_DIV_RESETB, 1), - ]) + ])?; + self.f_sys_clk = self.f_ref_clk; + Ok(()) } pub fn enable_pll(&mut self, f_sys_clk: u64) -> Result<(), Error> { @@ -170,16 +176,19 @@ where ])?; self.set_configurations(&mut [ (DDSCFRMask::PFD_RESET, 0), - ]) + ])?; + self.f_sys_clk = self.f_ref_clk * divider; + Ok(()) } // Change external clock source (ref_clk) pub fn set_ref_clk_frequency(&mut self, f_ref_clk: u64) { self.f_ref_clk = f_ref_clk; + // TODO: Examine clock tree and update f_sys_clk } /* - * Impleement configurations registers I/O through bitmasks + * Implement configurations registers I/O through bitmasks * * Get all (cfr1, cfr2, cfr3) contents */ @@ -246,6 +255,41 @@ where self.set_all_configurations(data_array.clone()) } + /* + * Set a single tone profile + * Phase: Expressed in positive degree + * Frequency: Must be integer + * Amplitude: In a scale from 0 to 1, taking float + */ + pub fn set_single_tone_profile(&mut self, profile: u8, f_out: u64, phase_offset: f64, amp_scale_factor: f64) -> Result<(), Error> { + + assert!(profile < 8); + assert!(phase_offset >= 0.0 && phase_offset < 360.0); + assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0); + + let resolutions :[u64; 3] = [1 << 32, 1 << 16, 1 << 14]; + let ftw = (resolutions[0] * f_out / self.f_sys_clk) as u32; + let pow = ((resolutions[1] as f64) * phase_offset / 360.0) as u16; + let asf = ((resolutions[2] as f64) * amp_scale_factor) as u16; + // Setup configuration registers before writing single tone register + self.set_configurations(&mut [ + (DDSCFRMask::RAM_ENABLE, 0), + (DDSCFRMask::DIGITAL_RAMP_ENABLE, 0), + (DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0), + ])?; + // Transfer single tone profile data + self.write_register(0x0E + profile, &mut [ + ((asf >> 8 ) & 0xFF) as u8, + ((asf >> 0 ) & 0xFF) as u8, + ((pow >> 8 ) & 0xFF) as u8, + ((pow >> 0 ) & 0xFF) as u8, + ((ftw >> 24) & 0xFF) as u8, + ((ftw >> 16) & 0xFF) as u8, + ((ftw >> 8 ) & 0xFF) as u8, + ((ftw >> 0 ) & 0xFF) as u8, + ]) + } + } macro_rules! impl_register_io {