Compare commits
No commits in common. "8dbf62167971a56b71d777f824be76afe689687b" and "d78f85721f205abb2f4557ca56cdaf4c2f2f4fe2" have entirely different histories.
8dbf621679
...
d78f85721f
|
@ -130,8 +130,8 @@ fn main() -> ! {
|
|||
let ccdr = rcc
|
||||
.sys_ck(200.mhz())
|
||||
.hclk(200.mhz())
|
||||
.pll1_r_ck(100.mhz()) // for TRACECK
|
||||
.pll1_q_ck(48.mhz()) // for SPI
|
||||
.pll1_r_ck(100.mhz()) // for TRACECK
|
||||
.pll1_q_ck(48.mhz())
|
||||
.freeze(vos, &dp.SYSCFG);
|
||||
|
||||
// Get the delay provider.
|
||||
|
|
|
@ -78,45 +78,6 @@ where
|
|||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for Attenuators.
|
||||
* Return the number of test failed.
|
||||
*/
|
||||
pub fn test(&mut self) -> Result<u32, Error<E>> {
|
||||
// Test attenuators by getting back the attenuation
|
||||
let mut error_count = 0;
|
||||
// Convert cached SPI data into attenuation floats
|
||||
let att_floats :[f32; 4] = [
|
||||
((self.data[3] ^ 0xFC) as f32) / 8.0,
|
||||
((self.data[2] ^ 0xFC) as f32) / 8.0,
|
||||
((self.data[1] ^ 0xFC) as f32) / 8.0,
|
||||
((self.data[0] ^ 0xFC) as f32) / 8.0,
|
||||
];
|
||||
// Set the attenuation to an arbitrary value, then read the attenuation
|
||||
self.set_attenuation([
|
||||
3.5, 9.5, 20.0, 28.5
|
||||
])?;
|
||||
match self.get_attenuation() {
|
||||
Ok(arr) => {
|
||||
if arr[0] != 3.5 {
|
||||
error_count += 1;
|
||||
}
|
||||
if arr[1] != 9.5 {
|
||||
error_count += 1;
|
||||
}
|
||||
if arr[2] != 20.0 {
|
||||
error_count += 1;
|
||||
}
|
||||
if arr[3] != 28.5 {
|
||||
error_count += 1;
|
||||
}
|
||||
},
|
||||
Err(_) => return Err(Error::AttenuatorError),
|
||||
};
|
||||
self.set_attenuation(att_floats)?;
|
||||
Ok(error_count)
|
||||
}
|
||||
}
|
||||
|
||||
impl<SPI, E> Transfer<u8> for Attenuator<SPI>
|
||||
|
|
|
@ -97,19 +97,7 @@ where
|
|||
pub fn get_all_status(&mut self) -> Result<u32, Error<E>> {
|
||||
return self.set_all_configurations();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method for Configuration Register.
|
||||
* Return the number of test failed.
|
||||
*/
|
||||
pub fn test(&mut self) -> Result<u32, Error<E>> {
|
||||
// Test configuration register by getting PROTO_KEY.
|
||||
match self.get_status(StatusMask::PROTO_KEY) {
|
||||
Ok(8) => Ok(0),
|
||||
Ok(_) => Ok(1),
|
||||
Err(_) => Err(Error::ConfigRegisterError),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<SPI, E> Transfer<u8> for ConfigRegister<SPI>
|
||||
|
|
120
src/dds.rs
120
src/dds.rs
|
@ -144,16 +144,33 @@ where
|
|||
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!");
|
||||
return Err(Error::DDSCLKError);
|
||||
panic!("Invalid divider value for PLL!");
|
||||
}
|
||||
let vco = self.get_VCO_no(f_sys_clk, divider as u8)?;
|
||||
|
||||
// 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.into()),
|
||||
(DDSCFRMask::VCO_SEL, vco),
|
||||
// Reset PLL lock before re-enabling it
|
||||
(DDSCFRMask::PFD_RESET, 1),
|
||||
])?;
|
||||
|
@ -165,76 +182,9 @@ where
|
|||
}
|
||||
|
||||
// Change external clock source (ref_clk)
|
||||
pub fn set_ref_clk_frequency(&mut self, f_ref_clk: u64) -> Result<(), Error<E>> {
|
||||
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
|
||||
let mut configuration_queries = [
|
||||
// Acquire PLL status
|
||||
(DDSCFRMask::PLL_ENABLE, 0),
|
||||
// Acquire N-divider, to adjust VCO if necessary
|
||||
(DDSCFRMask::N, 0),
|
||||
// Acquire REF_CLK divider bypass
|
||||
(DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0)
|
||||
];
|
||||
|
||||
self.get_configurations(&mut configuration_queries)?;
|
||||
if configuration_queries[0].1 == 1 {
|
||||
// Recalculate sys_clk
|
||||
let divider :u64 = configuration_queries[1].1.into();
|
||||
let f_sys_clk = self.f_ref_clk * divider;
|
||||
// Adjust VCO
|
||||
match self.get_VCO_no(f_sys_clk, divider as u8) {
|
||||
Ok(vco_no) => {
|
||||
self.set_configurations(&mut [
|
||||
// Update VCO selection
|
||||
(DDSCFRMask::VCO_SEL, vco_no.into()),
|
||||
// Reset PLL lock before re-enabling it
|
||||
(DDSCFRMask::PFD_RESET, 1),
|
||||
])?;
|
||||
self.set_configurations(&mut [
|
||||
(DDSCFRMask::PFD_RESET, 0),
|
||||
])?;
|
||||
// Update f_sys_clk from recalculation
|
||||
self.f_sys_clk = f_sys_clk;
|
||||
Ok(())
|
||||
},
|
||||
Err(_) => {
|
||||
// Forcibly turn off PLL, enable default clk tree (divide by 2)
|
||||
self.enable_divided_ref_clk()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if configuration_queries[2].1 == 0 {
|
||||
self.f_sys_clk = self.f_ref_clk / 2;
|
||||
Ok(())
|
||||
}
|
||||
else {
|
||||
self.f_sys_clk = self.f_ref_clk;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_VCO_no(&mut self, f_sys_clk: u64, divider: u8) -> Result<u8, Error<E>> {
|
||||
// Select a VCO
|
||||
if divider == 1 {
|
||||
Ok(6) // Bypass PLL if no frequency division needed
|
||||
} else if f_sys_clk > 1_150_000_000 {
|
||||
Err(Error::DDSCLKError)
|
||||
} else if f_sys_clk > 820_000_000 {
|
||||
Ok(5)
|
||||
} else if f_sys_clk > 700_000_000 {
|
||||
Ok(4)
|
||||
} else if f_sys_clk > 600_000_000 {
|
||||
Ok(3)
|
||||
} else if f_sys_clk > 500_000_000 {
|
||||
Ok(2)
|
||||
} else if f_sys_clk > 420_000_000 {
|
||||
Ok(1)
|
||||
} else if f_sys_clk > 370_000_000 {
|
||||
Ok(0)
|
||||
} else {
|
||||
Ok(7) // Bypass PLL if f_sys_clk is too low
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -346,29 +296,7 @@ where
|
|||
((ftw >> 8 ) & 0xFF) as u8,
|
||||
((ftw >> 0 ) & 0xFF) as u8,
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Test method for DDS.
|
||||
* Return the number of test failed.
|
||||
*/
|
||||
pub fn test(&mut self) -> Result<u32, Error<E>> {
|
||||
// Test configuration register by getting SDIO_IN_ONLY and LSB_FIRST.
|
||||
let mut error_count = 0;
|
||||
let mut config_checks = [
|
||||
(DDSCFRMask::SDIO_IN_ONLY, 0),
|
||||
(DDSCFRMask::LSB_FIRST, 0)
|
||||
];
|
||||
self.get_configurations(&mut config_checks)?;
|
||||
if config_checks[0].1 == 0 {
|
||||
error_count += 1;
|
||||
}
|
||||
if config_checks[1].1 == 1 {
|
||||
error_count += 1;
|
||||
}
|
||||
Ok(error_count)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
57
src/lib.rs
57
src/lib.rs
|
@ -26,8 +26,6 @@ use crate::cpld::DoOnGetRefMutData;
|
|||
|
||||
pub mod config_register;
|
||||
use crate::config_register::ConfigRegister;
|
||||
use crate::config_register::CFGMask;
|
||||
use crate::config_register::StatusMask;
|
||||
|
||||
pub mod attenuator;
|
||||
use crate::attenuator::Attenuator;
|
||||
|
@ -48,8 +46,6 @@ pub enum Error<E> {
|
|||
AttenuatorError,
|
||||
IOUpdateError,
|
||||
DDSError,
|
||||
ConfigRegisterError,
|
||||
DDSCLKError,
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -82,59 +78,6 @@ where
|
|||
],
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset method. To be invoked by initialization and manual reset.
|
||||
* Only Urukul struct provides reset method.
|
||||
* DDS reset is controlled by Urukul (RST).
|
||||
* Attenuators only have shift register reset, which does not affect its data
|
||||
* CPLD only has a "all-zero" default state.
|
||||
*/
|
||||
pub fn reset(&mut self) -> Result<(), Error<E>> {
|
||||
// Reset DDS and attenuators
|
||||
self.config_register.set_configurations(&mut [
|
||||
(CFGMask::RST, 1),
|
||||
(CFGMask::IO_RST, 1),
|
||||
(CFGMask::IO_UPDATE, 0)
|
||||
])?;
|
||||
// Set 0 to all fields on configuration register.
|
||||
self.config_register.set_configurations(&mut [
|
||||
(CFGMask::RF_SW, 0),
|
||||
(CFGMask::LED, 0),
|
||||
(CFGMask::PROFILE, 0),
|
||||
(CFGMask::IO_UPDATE, 0),
|
||||
(CFGMask::MASK_NU, 0),
|
||||
(CFGMask::CLK_SEL0, 0),
|
||||
(CFGMask::SYNC_SEL, 0),
|
||||
(CFGMask::RST, 0),
|
||||
(CFGMask::IO_RST, 0),
|
||||
(CFGMask::CLK_SEL1, 0),
|
||||
(CFGMask::DIV, 0),
|
||||
])?;
|
||||
// Init all DDS chips. Configure SDIO as input only.
|
||||
for chip_no in 0..4 {
|
||||
self.dds[chip_no].init()?;
|
||||
}
|
||||
|
||||
// Clock tree reset. CPLD divides clock frequency by 4 by default.
|
||||
for chip_no in 0..4 {
|
||||
self.dds[chip_no].set_ref_clk_frequency(25_000_000)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
* Test method fo Urukul.
|
||||
* Return the number of test failed.
|
||||
*/
|
||||
pub fn test(&mut self) -> Result<u32, Error<E>> {
|
||||
let mut count = self.config_register.test()?;
|
||||
count += self.attenuator.test()?;
|
||||
for chip_no in 0..4 {
|
||||
count += self.dds[chip_no].test()?;
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
}
|
||||
|
||||
// /*
|
||||
|
|
26
src/scpi.rs
26
src/scpi.rs
|
@ -28,8 +28,6 @@ use scpi::{
|
|||
scpi_tree,
|
||||
};
|
||||
|
||||
use embedded_hal::blocking::spi::Transfer;
|
||||
|
||||
use crate::Urukul;
|
||||
|
||||
// pub struct MyDevice;
|
||||
|
@ -52,33 +50,13 @@ impl Command for HelloWorldCommand {
|
|||
* Implement "Device" trait from SCPI
|
||||
* TODO: Implement mandatory commands
|
||||
*/
|
||||
impl<SPI, E> Device for Urukul<SPI>
|
||||
where
|
||||
SPI: Transfer<u8, Error = E>
|
||||
{
|
||||
impl<SPI> Device for Urukul<SPI> {
|
||||
fn cls(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rst(&mut self) -> Result<()> {
|
||||
match self.reset() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(Error::new(
|
||||
ErrorCode::HardwareError
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn tst(&mut self) -> Result<()> {
|
||||
match self.test() {
|
||||
Ok(0) => Ok(()),
|
||||
Ok(_) => Err(Error::new(
|
||||
ErrorCode::SelfTestFailed
|
||||
)),
|
||||
Err(_) => Err(Error::new(
|
||||
ErrorCode::SelfTestFailed
|
||||
)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue