forked from M-Labs/humpback-dds
dds: add clock control
This commit is contained in:
parent
38b1c7528c
commit
1d3ced0d16
|
@ -1,5 +1,4 @@
|
|||
use embedded_hal::blocking::spi::Transfer;
|
||||
use cortex_m::asm::nop;
|
||||
use cortex_m_semihosting::hprintln;
|
||||
use core::assert;
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use core::mem::size_of;
|
||||
|
||||
/*
|
||||
* Macro builder for bit masks
|
||||
* $collection: Name for the bit mask collection
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
95
src/dds.rs
95
src/dds.rs
|
@ -65,15 +65,17 @@ const READ_MASK :u8 = 0x80;
|
|||
|
||||
pub struct DDS<SPI> {
|
||||
spi: SPI,
|
||||
f_ref_clk: u64,
|
||||
}
|
||||
|
||||
impl<SPI, E> DDS<SPI>
|
||||
where
|
||||
SPI: Transfer<u8, Error = E>
|
||||
{
|
||||
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<SPI, E> DDS<SPI>
|
||||
where
|
||||
SPI: Transfer<u8, Error = E>
|
||||
{
|
||||
/*
|
||||
* Implement init: Set SDIO to be input only, using LSB first
|
||||
*/
|
||||
pub fn init(&mut self) -> Result<(), Error<E>> {
|
||||
match self.write_register(0x00, &mut [
|
||||
0x00, 0x00, 0x00, 0x02
|
||||
|
@ -104,17 +107,81 @@ where
|
|||
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
|
||||
*/
|
||||
impl<SPI, E> DDS<SPI>
|
||||
where
|
||||
SPI: Transfer<u8, Error = E>
|
||||
{
|
||||
/*
|
||||
* Return (cfr1, cfr2, cfr3) contents
|
||||
*
|
||||
* Get all (cfr1, cfr2, cfr3) contents
|
||||
*/
|
||||
fn get_all_configurations(&mut self) -> Result<[u32; 3], Error<E>> {
|
||||
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>> {
|
||||
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())
|
||||
}
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
40
src/main.rs
40
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([
|
||||
|
|
Loading…
Reference in New Issue