2020-08-12 15:31:06 +08:00
|
|
|
use embedded_hal::blocking::spi::Transfer;
|
|
|
|
use cortex_m_semihosting::hprintln;
|
|
|
|
use crate::Error;
|
2020-08-26 11:04:08 +08:00
|
|
|
use core::mem::size_of;
|
2020-08-12 15:31:06 +08:00
|
|
|
|
2020-08-26 13:18:50 +08:00
|
|
|
/*
|
|
|
|
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
|
|
|
|
*/
|
2020-08-26 11:04:08 +08:00
|
|
|
construct_bitmask!(DDSCFRMask; u32;
|
|
|
|
// CFR1 bitmasks
|
2020-08-13 17:17:21 +08:00
|
|
|
LSB_FIRST, 0, 1,
|
|
|
|
SDIO_IN_ONLY, 1, 1,
|
|
|
|
EXT_POWER_DOWN_CTRL, 3, 1,
|
|
|
|
AUX_DAC_POWER_DOWN, 4, 1,
|
|
|
|
REFCLK_IN_POWER_DOWN, 5, 1,
|
|
|
|
DAC_POWER_DOWN, 6, 1,
|
|
|
|
DIGITAL_POWER_DOWN, 7, 1,
|
|
|
|
SEL_AUTO_OSK, 8, 1,
|
|
|
|
OSK_ENABLE, 9, 1,
|
|
|
|
LOAD_ARR_IO_UPDATE, 10, 1,
|
|
|
|
CLEAR_PHASE_ACU, 11, 1,
|
|
|
|
CLEAR_DIGITAL_RAMP_ACU, 12, 1,
|
|
|
|
AUTOCLEAR_PHASE_ACU, 13, 1,
|
|
|
|
AUTOCLEAR_DIGITAL_RAMP_ACU, 14, 1,
|
|
|
|
LOAD_LRR_IO_UPDATE, 15, 1,
|
|
|
|
SEL_DDS_SIN_OUT, 16, 1,
|
|
|
|
PROFILE_CTRL, 17, 4,
|
|
|
|
INV_SINC_FILTER_ENABLE, 22, 1,
|
|
|
|
MANUAL_OSK_EXT_CTRL, 23, 1,
|
|
|
|
RAM_PLAYBACK_DST, 29, 2,
|
2020-08-26 11:04:08 +08:00
|
|
|
RAM_ENABLE, 31, 1,
|
2020-08-13 17:17:21 +08:00
|
|
|
|
2020-08-26 11:04:08 +08:00
|
|
|
// CFR2 bitmasks
|
|
|
|
FM_GAIN, 0 +32, 4,
|
|
|
|
PARALLEL_DATA_PORT_ENABLE, 4 +32, 1,
|
|
|
|
SYNC_TIM_VALIDATION_DISABLE, 5 +32, 1,
|
|
|
|
DATA_ASSEM_HOLD_LAST_VALUE, 6 +32, 1,
|
|
|
|
MATCHED_LATENCY_ENABLE, 7 +32, 1,
|
|
|
|
TXENABLE_INV, 9 +32, 1,
|
|
|
|
PDCLK_INV, 10 +32, 1,
|
|
|
|
PDCLK_ENABLE, 11 +32, 1,
|
|
|
|
IO_UPDATE_RATE_CTRL, 14 +32, 2,
|
|
|
|
READ_EFFECTIVE_FTW, 16 +32, 1,
|
|
|
|
DIGITAL_RAMP_NO_DWELL_LOW, 17 +32, 1,
|
|
|
|
DIGITAL_RAMP_NO_DWELL_HIGH, 18 +32, 1,
|
|
|
|
DIGITAL_RAMP_ENABLE, 19 +32, 1,
|
|
|
|
DIGITAL_RAMP_DEST, 20 +32, 2,
|
|
|
|
SYNC_CLK_ENABLE, 22 +32, 1,
|
|
|
|
INT_IO_UPDATE_ACTIVE, 23 +32, 1,
|
|
|
|
EN_AMP_SCALE_SINGLE_TONE_PRO, 24 +32, 1,
|
2020-08-14 14:14:14 +08:00
|
|
|
|
2020-08-26 11:04:08 +08:00
|
|
|
// CFR3 bitmasks
|
|
|
|
N, 1 +64, 7,
|
|
|
|
PLL_ENABLE, 8 +64, 1,
|
|
|
|
PFD_RESET, 10 +64, 1,
|
|
|
|
REFCLK_IN_DIV_RESETB, 14 +64, 1,
|
|
|
|
REFCLK_IN_DIV_BYPASS, 15 +64, 1,
|
|
|
|
I_CP, 19 +64, 3,
|
|
|
|
VCO_SEL, 24 +64, 3,
|
|
|
|
DRV0, 28 +64, 2
|
2020-08-17 12:15:11 +08:00
|
|
|
);
|
2020-08-14 14:14:14 +08:00
|
|
|
|
2020-08-17 11:45:42 +08:00
|
|
|
const WRITE_MASK :u8 = 0x00;
|
|
|
|
const READ_MASK :u8 = 0x80;
|
|
|
|
|
2020-08-12 15:31:06 +08:00
|
|
|
pub struct DDS<SPI> {
|
|
|
|
spi: SPI,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<SPI, E> DDS<SPI>
|
|
|
|
where
|
2020-08-17 11:45:42 +08:00
|
|
|
SPI: Transfer<u8, Error = E>
|
2020-08-12 15:31:06 +08:00
|
|
|
{
|
|
|
|
pub fn new(spi: SPI) -> Self {
|
|
|
|
DDS {
|
|
|
|
spi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-17 12:15:11 +08:00
|
|
|
impl<SPI, E> Transfer<u8> for DDS<SPI>
|
2020-08-12 15:31:06 +08:00
|
|
|
where
|
|
|
|
SPI: Transfer<u8, Error = E>
|
|
|
|
{
|
|
|
|
type Error = Error<E>;
|
|
|
|
|
|
|
|
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
|
|
|
self.spi.transfer(words).map_err(Error::SPI)
|
|
|
|
}
|
|
|
|
}
|
2020-08-17 11:45:42 +08:00
|
|
|
|
2020-08-26 13:18:50 +08:00
|
|
|
/*
|
|
|
|
* Implement init
|
|
|
|
*/
|
|
|
|
impl<SPI, E> DDS<SPI>
|
|
|
|
where
|
|
|
|
SPI: Transfer<u8, Error = E>
|
|
|
|
{
|
|
|
|
pub fn init(&mut self) -> Result<(), Error<E>> {
|
|
|
|
match self.write_register(0x00, &mut [
|
|
|
|
0x00, 0x00, 0x00, 0x02
|
|
|
|
]) {
|
|
|
|
Ok(_) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Impleement configurations registers I/O through bitmasks
|
|
|
|
*/
|
|
|
|
impl<SPI, E> DDS<SPI>
|
|
|
|
where
|
|
|
|
SPI: Transfer<u8, Error = E>
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Return (cfr1, cfr2, cfr3) contents
|
|
|
|
*/
|
|
|
|
fn get_all_configurations(&mut self) -> Result<[u32; 3], Error<E>> {
|
|
|
|
let mut cfr_reg = [0; 12];
|
|
|
|
self.read_register(0x00, &mut cfr_reg[0..4])?;
|
|
|
|
self.read_register(0x01, &mut cfr_reg[4..8])?;
|
|
|
|
self.read_register(0x02, &mut cfr_reg[8..12])?;
|
|
|
|
Ok([
|
|
|
|
(cfr_reg[0] as u32) << 24 | (cfr_reg[1] as u32) << 16 | (cfr_reg[2] as u32) << 8 | (cfr_reg[3] as u32),
|
|
|
|
(cfr_reg[4] as u32) << 24 | (cfr_reg[5] as u32) << 16 | (cfr_reg[6] as u32) << 8 | (cfr_reg[7] as u32),
|
|
|
|
(cfr_reg[8] as u32) << 24 | (cfr_reg[9] as u32) << 16 | (cfr_reg[10] as u32) << 8 | (cfr_reg[11] as u32)
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a set of configurations using DDSCFRMask
|
|
|
|
*/
|
|
|
|
pub fn get_configurations<'w>(&mut self, mask_pairs: &'w mut[(DDSCFRMask, u32)]) -> Result<&'w [(DDSCFRMask, u32)], Error<E>> {
|
|
|
|
let data_array = self.get_all_configurations()?;
|
|
|
|
for index in 0..mask_pairs.len() {
|
|
|
|
mask_pairs[index].1 = match mask_pairs[index].0.get_shift() {
|
|
|
|
0..=31 => mask_pairs[index].0.get_filtered_content(data_array[0]),
|
|
|
|
32..=63 => mask_pairs[index].0.get_filtered_content(data_array[1]),
|
|
|
|
64..=95 => mask_pairs[index].0.get_filtered_content(data_array[2]),
|
|
|
|
_ => panic!("Invalid DDSCFRMask!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(mask_pairs)
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Write (cfr1, cfr2, cfr3) contents
|
|
|
|
*/
|
|
|
|
fn set_all_configurations(&mut self, data_array: [u32; 3]) -> Result<(), Error<E>> {
|
|
|
|
for register in 0x00..=0x02 {
|
|
|
|
self.write_register(register, &mut [
|
|
|
|
((data_array[register as usize] >> 24) & 0xFF) as u8,
|
|
|
|
((data_array[register as usize] >> 16) & 0xFF) as u8,
|
|
|
|
((data_array[register as usize] >> 8 ) & 0xFF) as u8,
|
|
|
|
((data_array[register as usize] >> 0 ) & 0xFF) as u8
|
|
|
|
])?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set a set of configurations using DDSCFRMask
|
|
|
|
*/
|
|
|
|
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
|
|
|
|
if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST || mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
match mask_pairs[index].0.get_shift() {
|
|
|
|
0..=31 => mask_pairs[index].0.set_data_by_arg(&mut data_array[0], mask_pairs[index].1),
|
|
|
|
32..=63 => mask_pairs[index].0.set_data_by_arg(&mut data_array[1], mask_pairs[index].1),
|
|
|
|
64..=95 => mask_pairs[index].0.set_data_by_arg(&mut data_array[2], mask_pairs[index].1),
|
|
|
|
_ => panic!("Invalid DDSCFRMask!"),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
hprintln!("Modified array {:#X?}", data_array).unwrap();
|
|
|
|
self.set_all_configurations(data_array.clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2020-08-26 11:04:08 +08:00
|
|
|
|
2020-08-17 11:45:42 +08:00
|
|
|
macro_rules! impl_register_io {
|
|
|
|
($($reg_addr: expr, $reg_byte_size: expr),+) => {
|
|
|
|
impl<SPI, E> DDS<SPI>
|
|
|
|
where
|
|
|
|
SPI: Transfer<u8, Error = E>
|
|
|
|
{
|
|
|
|
pub fn write_register(&mut self, addr: u8, bytes: &mut[u8]) -> Result<(), Error<E>> {
|
|
|
|
match addr {
|
|
|
|
$(
|
|
|
|
$reg_addr => {
|
|
|
|
assert_eq!(bytes.len(), $reg_byte_size);
|
2020-08-17 12:15:11 +08:00
|
|
|
let mut arr: [u8; $reg_byte_size + 1] = [0; ($reg_byte_size + 1)];
|
|
|
|
arr[0] = addr | WRITE_MASK;
|
2020-08-17 11:45:42 +08:00
|
|
|
for i in 0..$reg_byte_size {
|
|
|
|
arr[i+1] = bytes[i];
|
|
|
|
}
|
2020-08-17 12:15:11 +08:00
|
|
|
match self.spi.transfer(&mut arr).map_err(Error::SPI) {
|
2020-08-17 11:45:42 +08:00
|
|
|
Ok(v) => Ok(()),
|
|
|
|
Err(e) => Err(e),
|
2020-08-17 12:15:11 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
)*
|
|
|
|
_ => panic!("Bad address for DDS writing.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn read_register<'w>(&mut self, addr: u8, bytes: &'w mut[u8]) -> Result<&'w [u8], Error<E>> {
|
|
|
|
match addr {
|
|
|
|
$(
|
|
|
|
$reg_addr => {
|
|
|
|
assert_eq!(bytes.len(), $reg_byte_size);
|
|
|
|
let mut arr: [u8; $reg_byte_size + 1] = [0; ($reg_byte_size + 1)];
|
|
|
|
arr[0] = addr | READ_MASK;
|
|
|
|
match self.spi.transfer(&mut arr).map_err(Error::SPI) {
|
|
|
|
Ok(ret) => {
|
|
|
|
assert_eq!(ret.len(), $reg_byte_size + 1);
|
|
|
|
for i in 0..$reg_byte_size {
|
|
|
|
bytes[i] = ret[i+1];
|
|
|
|
}
|
|
|
|
Ok(bytes)
|
|
|
|
},
|
|
|
|
Err(e) => Err(e),
|
|
|
|
}
|
2020-08-17 11:45:42 +08:00
|
|
|
},
|
|
|
|
)*
|
2020-08-17 12:15:11 +08:00
|
|
|
_ => panic!("Bad address for DDS reading.")
|
2020-08-17 11:45:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl_register_io!(
|
|
|
|
0x00, 4,
|
|
|
|
0x01, 4,
|
|
|
|
0x02, 4,
|
|
|
|
0x03, 4,
|
|
|
|
0x04, 4,
|
|
|
|
0x07, 4,
|
|
|
|
0x08, 2,
|
|
|
|
0x09, 4,
|
|
|
|
0x0A, 4,
|
|
|
|
0x0B, 8,
|
|
|
|
0x0C, 8,
|
|
|
|
0x0D, 4,
|
|
|
|
0x0E, 8,
|
|
|
|
0x0F, 8,
|
|
|
|
0x10, 8,
|
|
|
|
0x11, 8,
|
|
|
|
0x12, 8,
|
|
|
|
0x13, 8,
|
|
|
|
0x14, 8,
|
|
|
|
0x15, 8,
|
|
|
|
0x16, 4
|
|
|
|
);
|