dds: add clock control

This commit is contained in:
occheung 2020-08-26 16:49:37 +08:00
parent 38b1c7528c
commit 1d3ced0d16
6 changed files with 92 additions and 60 deletions

View File

@ -1,5 +1,4 @@
use embedded_hal::blocking::spi::Transfer; use embedded_hal::blocking::spi::Transfer;
use cortex_m::asm::nop;
use cortex_m_semihosting::hprintln; use cortex_m_semihosting::hprintln;
use core::assert; use core::assert;

View File

@ -1,5 +1,3 @@
use core::mem::size_of;
/* /*
* Macro builder for bit masks * Macro builder for bit masks
* $collection: Name for the bit mask collection * $collection: Name for the bit mask collection

View File

@ -78,7 +78,7 @@ where
* Return selected configuration field * Return selected configuration field
*/ */
pub fn get_configuration(&mut self, config_type: CFGMask) -> u8 { 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
} }
/* /*

View File

@ -65,15 +65,17 @@ const READ_MASK :u8 = 0x80;
pub struct DDS<SPI> { pub struct DDS<SPI> {
spi: SPI, spi: SPI,
f_ref_clk: u64,
} }
impl<SPI, E> DDS<SPI> impl<SPI, E> DDS<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>
{ {
pub fn new(spi: SPI) -> Self { pub fn new(spi: SPI, f_ref_clk: u64) -> Self {
DDS { DDS {
spi spi,
f_ref_clk,
} }
} }
} }
@ -89,13 +91,14 @@ where
} }
} }
/*
* Implement init
*/
impl<SPI, E> DDS<SPI> impl<SPI, E> DDS<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>
{ {
/*
* Implement init: Set SDIO to be input only, using LSB first
*/
pub fn init(&mut self) -> Result<(), Error<E>> { pub fn init(&mut self) -> Result<(), Error<E>> {
match self.write_register(0x00, &mut [ match self.write_register(0x00, &mut [
0x00, 0x00, 0x00, 0x02 0x00, 0x00, 0x00, 0x02
@ -104,17 +107,81 @@ where
Err(e) => Err(e), Err(e) => Err(e),
} }
} }
/*
* Implement clock control
*/
pub fn enable_divided_ref_clk(&mut self) -> Result<(), Error<E>> {
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<E>> {
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<E>> {
// 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 * Impleement configurations registers I/O through bitmasks
*/ *
impl<SPI, E> DDS<SPI> * Get all (cfr1, cfr2, cfr3) contents
where
SPI: Transfer<u8, Error = E>
{
/*
* Return (cfr1, cfr2, cfr3) contents
*/ */
fn get_all_configurations(&mut self) -> Result<[u32; 3], Error<E>> { fn get_all_configurations(&mut self) -> Result<[u32; 3], Error<E>> {
let mut cfr_reg = [0; 12]; let mut cfr_reg = [0; 12];
@ -164,9 +231,8 @@ where
*/ */
pub fn set_configurations(&mut self, mask_pairs: &mut[(DDSCFRMask, u32)]) -> Result<(), Error<E>> { pub fn set_configurations(&mut self, mask_pairs: &mut[(DDSCFRMask, u32)]) -> Result<(), Error<E>> {
let mut data_array = self.get_all_configurations()?; let mut data_array = self.get_all_configurations()?;
hprintln!("Initial array {:#X?}", data_array).unwrap();
for index in 0..mask_pairs.len() { 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 { if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST || mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY {
continue; continue;
} }
@ -177,7 +243,6 @@ where
_ => panic!("Invalid DDSCFRMask!"), _ => panic!("Invalid DDSCFRMask!"),
}; };
} }
hprintln!("Modified array {:#X?}", data_array).unwrap();
self.set_all_configurations(data_array.clone()) self.set_all_configurations(data_array.clone())
} }

View File

@ -6,10 +6,8 @@ use embedded_hal::{
}; };
use core::cell; use core::cell;
use core::mem::size_of;
use cortex_m; use cortex_m;
use cortex_m::asm::nop;
use cortex_m_semihosting::hprintln; use cortex_m_semihosting::hprintln;
#[macro_use] #[macro_use]

View File

@ -10,13 +10,9 @@ use stm32h7xx_hal::hal::digital::v2::{
use stm32h7xx_hal::{pac, prelude::*, spi}; use stm32h7xx_hal::{pac, prelude::*, spi};
use cortex_m; use cortex_m;
use cortex_m::asm::nop;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln; use cortex_m_semihosting::hprintln;
use core::ptr;
use nb::block;
use firmware; use firmware;
use firmware::{ use firmware::{
CPLD, CPLD,
@ -102,7 +98,7 @@ fn main() -> ! {
let mut config = ConfigRegister::new(parts.spi1); let mut config = ConfigRegister::new(parts.spi1);
let mut att = Attenuator::new(parts.spi2); 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 // Reset all DDS, set CLK_SEL to 0
config.set_configurations(&mut [ config.set_configurations(&mut [
@ -115,21 +111,9 @@ fn main() -> ! {
(CFGMask::IO_RST, 0), (CFGMask::IO_RST, 0),
(CFGMask::RST, 0), (CFGMask::RST, 0),
(CFGMask::RF_SW, 13), (CFGMask::RF_SW, 13),
(CFGMask::DIV, 2) (CFGMask::DIV, 3)
]).unwrap(); ]).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.init().unwrap();
dds0.set_configurations(&mut [ dds0.set_configurations(&mut [
@ -137,30 +121,17 @@ fn main() -> ! {
(DDSCFRMask::READ_EFFECTIVE_FTW, 1), (DDSCFRMask::READ_EFFECTIVE_FTW, 1),
(DDSCFRMask::DIGITAL_RAMP_ENABLE, 0), (DDSCFRMask::DIGITAL_RAMP_ENABLE, 0),
(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1), (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(); ]).unwrap();
hprintln!("{:#X?}", dds0.read_register(0x02, &mut[ dds0.enable_pll(1_150_000_000).unwrap();
0x00, 0x00, 0x00, 0x00
]).unwrap()).unwrap();
dds0.set_configurations(&mut [
(DDSCFRMask::PFD_RESET, 0),
]).unwrap();
hprintln!("{:#X?}", dds0.read_register(0x02, &mut[ hprintln!("{:#X?}", dds0.read_register(0x02, &mut[
0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00
]).unwrap()).unwrap(); ]).unwrap()).unwrap();
// Calculate FTW // Calculate FTW
let f_out = 8_008_135; let f_out = 10_000_000;
let f_sclk = 100_000_000 / 2 * 20; let f_sclk = 1_150_000_000;
let resolution :u64 = 1 << 32; let resolution :u64 = 1 << 32;
let ftw = (resolution * f_out / f_sclk) as u32; let ftw = (resolution * f_out / f_sclk) as u32;
@ -177,6 +148,7 @@ fn main() -> ! {
profile[7] = ((ftw >> 0 ) & 0xFF) as u8; profile[7] = ((ftw >> 0 ) & 0xFF) as u8;
dds0.write_register(0x0E, &mut profile).unwrap(); dds0.write_register(0x0E, &mut profile).unwrap();
hprintln!("{:#X?}", dds0.read_register(0x0E, &mut profile).unwrap()).unwrap();
// Attenuator // Attenuator
att.set_attenuation([ att.set_attenuation([