#![no_std]
use bit_field::BitField;
use bitflags::bitflags;
use embedded_hal::{blocking::delay::DelayUs, digital::v2::OutputPin};
pub struct Ad9959<INTERFACE> {
interface: INTERFACE,
reference_clock_frequency: f32,
system_clock_multiplier: u8,
communication_mode: Mode,
}
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>;
}
#[derive(Copy, Clone, PartialEq, Eq)]
#[repr(u8)]
pub enum Mode {
SingleBitTwoWire = 0b000,
SingleBitThreeWire = 0b010,
TwoBitSerial = 0b100,
FourBitSerial = 0b110,
}
bitflags! {
pub struct Channel: u8 {
const ONE = 0b00010000;
const TWO = 0b00100000;
const THREE = 0b01000000;
const FOUR = 0b10000000;
const ALL = Self::ONE.bits() | Self::TWO.bits() | Self::THREE.bits() | Self::FOUR.bits();
}
}
#[allow(clippy::upper_case_acronyms)]
#[repr(u8)]
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,
}
#[derive(Debug)]
pub enum Error {
Interface,
Check,
Bounds,
Pin,
Frequency,
}
impl<I: Interface> Ad9959<I> {
pub fn new(
interface: I,
mut reset_pin: impl OutputPin,
io_update: &mut impl OutputPin,
delay: &mut impl DelayUs<u8>,
desired_mode: Mode,
clock_frequency: f32,
multiplier: u8,
) -> Result<Self, Error> {
let mut ad9959 = Ad9959 {
interface,
reference_clock_frequency: clock_frequency,
system_clock_multiplier: 1,
communication_mode: desired_mode,
};
io_update.set_low().or(Err(Error::Pin))?;
reset_pin.set_high().or(Err(Error::Pin))?;
delay.delay_us(5);
reset_pin.set_low().or(Err(Error::Pin))?;
ad9959
.interface
.configure_mode(Mode::SingleBitTwoWire)
.or(Err(Error::Interface))?;
let csr = [Channel::ALL.bits() | desired_mode as u8];
ad9959.write(Register::CSR, &csr)?;
io_update.set_high().or(Err(Error::Pin))?;
delay.delay_us(5);
io_update.set_low().or(Err(Error::Pin))?;
ad9959
.interface
.configure_mode(desired_mode)
.or(Err(Error::Interface))?;
delay.delay_us(5);
let mut updated_csr: [u8; 1] = [0];
ad9959.read(Register::CSR, &mut updated_csr)?;
if updated_csr[0] != csr[0] {
return Err(Error::Check);
}
ad9959.configure_system_clock(clock_frequency, multiplier)?;
io_update.set_high().or(Err(Error::Pin))?;
delay.delay_us(5);
io_update.set_low().or(Err(Error::Pin))?;
Ok(ad9959)
}
fn read(&mut self, reg: Register, data: &mut [u8]) -> Result<(), Error> {
self.interface
.read(reg as u8, data)
.or(Err(Error::Interface))
}
fn write(&mut self, reg: Register, data: &[u8]) -> Result<(), Error> {
self.interface
.write(reg as u8, data)
.or(Err(Error::Interface))
}
fn configure_system_clock(
&mut self,
reference_clock_frequency: f32,
multiplier: u8,
) -> Result<f32, Error> {
self.reference_clock_frequency = reference_clock_frequency;
if multiplier != 1 && !(4..=20).contains(&multiplier) {
return Err(Error::Bounds);
}
let frequency = multiplier as f32 * self.reference_clock_frequency;
if frequency > 500_000_000.0f32 {
return Err(Error::Frequency);
}
let mut fr1: [u8; 3] = [0, 0, 0];
self.read(Register::FR1, &mut fr1)?;
fr1[0].set_bits(2..=6, multiplier);
let vco_range = frequency > 255e6;
fr1[0].set_bit(7, vco_range);
self.write(Register::FR1, &fr1)?;
self.system_clock_multiplier = multiplier;
Ok(self.system_clock_frequency())
}
pub fn get_reference_clock_frequency(&self) -> f32 {
self.reference_clock_frequency
}
pub fn get_reference_clock_multiplier(&mut self) -> Result<u8, Error> {
let mut fr1: [u8; 3] = [0, 0, 0];
self.read(Register::FR1, &mut fr1)?;
Ok(fr1[0].get_bits(2..=6))
}
pub fn self_test(&mut self) -> Result<bool, Error> {
let mut csr: [u8; 1] = [0];
self.read(Register::CSR, &mut csr)?;
let old_csr = csr[0];
csr[0].set_bits(4..8, 0xF);
self.write(Register::CSR, &csr)?;
csr[0] = 0;
self.read(Register::CSR, &mut csr)?;
if csr[0].get_bits(4..8) != 0xF {
return Ok(false);
}
csr[0].set_bits(4..8, 0x0);
self.write(Register::CSR, &csr)?;
csr[0] = 0xFF;
self.read(Register::CSR, &mut csr)?;
if csr[0].get_bits(4..8) != 0 {
return Ok(false);
}
csr[0] = old_csr;
self.write(Register::CSR, &csr)?;
Ok(true)
}
fn system_clock_frequency(&self) -> f32 {
self.system_clock_multiplier as f32 * self.reference_clock_frequency
}
fn modify_channel(
&mut self,
channel: Channel,
register: Register,
data: &[u8],
) -> Result<(), Error> {
let csr = [self.communication_mode as u8 | channel.bits()];
self.write(Register::CSR, &csr)?;
self.write(register, data)?;
Ok(())
}
fn read_channel(
&mut self,
channel: Channel,
register: Register,
data: &mut [u8],
) -> Result<(), Error> {
let mut csr = [0];
self.read(Register::CSR, &mut csr)?;
let new_csr = [self.communication_mode as u8 | channel.bits()];
self.write(Register::CSR, &new_csr)?;
self.read(register, data)?;
self.write(Register::CSR, &csr)?;
Ok(())
}
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))
}
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))
}
pub fn set_amplitude(
&mut self,
channel: Channel,
amplitude: f32,
) -> Result<f32, Error> {
if !(0.0..=1.0).contains(&litude) {
return Err(Error::Bounds);
}
let amplitude_control: u16 = (amplitude * (1 << 10) as f32) as u16;
let mut acr: [u8; 3] = [0; 3];
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];
acr[1].set_bit(4, true);
}
self.modify_channel(channel, Register::ACR, &acr)?;
Ok(amplitude_control as f32 / (1 << 10) as f32)
}
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) {
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)
}
}
pub fn set_frequency(
&mut self,
channel: Channel,
frequency: f32,
) -> Result<f32, Error> {
if frequency < 0.0 || frequency > self.system_clock_frequency() {
return Err(Error::Bounds);
}
let tuning_word: u32 = ((frequency / self.system_clock_frequency())
* 1u64.wrapping_shl(32) as f32)
as u32;
self.modify_channel(
channel,
Register::CFTW0,
&tuning_word.to_be_bytes(),
)?;
Ok((tuning_word as f32 / 1u64.wrapping_shl(32) as f32)
* self.system_clock_frequency())
}
pub fn get_frequency(&mut self, channel: Channel) -> Result<f32, Error> {
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);
Ok((tuning_word as f32 * self.system_clock_frequency())
/ (1u64 << 32) as f32)
}
pub fn freeze(self) -> (I, Mode) {
(self.interface, self.communication_mode)
}
}
pub struct ProfileSerializer {
data: [u8; 32],
index: usize,
mode: u32,
}
impl ProfileSerializer {
pub fn new(mode: Mode) -> Self {
Self {
mode: mode as _,
data: [0; 32],
index: 0,
}
}
#[inline]
pub fn update_channels(
&mut self,
channels: Channel,
ftw: Option<u32>,
pow: Option<u16>,
acr: Option<u32>,
) {
let csr = [self.mode as u8 | channels.bits()];
self.add_write(Register::CSR, &csr);
if let Some(ftw) = ftw {
self.add_write(Register::CFTW0, &ftw.to_be_bytes());
}
if let Some(pow) = pow {
self.add_write(Register::CPOW0, &pow.to_be_bytes());
}
if let Some(acr) = acr {
self.add_write(Register::ACR, &acr.to_be_bytes()[1..]);
}
}
fn add_write(&mut self, register: Register, value: &[u8]) {
let data = &mut self.data[self.index..];
data[0] = register as u8;
data[1..][..value.len()].copy_from_slice(value);
self.index += value.len() + 1;
}
#[inline]
fn pad(&mut self) {
if self.index & 1 != 0 {
self.add_write(Register::LSRR, &[0, 0]);
}
if self.index & 2 != 0 {
self.add_write(Register::CSR, &[self.mode as _]);
}
debug_assert_eq!(self.index & 3, 0);
}
#[inline]
pub fn finalize(&mut self) -> &[u32] {
self.pad();
bytemuck::cast_slice(&self.data[..self.index])
}
}