Skip to content

Commit

Permalink
Split into modules
Browse files Browse the repository at this point in the history
  • Loading branch information
eldruin committed May 30, 2019
1 parent bf905ee commit 868cb47
Show file tree
Hide file tree
Showing 4 changed files with 384 additions and 372 deletions.
46 changes: 46 additions & 0 deletions src/ad9833_ad9837.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use {marker, Ad983x, BitFlags, Error, OutputWaveform, SpiInterface};

impl<SPI, CS> Ad983x<SpiInterface<SPI, CS>, marker::Ad9833Ad9837> {
/// Create a new instance of an AD9833 device.
/// Remember to call `reset()` before using the device after power up.
pub fn new_ad9833(spi: SPI, chip_select: CS) -> Self {
Self::create(spi, chip_select)
}
/// Create a new instance of an AD9837 device.
/// Remember to call `reset()` before using the device after power up.
pub fn new_ad9837(spi: SPI, chip_select: CS) -> Self {
// Behaves the same as AD9833
Self::create(spi, chip_select)
}
}

impl<SPI, CS, E> Ad983x<SpiInterface<SPI, CS>, marker::Ad9833Ad9837>
where
SPI: hal::blocking::spi::Write<u8, Error = E>,
CS: hal::digital::OutputPin,
{
/// Set the output waveform
pub fn set_output_waveform(&mut self, waveform: OutputWaveform) -> Result<(), Error<E>> {
let control = match waveform {
OutputWaveform::Sinusoidal => self
.control
.with_low(BitFlags::OPBITEN)
.with_low(BitFlags::MODE),
OutputWaveform::Triangle => self
.control
.with_low(BitFlags::OPBITEN)
.with_high(BitFlags::MODE),
OutputWaveform::SquareMsbOfDac => self
.control
.with_high(BitFlags::OPBITEN)
.with_low(BitFlags::MODE)
.with_high(BitFlags::DIV2),
OutputWaveform::SquareMsbOfDacDiv2 => self
.control
.with_high(BitFlags::OPBITEN)
.with_low(BitFlags::MODE)
.with_low(BitFlags::DIV2),
};
self.write_control(control)
}
}
84 changes: 84 additions & 0 deletions src/ad9834_ad9838.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use {marker, Ad983x, BitFlags, ControlSource, Error, OutputWaveform, SignBitOutput, SpiInterface};

impl<SPI, CS> Ad983x<SpiInterface<SPI, CS>, marker::Ad9834Ad9838> {
/// Create a new instance of an AD9834 device.
/// Remember to call `reset()` before using the device after power up.
pub fn new_ad9834(spi: SPI, chip_select: CS) -> Self {
Self::create(spi, chip_select)
}

/// Create a new instance of an AD9838 device.
/// Remember to call `reset()` before using the device after power up.
pub fn new_ad9838(spi: SPI, chip_select: CS) -> Self {
Self::create(spi, chip_select)
}
}

impl<SPI, CS, E> Ad983x<SpiInterface<SPI, CS>, marker::Ad9834Ad9838>
where
SPI: hal::blocking::spi::Write<u8, Error = E>,
CS: hal::digital::OutputPin,
{
/// Set the output waveform
///
/// Will return `Error::InvalidArgument` for `SquareMsbOfDac` and `SquareMsbOfDacDiv2`
/// as this is not available on AD9834/AD9838 devices. To set the digital output,
/// please use
pub fn set_output_waveform(&mut self, waveform: OutputWaveform) -> Result<(), Error<E>> {
let control;
match waveform {
OutputWaveform::Sinusoidal => {
control = self
.control
.with_low(BitFlags::OPBITEN)
.with_low(BitFlags::MODE)
}
OutputWaveform::Triangle => {
control = self
.control
.with_low(BitFlags::OPBITEN)
.with_high(BitFlags::MODE)
}
OutputWaveform::SquareMsbOfDac => return Err(Error::InvalidArgument),
OutputWaveform::SquareMsbOfDacDiv2 => return Err(Error::InvalidArgument),
};
self.write_control(control)
}

/// Set the digital output
pub fn set_sign_bit_output(&mut self, configuration: SignBitOutput) -> Result<(), Error<E>> {
let control = match configuration {
SignBitOutput::Disabled => self.control.with_low(BitFlags::OPBITEN),
SignBitOutput::Comparator => self
.control
.with_high(BitFlags::OPBITEN)
.with_low(BitFlags::MODE)
.with_high(BitFlags::SIGN_PIB)
.with_high(BitFlags::DIV2),
SignBitOutput::SquareMsbOfDac => self
.control
.with_high(BitFlags::OPBITEN)
.with_low(BitFlags::MODE)
.with_low(BitFlags::SIGN_PIB)
.with_high(BitFlags::DIV2),
SignBitOutput::SquareMsbOfDacDiv2 => self
.control
.with_high(BitFlags::OPBITEN)
.with_low(BitFlags::MODE)
.with_low(BitFlags::SIGN_PIB)
.with_low(BitFlags::DIV2),
};
self.write_control(control)
}

/// Set the control source used for the functions:
/// frequency register selection, phase register selection,
/// reset of internal registers, and DAC power-down.
pub fn set_control_source(&mut self, source: ControlSource) -> Result<(), Error<E>> {
let control = match source {
ControlSource::Software => self.control.with_low(BitFlags::PIN_SW),
ControlSource::HardwarePins => self.control.with_high(BitFlags::PIN_SW),
};
self.write_control(control)
}
}
249 changes: 249 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
use core::marker::PhantomData;
use {
Ad983x, BitFlags, Config, Error, FrequencyRegister, PhaseRegister, PoweredDown, SpiInterface,
};

impl Config {
pub(crate) fn with_high(self, mask: u16) -> Self {
Config {
bits: self.bits | mask,
}
}
pub(crate) fn with_low(self, mask: u16) -> Self {
Config {
bits: self.bits & !mask,
}
}
}

impl BitFlags {
pub(crate) const D15: u16 = 1 << 15;
pub(crate) const D14: u16 = 1 << 14;
pub(crate) const D13: u16 = 1 << 13;
pub(crate) const B28: u16 = 1 << 13;
pub(crate) const HLB: u16 = 1 << 12;
pub(crate) const FSELECT: u16 = 1 << 11;
pub(crate) const PSELECT: u16 = 1 << 10;
pub(crate) const PIN_SW: u16 = 1 << 9;
pub(crate) const RESET: u16 = 1 << 8;
pub(crate) const SLEEP_MCLK: u16 = 1 << 7; // SLEEP1
pub(crate) const SLEEP_DAC: u16 = 1 << 6; // SLEEP12
pub(crate) const OPBITEN: u16 = 1 << 5;
pub(crate) const SIGN_PIB: u16 = 1 << 4;
pub(crate) const DIV2: u16 = 1 << 3;
pub(crate) const MODE: u16 = 1 << 1;
}

impl<SPI, CS, IC> Ad983x<SpiInterface<SPI, CS>, IC> {
pub(crate) fn create(spi: SPI, chip_select: CS) -> Self {
Ad983x {
iface: SpiInterface {
spi,
cs: chip_select,
},
control: Config {
bits: BitFlags::RESET,
},
_ic: PhantomData,
}
}
}

impl<SPI, CS, E, IC> Ad983x<SpiInterface<SPI, CS>, IC>
where
SPI: hal::blocking::spi::Write<u8, Error = E>,
CS: hal::digital::OutputPin,
{
/// Destroy driver instance, return SPI bus instance and CS output pin.
pub fn destroy(self) -> (SPI, CS) {
(self.iface.spi, self.iface.cs)
}

/// Resets the internal registers and leaves the device disabled.
///
/// Note that this is ignored in AD9834/AD9838 devices if hardware pin
/// control source is selected.
pub fn reset(&mut self) -> Result<(), Error<E>> {
self.disable()
}

/// Disable the device (enable reset)
///
/// This resets the internal registers.
/// Note that this is ignored in AD9834/AD9838 devices if hardware pin
/// control source is selected.
pub fn disable(&mut self) -> Result<(), Error<E>> {
let control = self.control.with_high(BitFlags::RESET);
self.write_control(control)
}

/// Enable the device (disable reset)
///
/// Note that this is ignored in AD9834/AD9838 devices if hardware pin
/// control source is selected.
pub fn enable(&mut self) -> Result<(), Error<E>> {
let control = self.control.with_low(BitFlags::RESET);
self.write_control(control)
}

fn check_value_fits<T>(value: T, bit_count: T) -> Result<(), Error<E>>
where
T: From<u8> + PartialOrd + core::ops::Shl<Output = T>,
{
if value >= (T::from(1) << bit_count) {
Err(Error::InvalidArgument)
} else {
Ok(())
}
}

/// Set the frequency as a 28-bit word
///
/// This will change the mode to 28-bit if it is not used.
/// Returns `Error::InvalidArgument` if providing a value that does not fit in 28 bits.
pub fn set_frequency(
&mut self,
register: FrequencyRegister,
value: u32,
) -> Result<(), Error<E>> {
Self::check_value_fits(value, 28)?;
let control = self.control.with_high(BitFlags::B28);
self.write_control_if_different(control)?;
let lsb = value & ((1 << 14) - 1);
let msb = value >> 14;
let reg = Self::get_freq_register_bits(register);
self.write(reg | lsb as u16)?;
self.write(reg | msb as u16)
}

fn get_freq_register_bits(register: FrequencyRegister) -> u16 {
match register {
FrequencyRegister::F0 => BitFlags::D14,
FrequencyRegister::F1 => BitFlags::D15,
}
}

/// Set the frequency 14-bit MSBs
///
/// This will deactivate the 28-bit mode if it is not already the case.
/// Returns `Error::InvalidArgument` if providing a value that does not fit in 14 bits.
pub fn set_frequency_msb(
&mut self,
register: FrequencyRegister,
value: u16,
) -> Result<(), Error<E>> {
Self::check_value_fits(value, 14)?;
let control = self
.control
.with_low(BitFlags::B28)
.with_high(BitFlags::HLB);
self.write_control_if_different(control)?;
let reg = Self::get_freq_register_bits(register);
self.write(reg | value as u16)
}

/// Set the frequency 14-bit LSBs
///
/// This will deactivate the 28-bit mode if it is not already the case.
/// Returns `Error::InvalidArgument` if providing a value that does not fit in 14 bits.
pub fn set_frequency_lsb(
&mut self,
register: FrequencyRegister,
value: u16,
) -> Result<(), Error<E>> {
Self::check_value_fits(value, 14)?;
let control = self.control.with_low(BitFlags::B28).with_low(BitFlags::HLB);
self.write_control_if_different(control)?;
let reg = Self::get_freq_register_bits(register);
self.write(reg | value as u16)
}

/// Select the frequency register that is used
///
/// Note: this can be overriden through the FSELECT pin in AD9834/AD9838
/// devices if hardware pin control source is selected.
pub fn select_frequency(&mut self, register: FrequencyRegister) -> Result<(), Error<E>> {
let control = match register {
FrequencyRegister::F0 => self.control.with_low(BitFlags::FSELECT),
FrequencyRegister::F1 => self.control.with_high(BitFlags::FSELECT),
};
self.write_control(control)
}

/// Set a phase register (12-bit value)
///
/// Returns `Error::InvalidArgument` if providing a value that does not fit in 12 bits.
pub fn set_phase(&mut self, register: PhaseRegister, value: u16) -> Result<(), Error<E>> {
Self::check_value_fits(value, 12)?;
let value = value | BitFlags::D14 | BitFlags::D15;
let value = match register {
PhaseRegister::P0 => value,
PhaseRegister::P1 => value | BitFlags::D13,
};
self.write(value)
}

/// Select the phase register that is used.
///
/// Note: this can be overriden through the PSELECT pin in AD9834/AD9838
/// devices if hardware pin control source is selected.
pub fn select_phase(&mut self, register: PhaseRegister) -> Result<(), Error<E>> {
let control = match register {
PhaseRegister::P0 => self.control.with_low(BitFlags::PSELECT),
PhaseRegister::P1 => self.control.with_high(BitFlags::PSELECT),
};
self.write_control(control)
}

/// Set device parts powered-down state.
///
/// Note: This can be overriden through the SLEEP pin
/// in AD9834/AD9838 devices if hardware pin control source is selected.
pub fn set_powered_down(&mut self, config: PoweredDown) -> Result<(), Error<E>> {
let control = match config {
PoweredDown::Nothing => self
.control
.with_low(BitFlags::SLEEP_MCLK)
.with_low(BitFlags::SLEEP_DAC),
PoweredDown::Dac => self
.control
.with_low(BitFlags::SLEEP_MCLK)
.with_high(BitFlags::SLEEP_DAC),
PoweredDown::InternalClock => self
.control
.with_high(BitFlags::SLEEP_MCLK)
.with_low(BitFlags::SLEEP_DAC),
PoweredDown::DacAndInternalClock => self
.control
.with_high(BitFlags::SLEEP_MCLK)
.with_high(BitFlags::SLEEP_DAC),
};
self.write_control(control)
}

pub(crate) fn write_control_if_different(&mut self, control: Config) -> Result<(), Error<E>> {
if control != self.control {
self.write_control(control)
} else {
Ok(())
}
}

pub(crate) fn write_control(&mut self, control: Config) -> Result<(), Error<E>> {
let payload = control.bits & 0b0011_1111_1111_1111;
self.write(payload)?;
self.control = control;
Ok(())
}

pub(crate) fn write(&mut self, payload: u16) -> Result<(), Error<E>> {
self.iface.cs.set_low();
let result = self
.iface
.spi
.write(&[(payload >> 8) as u8, payload as u8])
.map_err(Error::Spi);
self.iface.cs.set_high();
result
}
}
Loading

0 comments on commit 868cb47

Please sign in to comment.