From 1d3ced0d16990e773be6ddb36bb7176cc76d6bfc Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 26 Aug 2020 16:49:37 +0800 Subject: [PATCH] dds: add clock control --- src/attenuator.rs | 1 - src/bitmask_macro.rs | 2 - src/config_register.rs | 2 +- src/dds.rs | 105 +++++++++++++++++++++++++++++++++-------- src/lib.rs | 2 - src/main.rs | 40 +++------------- 6 files changed, 92 insertions(+), 60 deletions(-) diff --git a/src/attenuator.rs b/src/attenuator.rs index 3b90235..8532501 100644 --- a/src/attenuator.rs +++ b/src/attenuator.rs @@ -1,5 +1,4 @@ use embedded_hal::blocking::spi::Transfer; -use cortex_m::asm::nop; use cortex_m_semihosting::hprintln; use core::assert; diff --git a/src/bitmask_macro.rs b/src/bitmask_macro.rs index a72dabc..9f45aee 100644 --- a/src/bitmask_macro.rs +++ b/src/bitmask_macro.rs @@ -1,5 +1,3 @@ -use core::mem::size_of; - /* * Macro builder for bit masks * $collection: Name for the bit mask collection diff --git a/src/config_register.rs b/src/config_register.rs index 0f056ad..a3ce61d 100644 --- a/src/config_register.rs +++ b/src/config_register.rs @@ -78,7 +78,7 @@ where * Return selected configuration field */ pub fn get_configuration(&mut self, config_type: CFGMask) -> u8 { - (config_type.get_filtered_content(self.data) as u8) + config_type.get_filtered_content(self.data) as u8 } /* diff --git a/src/dds.rs b/src/dds.rs index 70df3b1..5a39308 100644 --- a/src/dds.rs +++ b/src/dds.rs @@ -65,15 +65,17 @@ const READ_MASK :u8 = 0x80; pub struct DDS { spi: SPI, + f_ref_clk: u64, } impl DDS where SPI: Transfer { - pub fn new(spi: SPI) -> Self { + pub fn new(spi: SPI, f_ref_clk: u64) -> Self { DDS { - spi + spi, + f_ref_clk, } } } @@ -89,13 +91,14 @@ where } } -/* - * Implement init - */ - impl DDS - where + +impl DDS +where SPI: Transfer - { +{ + /* + * Implement init: Set SDIO to be input only, using LSB first + */ pub fn init(&mut self) -> Result<(), Error> { match self.write_register(0x00, &mut [ 0x00, 0x00, 0x00, 0x02 @@ -104,17 +107,81 @@ where Err(e) => Err(e), } } - } -/* - * Impleement configurations registers I/O through bitmasks - */ -impl DDS -where - SPI: Transfer -{ /* - * Return (cfr1, cfr2, cfr3) contents + * Implement clock control + */ + pub fn enable_divided_ref_clk(&mut self) -> Result<(), Error> { + self.set_configurations(&mut [ + // Disable PLL + (DDSCFRMask::PLL_ENABLE, 0), + // Take ref_clk source from divider + (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0), + // Ensure divider is not reset + (DDSCFRMask::REFCLK_IN_DIV_RESETB, 1), + ]) + } + + pub fn enable_normal_ref_clk(&mut self) -> Result<(), Error> { + self.set_configurations(&mut [ + // Disable PLL + (DDSCFRMask::PLL_ENABLE, 0), + // Take ref_clk source from divider bypass + (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 1), + // Reset does not matter + (DDSCFRMask::REFCLK_IN_DIV_RESETB, 1), + ]) + } + + pub fn enable_pll(&mut self, f_sys_clk: u64) -> Result<(), Error> { + // Get a divider + let divider = f_sys_clk / self.f_ref_clk; + // Reject extreme divider values. However, accept no frequency division + if ((divider > 127 || divider < 12) && divider != 1) { + panic!("Invalid divider value for PLL!"); + } + // Select a VCO + let vco = if divider == 1 { + 6 // Bypass PLL if no frequency division needed + } else if f_sys_clk > 1_150_000_000 { + panic!("Invalid divider value for PLL!") + } else if f_sys_clk > 820_000_000 { + 5 + } else if f_sys_clk > 700_000_000 { + 4 + } else if f_sys_clk > 600_000_000 { + 3 + } else if f_sys_clk > 500_000_000 { + 2 + } else if f_sys_clk > 420_000_000 { + 1 + } else if f_sys_clk > 370_000_000 { + 0 + } else { + 7 // Bypass PLL if f_sys_clk is too low + }; + self.set_configurations(&mut [ + // Enable PLL, set divider (valid or not) and VCO + (DDSCFRMask::PLL_ENABLE, 1), + (DDSCFRMask::N, divider as u32), + (DDSCFRMask::VCO_SEL, vco), + // Reset PLL lock before re-enabling it + (DDSCFRMask::PFD_RESET, 1), + ])?; + self.set_configurations(&mut [ + (DDSCFRMask::PFD_RESET, 0), + ]) + } + + // 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; + } + + /* + * Impleement configurations registers I/O through bitmasks + * + * Get all (cfr1, cfr2, cfr3) contents */ fn get_all_configurations(&mut self) -> Result<[u32; 3], Error> { let mut cfr_reg = [0; 12]; @@ -164,9 +231,8 @@ where */ pub fn set_configurations(&mut self, mask_pairs: &mut[(DDSCFRMask, u32)]) -> Result<(), Error> { let mut data_array = self.get_all_configurations()?; - hprintln!("Initial array {:#X?}", data_array).unwrap(); for index in 0..mask_pairs.len() { - // Reject any attempt to write LSB_FIRST and SBIO_INPUT_ONLY + // Reject any attempt to rewrite LSB_FIRST and SBIO_INPUT_ONLY if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST || mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY { continue; } @@ -177,7 +243,6 @@ where _ => panic!("Invalid DDSCFRMask!"), }; } - hprintln!("Modified array {:#X?}", data_array).unwrap(); self.set_all_configurations(data_array.clone()) } diff --git a/src/lib.rs b/src/lib.rs index a0b3fa4..be9ce27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,10 +6,8 @@ use embedded_hal::{ }; use core::cell; -use core::mem::size_of; use cortex_m; -use cortex_m::asm::nop; use cortex_m_semihosting::hprintln; #[macro_use] diff --git a/src/main.rs b/src/main.rs index 9241f0d..b9c338a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,13 +10,9 @@ use stm32h7xx_hal::hal::digital::v2::{ use stm32h7xx_hal::{pac, prelude::*, spi}; use cortex_m; -use cortex_m::asm::nop; use cortex_m_rt::entry; use cortex_m_semihosting::hprintln; -use core::ptr; -use nb::block; - use firmware; use firmware::{ CPLD, @@ -102,7 +98,7 @@ fn main() -> ! { let mut config = ConfigRegister::new(parts.spi1); let mut att = Attenuator::new(parts.spi2); - let mut dds0 = DDS::new(parts.spi4); + let mut dds0 = DDS::new(parts.spi4, 25_000_000); // Reset all DDS, set CLK_SEL to 0 config.set_configurations(&mut [ @@ -115,21 +111,9 @@ fn main() -> ! { (CFGMask::IO_RST, 0), (CFGMask::RST, 0), (CFGMask::RF_SW, 13), - (CFGMask::DIV, 2) + (CFGMask::DIV, 3) ]).unwrap(); - // dds0.write_register(0x00, &mut[ - // 0x00, 0x00, 0x00, 0x02 - // ]).unwrap(); - - // dds0.write_register(0x01, &mut[ - // 0x01, 0x01, 0x00, 0x20 - // ]).unwrap(); - - // dds0.write_register(0x02, &mut[ - // 0x05, 0x38, 0xC5, 0x28 - // ]).unwrap(); - dds0.init().unwrap(); dds0.set_configurations(&mut [ @@ -137,30 +121,17 @@ fn main() -> ! { (DDSCFRMask::READ_EFFECTIVE_FTW, 1), (DDSCFRMask::DIGITAL_RAMP_ENABLE, 0), (DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1), - (DDSCFRMask::N, 0x14), - (DDSCFRMask::PLL_ENABLE, 1), - (DDSCFRMask::PFD_RESET, 1), - (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 1), - (DDSCFRMask::I_CP, 7), - (DDSCFRMask::VCO_SEL, 5), - (DDSCFRMask::DRV0, 0), ]).unwrap(); - hprintln!("{:#X?}", dds0.read_register(0x02, &mut[ - 0x00, 0x00, 0x00, 0x00 - ]).unwrap()).unwrap(); - - dds0.set_configurations(&mut [ - (DDSCFRMask::PFD_RESET, 0), - ]).unwrap(); + dds0.enable_pll(1_150_000_000).unwrap(); hprintln!("{:#X?}", dds0.read_register(0x02, &mut[ 0x00, 0x00, 0x00, 0x00 ]).unwrap()).unwrap(); // Calculate FTW - let f_out = 8_008_135; - let f_sclk = 100_000_000 / 2 * 20; + let f_out = 10_000_000; + let f_sclk = 1_150_000_000; let resolution :u64 = 1 << 32; let ftw = (resolution * f_out / f_sclk) as u32; @@ -177,6 +148,7 @@ fn main() -> ! { profile[7] = ((ftw >> 0 ) & 0xFF) as u8; dds0.write_register(0x0E, &mut profile).unwrap(); + hprintln!("{:#X?}", dds0.read_register(0x0E, &mut profile).unwrap()).unwrap(); // Attenuator att.set_attenuation([