use embedded_hal::blocking::spi::Transfer; use cortex_m_semihosting::hprintln; use crate::Error; use core::mem::size_of; /* * Bitmask for all configurations (Order: CFR3, CFR2, CFR1) */ construct_bitmask!(DDSCFRMask; u32; // CFR1 bitmasks 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, RAM_ENABLE, 31, 1, // 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, // 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 ); const WRITE_MASK :u8 = 0x00; const READ_MASK :u8 = 0x80; pub struct DDS { spi: SPI, } impl DDS where SPI: Transfer { pub fn new(spi: SPI) -> Self { DDS { spi } } } impl Transfer for DDS where SPI: Transfer { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { self.spi.transfer(words).map_err(Error::SPI) } } /* * Implement init */ impl DDS where SPI: Transfer { pub fn init(&mut self) -> Result<(), Error> { match self.write_register(0x00, &mut [ 0x00, 0x00, 0x00, 0x02 ]) { Ok(_) => Ok(()), Err(e) => Err(e), } } } /* * Impleement configurations registers I/O through bitmasks */ impl DDS where SPI: Transfer { /* * Return (cfr1, cfr2, cfr3) contents */ fn get_all_configurations(&mut self) -> Result<[u32; 3], Error> { 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> { 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> { 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> { 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()) } } macro_rules! impl_register_io { ($($reg_addr: expr, $reg_byte_size: expr),+) => { impl DDS where SPI: Transfer { pub fn write_register(&mut self, addr: u8, bytes: &mut[u8]) -> Result<(), Error> { 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 | WRITE_MASK; for i in 0..$reg_byte_size { arr[i+1] = bytes[i]; } match self.spi.transfer(&mut arr).map_err(Error::SPI) { Ok(v) => Ok(()), Err(e) => Err(e), } }, )* _ => panic!("Bad address for DDS writing.") } } pub fn read_register<'w>(&mut self, addr: u8, bytes: &'w mut[u8]) -> Result<&'w [u8], Error> { 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), } }, )* _ => panic!("Bad address for DDS reading.") } } } } } 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 );