pounder_test/ad9959/src/lib.rs

572 lines
18 KiB
Rust
Raw Normal View History

2020-06-09 00:20:10 +08:00
#![no_std]
use bit_field::BitField;
2020-06-16 22:22:12 +08:00
use embedded_hal::{blocking::delay::DelayMs, digital::v2::OutputPin};
2020-06-09 00:20:10 +08:00
/// A device driver for the AD9959 direct digital synthesis (DDS) chip.
///
/// This chip provides four independently controllable digital-to-analog output sinusoids with
/// configurable phase, amplitude, and frequency. All channels are inherently synchronized as they
/// are derived off a common system clock.
///
/// The chip contains a configurable PLL and supports system clock frequencies up to 500 MHz.
///
/// The chip supports a number of serial interfaces to improve data throughput, including normal,
/// dual, and quad SPI configurations.
pub struct Ad9959<INTERFACE, DELAY, UPDATE> {
2020-10-22 22:16:38 +08:00
pub interface: INTERFACE,
2020-06-09 00:20:10 +08:00
delay: DELAY,
reference_clock_frequency: f32,
2020-06-09 00:20:10 +08:00
system_clock_multiplier: u8,
io_update: UPDATE,
2020-10-22 22:16:38 +08:00
communication_mode: Mode,
2020-06-09 00:20:10 +08:00
}
2020-06-11 17:51:52 +08:00
/// A trait that allows a HAL to provide a means of communicating with the AD9959.
2020-06-09 00:20:10 +08:00
pub trait Interface {
type Error;
fn configure_mode(&mut self, mode: Mode) -> Result<(), Self::Error>;
fn write(&mut self, addr: u8, data: &[u8]) -> Result<(), Self::Error>;
fn read(&mut self, addr: u8, dest: &mut [u8]) -> Result<(), Self::Error>;
2020-10-22 22:16:38 +08:00
fn write_profile(&mut self, data: [u32; 4]) -> Result<(), Self::Error>;
2020-06-09 00:20:10 +08:00
}
2020-06-11 17:51:52 +08:00
/// Indicates various communication modes of the DDS. The value of this enumeration is equivalent to
/// the configuration bits of the DDS CSR register.
2020-06-09 00:20:10 +08:00
#[derive(Copy, Clone, PartialEq)]
pub enum Mode {
SingleBitTwoWire = 0b00,
SingleBitThreeWire = 0b01,
TwoBitSerial = 0b10,
FourBitSerial = 0b11,
}
/// The configuration registers within the AD9959 DDS device. The values of each register are
/// equivalent to the address.
pub enum Register {
CSR = 0x00,
FR1 = 0x01,
FR2 = 0x02,
CFR = 0x03,
CFTW0 = 0x04,
CPOW0 = 0x05,
ACR = 0x06,
LSRR = 0x07,
RDW = 0x08,
FDW = 0x09,
CW1 = 0x0a,
CW2 = 0x0b,
CW3 = 0x0c,
CW4 = 0x0d,
CW5 = 0x0e,
CW6 = 0x0f,
CW7 = 0x10,
CW8 = 0x11,
CW9 = 0x12,
CW10 = 0x13,
CW11 = 0x14,
CW12 = 0x15,
CW13 = 0x16,
CW14 = 0x17,
CW15 = 0x18,
}
/// Specifies an output channel of the AD9959 DDS chip.
pub enum Channel {
One = 0,
Two = 1,
Three = 2,
Four = 3,
}
/// Possible errors generated by the AD9959 driver.
#[derive(Debug)]
2020-06-12 00:02:01 +08:00
pub enum Error {
Interface,
Check,
2020-06-09 00:20:10 +08:00
Bounds,
Pin,
Frequency,
}
2020-06-16 22:22:12 +08:00
impl<PinE, INTERFACE, DELAY, UPDATE> Ad9959<INTERFACE, DELAY, UPDATE>
2020-06-09 00:20:10 +08:00
where
2020-06-12 00:02:01 +08:00
INTERFACE: Interface,
2020-06-09 00:20:10 +08:00
DELAY: DelayMs<u8>,
UPDATE: OutputPin<Error = PinE>,
{
2020-06-11 17:51:52 +08:00
/// Construct and initialize the DDS.
///
/// Args:
/// * `interface` - An interface to the DDS.
/// * `reset_pin` - A pin connected to the DDS reset input.
/// * `io_update` - A pin connected to the DDS io_update input.
/// * `delay` - A delay implementation for blocking operation for specific amounts of time.
/// * `desired_mode` - The desired communication mode of the interface to the DDS.
/// * `clock_frequency` - The clock frequency of the reference clock input.
/// * `multiplier` - The desired clock multiplier for the system clock. This multiplies
/// `clock_frequency` to generate the system clock.
2020-06-16 22:22:12 +08:00
pub fn new<RST>(
interface: INTERFACE,
reset_pin: &mut RST,
io_update: UPDATE,
delay: DELAY,
desired_mode: Mode,
clock_frequency: f32,
multiplier: u8,
) -> Result<Self, Error>
2020-06-09 00:20:10 +08:00
where
RST: OutputPin,
{
let mut ad9959 = Ad9959 {
interface,
io_update,
delay,
2020-06-09 00:20:10 +08:00
reference_clock_frequency: clock_frequency,
system_clock_multiplier: 1,
2020-10-22 22:16:38 +08:00
communication_mode: desired_mode,
2020-06-09 00:20:10 +08:00
};
ad9959.io_update.set_low().or_else(|_| Err(Error::Pin))?;
2020-06-09 00:20:10 +08:00
// Reset the AD9959
reset_pin.set_high().or_else(|_| Err(Error::Pin))?;
// Delay for a clock cycle to allow the device to reset.
2020-06-16 22:22:12 +08:00
ad9959
.delay
.delay_ms((1000.0 / clock_frequency as f32) as u8);
2020-06-09 00:20:10 +08:00
reset_pin.set_low().or_else(|_| Err(Error::Pin))?;
2020-06-16 22:22:12 +08:00
ad9959
.interface
.configure_mode(Mode::SingleBitTwoWire)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
// Program the interface configuration in the AD9959. Default to all channels enabled.
let mut csr: [u8; 1] = [0xF0];
csr[0].set_bits(1..3, desired_mode as u8);
2020-06-16 22:22:12 +08:00
ad9959
.interface
.write(Register::CSR as u8, &csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
// Latch the configuration registers to make them active.
ad9959.latch_configuration()?;
2020-06-16 22:22:12 +08:00
ad9959
.interface
.configure_mode(desired_mode)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
// Read back the CSR to ensure it specifies the mode correctly.
let mut updated_csr: [u8; 1] = [0];
2020-06-16 22:22:12 +08:00
ad9959
.interface
.read(Register::CSR as u8, &mut updated_csr)
.map_err(|_| Error::Interface)?;
if updated_csr[0] != csr[0] {
return Err(Error::Check);
}
2020-06-09 00:20:10 +08:00
// Set the clock frequency to configure the device as necessary.
ad9959.configure_system_clock(clock_frequency, multiplier)?;
Ok(ad9959)
}
2020-06-11 17:51:52 +08:00
/// Latch the DDS configuration to ensure it is active on the output channels.
2020-10-22 22:16:38 +08:00
pub fn latch_configuration(&mut self) -> Result<(), Error> {
self.delay.delay_ms(2);
2020-06-16 22:22:12 +08:00
self.io_update.set_high().or_else(|_| Err(Error::Pin))?;
// The SYNC_CLK is 1/4 the system clock frequency. The IO_UPDATE pin must be latched for one
// full SYNC_CLK pulse to register. For safety, we latch for 5 here.
self.delay
.delay_ms((5000.0 / self.system_clock_frequency()) as u8);
self.io_update.set_low().or_else(|_| Err(Error::Pin))?;
2020-06-09 00:20:10 +08:00
2020-06-16 22:22:12 +08:00
Ok(())
2020-06-09 00:20:10 +08:00
}
/// Configure the internal system clock of the chip.
///
/// Arguments:
/// * `reference_clock_frequency` - The reference clock frequency provided to the AD9959 core.
/// * `multiplier` - The frequency multiplier of the system clock. Must be 1 or 4-20.
2020-06-09 00:20:10 +08:00
///
/// Returns:
/// The actual frequency configured for the internal system clock.
2020-06-16 22:22:12 +08:00
pub fn configure_system_clock(
&mut self,
reference_clock_frequency: f32,
multiplier: u8,
2020-10-22 22:16:38 +08:00
) -> Result<f32, Error> {
2020-06-09 00:20:10 +08:00
self.reference_clock_frequency = reference_clock_frequency;
if multiplier != 1 && (multiplier > 20 || multiplier < 4) {
2020-06-09 00:20:10 +08:00
return Err(Error::Bounds);
}
2020-06-16 22:22:12 +08:00
let frequency =
2020-10-22 22:16:38 +08:00
multiplier as f32 * self.reference_clock_frequency as f32;
if frequency > 500_000_000.0f32 {
2020-06-09 00:20:10 +08:00
return Err(Error::Frequency);
}
// TODO: Update / disable any enabled channels?
let mut fr1: [u8; 3] = [0, 0, 0];
2020-06-16 22:22:12 +08:00
self.interface
.read(Register::FR1 as u8, &mut fr1)
.map_err(|_| Error::Interface)?;
fr1[0].set_bits(2..=6, multiplier);
2020-06-09 00:20:10 +08:00
let vco_range = frequency > 255e6;
fr1[0].set_bit(7, vco_range);
2020-06-16 22:22:12 +08:00
self.interface
.write(Register::FR1 as u8, &fr1)
.map_err(|_| Error::Interface)?;
self.system_clock_multiplier = multiplier;
2020-06-09 00:20:10 +08:00
2020-10-22 22:16:38 +08:00
self.latch_configuration()?;
2020-06-09 00:20:10 +08:00
Ok(self.system_clock_frequency())
}
2020-06-11 17:51:52 +08:00
/// Get the current reference clock frequency in Hz.
pub fn get_reference_clock_frequency(&self) -> f32 {
self.reference_clock_frequency
}
2020-06-11 17:51:52 +08:00
/// Get the current reference clock multiplier.
2020-06-12 00:02:01 +08:00
pub fn get_reference_clock_multiplier(&mut self) -> Result<u8, Error> {
let mut fr1: [u8; 3] = [0, 0, 0];
2020-06-16 22:22:12 +08:00
self.interface
.read(Register::FR1 as u8, &mut fr1)
.map_err(|_| Error::Interface)?;
Ok(fr1[0].get_bits(2..=6) as u8)
}
2020-06-09 00:20:10 +08:00
/// Perform a self-test of the communication interface.
///
/// Note:
/// This modifies the existing channel enables. They are restored upon exit.
///
/// Returns:
/// True if the self test succeeded. False otherwise.
2020-06-12 00:02:01 +08:00
pub fn self_test(&mut self) -> Result<bool, Error> {
2020-06-09 00:20:10 +08:00
let mut csr: [u8; 1] = [0];
2020-06-16 22:22:12 +08:00
self.interface
.read(Register::CSR as u8, &mut csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
let old_csr = csr[0];
// Enable all channels.
csr[0].set_bits(4..8, 0xF);
2020-06-16 22:22:12 +08:00
self.interface
.write(Register::CSR as u8, &csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
// Read back the enable.
csr[0] = 0;
2020-06-16 22:22:12 +08:00
self.interface
.read(Register::CSR as u8, &mut csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
if csr[0].get_bits(4..8) != 0xF {
return Ok(false);
}
// Clear all channel enables.
csr[0].set_bits(4..8, 0x0);
2020-06-16 22:22:12 +08:00
self.interface
.write(Register::CSR as u8, &csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
// Read back the enable.
csr[0] = 0xFF;
2020-06-16 22:22:12 +08:00
self.interface
.read(Register::CSR as u8, &mut csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
if csr[0].get_bits(4..8) != 0 {
return Ok(false);
}
// Restore the CSR.
csr[0] = old_csr;
2020-06-16 22:22:12 +08:00
self.interface
.write(Register::CSR as u8, &csr)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
Ok(true)
}
2020-06-11 17:51:52 +08:00
/// Get the current system clock frequency in Hz.
2020-10-22 22:16:38 +08:00
fn system_clock_frequency(&self) -> f32 {
self.system_clock_multiplier as f32
* self.reference_clock_frequency as f32
}
2020-06-11 17:51:52 +08:00
/// Update an output channel configuration register.
///
/// Args:
/// * `channel` - The channel to configure.
/// * `register` - The register to update.
/// * `data` - The contents to write to the provided register.
2020-06-16 22:22:12 +08:00
fn modify_channel(
&mut self,
channel: Channel,
register: Register,
data: &[u8],
) -> Result<(), Error> {
2020-06-11 17:51:52 +08:00
// Disable all other outputs so that we can update the configuration register of only the
// specified channel.
2020-10-22 22:16:38 +08:00
let csr: u8 = *0x00_u8
.set_bits(1..=2, self.communication_mode as u8)
.set_bit(4 + channel as usize, true);
2020-06-09 00:20:10 +08:00
2020-06-16 22:22:12 +08:00
self.interface
2020-10-22 22:16:38 +08:00
.write(Register::CSR as u8, &[csr])
2020-06-16 22:22:12 +08:00
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
2020-06-16 22:22:12 +08:00
self.interface
.write(register as u8, &data)
.map_err(|_| Error::Interface)?;
2020-06-09 00:20:10 +08:00
// Latch the configuration and restore the previous CSR. Note that the re-enable of the
// channel happens immediately, so the CSR update does not need to be latched.
self.latch_configuration()?;
Ok(())
}
2020-06-11 17:51:52 +08:00
/// Read a configuration register of a specific channel.
///
/// Args:
/// * `channel` - The channel to read.
/// * `register` - The register to read.
/// * `data` - A location to store the read register contents.
2020-06-16 22:22:12 +08:00
fn read_channel(
&mut self,
channel: Channel,
register: Register,
mut data: &mut [u8],
) -> Result<(), Error> {
2020-06-11 17:51:52 +08:00
// Disable all other channels in the CSR so that we can read the configuration register of
// only the desired channel.
let mut csr: [u8; 1] = [0];
2020-06-16 22:22:12 +08:00
self.interface
.read(Register::CSR as u8, &mut csr)
.map_err(|_| Error::Interface)?;
let mut new_csr = csr;
new_csr[0].set_bits(4..8, 0);
new_csr[0].set_bit(4 + channel as usize, true);
2020-06-16 22:22:12 +08:00
self.interface
.write(Register::CSR as u8, &new_csr)
.map_err(|_| Error::Interface)?;
2020-06-16 22:22:12 +08:00
self.interface
.read(register as u8, &mut data)
.map_err(|_| Error::Interface)?;
// Restore the previous CSR. Note that the re-enable of the channel happens immediately, so
// the CSR update does not need to be latched.
2020-06-16 22:22:12 +08:00
self.interface
.write(Register::CSR as u8, &csr)
.map_err(|_| Error::Interface)?;
Ok(())
}
2020-06-09 00:20:10 +08:00
/// Configure the phase of a specified channel.
///
/// Arguments:
/// * `channel` - The channel to configure the frequency of.
/// * `phase_turns` - The desired phase offset in turns.
2020-06-09 00:20:10 +08:00
///
/// Returns:
/// The actual programmed phase offset of the channel in turns.
2020-06-16 22:22:12 +08:00
pub fn set_phase(
&mut self,
channel: Channel,
phase_turns: f32,
) -> Result<f32, Error> {
let phase_offset: u16 =
(phase_turns * (1 << 14) as f32) as u16 & 0x3FFFu16;
self.modify_channel(
channel,
Register::CPOW0,
&phase_offset.to_be_bytes(),
)?;
Ok((phase_offset as f32) / ((1 << 14) as f32))
}
2020-06-11 17:51:52 +08:00
/// Get the current phase of a specified channel.
///
/// Args:
/// * `channel` - The channel to get the phase of.
///
/// Returns:
/// The phase of the channel in turns.
2020-06-12 00:02:01 +08:00
pub fn get_phase(&mut self, channel: Channel) -> Result<f32, Error> {
let mut phase_offset: [u8; 2] = [0; 2];
self.read_channel(channel, Register::CPOW0, &mut phase_offset)?;
let phase_offset = u16::from_be_bytes(phase_offset) & 0x3FFFu16;
Ok((phase_offset as f32) / ((1 << 14) as f32))
2020-06-09 00:20:10 +08:00
}
/// Configure the amplitude of a specified channel.
///
/// Arguments:
/// * `channel` - The channel to configure the frequency of.
/// * `amplitude` - A normalized amplitude setting [0, 1].
///
/// Returns:
/// The actual normalized amplitude of the channel relative to full-scale range.
2020-06-16 22:22:12 +08:00
pub fn set_amplitude(
&mut self,
channel: Channel,
amplitude: f32,
) -> Result<f32, Error> {
2020-06-09 00:20:10 +08:00
if amplitude < 0.0 || amplitude > 1.0 {
return Err(Error::Bounds);
}
let amplitude_control: u16 = (amplitude * (1 << 10) as f32) as u16;
let mut acr: [u8; 3] = [0; 3];
2020-06-09 00:20:10 +08:00
// Enable the amplitude multiplier for the channel if required. The amplitude control has
// full-scale at 0x3FF (amplitude of 1), so the multiplier should be disabled whenever
// full-scale is used.
if amplitude_control < (1 << 10) {
let masked_control = amplitude_control & 0x3FF;
acr[1] = masked_control.to_be_bytes()[0];
acr[2] = masked_control.to_be_bytes()[1];
// Enable the amplitude multiplier
acr[1].set_bit(4, true);
}
2020-06-09 00:20:10 +08:00
self.modify_channel(channel, Register::ACR, &acr)?;
Ok(amplitude_control as f32 / (1 << 10) as f32)
}
2020-06-11 17:51:52 +08:00
/// Get the configured amplitude of a channel.
///
/// Args:
/// * `channel` - The channel to get the amplitude of.
///
/// Returns:
/// The normalized amplitude of the channel.
2020-06-12 00:02:01 +08:00
pub fn get_amplitude(&mut self, channel: Channel) -> Result<f32, Error> {
let mut acr: [u8; 3] = [0; 3];
self.read_channel(channel, Register::ACR, &mut acr)?;
if acr[1].get_bit(4) {
2020-06-16 22:22:12 +08:00
let amplitude_control: u16 =
(((acr[1] as u16) << 8) | (acr[2] as u16)) & 0x3FF;
Ok(amplitude_control as f32 / (1 << 10) as f32)
} else {
Ok(1.0)
}
2020-06-09 00:20:10 +08:00
}
/// Configure the frequency of a specified channel.
///
/// Arguments:
/// * `channel` - The channel to configure the frequency of.
/// * `frequency` - The desired output frequency in Hz.
///
/// Returns:
/// The actual programmed frequency of the channel.
2020-06-16 22:22:12 +08:00
pub fn set_frequency(
&mut self,
channel: Channel,
2020-10-22 22:16:38 +08:00
frequency: f32,
) -> Result<f32, Error> {
2020-06-09 00:20:10 +08:00
if frequency < 0.0 || frequency > self.system_clock_frequency() {
return Err(Error::Bounds);
}
// The function for channel frequency is `f_out = FTW * f_s / 2^32`, where FTW is the
// frequency tuning word and f_s is the system clock rate.
2020-06-16 22:22:12 +08:00
let tuning_word: u32 =
2020-10-22 22:16:38 +08:00
((frequency as f32 / self.system_clock_frequency())
* 1u64.wrapping_shl(32) as f32) as u32;
2020-06-16 22:22:12 +08:00
self.modify_channel(
channel,
Register::CFTW0,
&tuning_word.to_be_bytes(),
)?;
2020-10-22 22:16:38 +08:00
Ok((tuning_word as f32 / 1u64.wrapping_shl(32) as f32)
2020-06-16 22:22:12 +08:00
* self.system_clock_frequency())
2020-06-09 00:20:10 +08:00
}
2020-06-11 17:51:52 +08:00
/// Get the frequency of a channel.
///
/// Arguments:
/// * `channel` - The channel to get the frequency of.
///
/// Returns:
/// The frequency of the channel in Hz.
2020-10-22 22:16:38 +08:00
pub fn get_frequency(&mut self, channel: Channel) -> Result<f32, Error> {
// Read the frequency tuning word for the channel.
let mut tuning_word: [u8; 4] = [0; 4];
self.read_channel(channel, Register::CFTW0, &mut tuning_word)?;
let tuning_word = u32::from_be_bytes(tuning_word);
// Convert the tuning word into a frequency.
2020-10-22 22:16:38 +08:00
Ok((tuning_word as f32 * self.system_clock_frequency()) / (1u64 << 32) as f32)
}
2020-10-21 16:17:22 +08:00
2020-10-22 22:16:38 +08:00
pub fn write_profile(&mut self, channel: Channel, freq: f32, turns: f32, amplitude: f32) -> Result<(), Error> {
let csr: u8 = *0x00_u8
.set_bits(1..=2, self.communication_mode as u8)
.set_bit(4 + channel as usize, true);
2020-10-21 16:17:22 +08:00
// The function for channel frequency is `f_out = FTW * f_s / 2^32`, where FTW is the
// frequency tuning word and f_s is the system clock rate.
2020-10-22 22:16:38 +08:00
let tuning_word: u32 = ((freq * (1u64 << 32) as f32) / self.system_clock_frequency()) as u32;
2020-10-21 16:17:22 +08:00
let phase_offset: u16 = (turns * (1 << 14) as f32) as u16 & 0x3FFFu16;
2020-10-22 22:16:38 +08:00
let pow: u32 = *0u32.set_bits(24..32, Register::CPOW0 as u32)
.set_bits(8..24, phase_offset as u32)
.set_bits(0..8, Register::CFTW0 as u32);
2020-10-21 16:17:22 +08:00
// Enable the amplitude multiplier for the channel if required. The amplitude control has
// full-scale at 0x3FF (amplitude of 1), so the multiplier should be disabled whenever
// full-scale is used.
2020-10-22 22:16:38 +08:00
let amplitude_control: u16 = (amplitude * (1 << 10) as f32) as u16;
2020-10-21 16:17:22 +08:00
2020-10-22 22:16:38 +08:00
let acr: u32 = *0u32.set_bits(24..32, Register::ACR as u32)
.set_bits(0..10, amplitude_control as u32 & 0x3FF)
.set_bit(12, amplitude_control < (1 << 10));
2020-10-21 16:17:22 +08:00
2020-10-22 22:16:38 +08:00
let serialized: [u32; 4] = [
u32::from_le_bytes([Register::CSR as u8, csr, Register::CSR as u8, csr]),
acr.to_be(),
pow.to_be(),
tuning_word.to_be(),
];
2020-10-21 16:17:22 +08:00
2020-10-22 22:16:38 +08:00
self.interface.write_profile(serialized).map_err(|_| Error::Interface)?;
2020-10-21 16:17:22 +08:00
2020-10-22 22:16:38 +08:00
Ok(())
2020-10-21 16:17:22 +08:00
}
2020-06-09 00:20:10 +08:00
}