#![cfg_attr(not(test), no_std)]
use embedded_hal::{blocking::spi::Write, digital::v2::OutputPin};
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum Channel {
A,
B,
C,
D,
E,
F,
G,
H,
}
impl From<Channel> for u8 {
fn from(chan: Channel) -> Self {
chan as u8
}
}
impl From<u8> for Channel {
fn from(chan: u8) -> Self {
match chan {
0 => Channel::A,
1 => Channel::B,
2 => Channel::C,
3 => Channel::D,
4 => Channel::E,
5 => Channel::F,
6 => Channel::G,
7 => Channel::H,
_ => panic!("Not a valid Ad5328 channel"),
}
}
}
impl Channel {
fn as_u16(&self) -> u16 {
(*self as u16) << 12
}
}
#[derive(Debug)]
pub enum Error<S, P> {
Spi(S),
Pin(P),
Conn,
Address,
Port,
Oob,
}
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum GAIN {
Gain0Vref,
Gain02Vref,
}
impl GAIN {
fn as_u16(&self) -> u16 {
(*self as u16) << 4
}
}
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum BUF {
Unbuffered,
Buffered,
}
impl BUF {
fn as_u16(&self) -> u16 {
(*self as u16) << 2
}
}
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum VDD {
ExternalRef,
VddAsRef,
}
impl VDD {
fn as_u16(&self) -> u16 {
*self as u16
}
}
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum LDAC {
LdacLow,
LdacHigh,
LdacSingleUpdate,
}
impl LDAC {
fn as_u16(&self) -> u16 {
0xa000 | (*self as u16)
}
}
pub struct Ad5328Config {
pub gain: (GAIN, GAIN),
pub buf: (BUF, BUF),
pub vdd: (VDD, VDD),
pub ldac: LDAC,
}
impl Default for Ad5328Config {
fn default() -> Self {
Self {
gain: (GAIN::Gain0Vref, GAIN::Gain0Vref),
buf: (BUF::Buffered, BUF::Buffered),
vdd: (VDD::ExternalRef, VDD::ExternalRef),
ldac: LDAC::LdacHigh,
}
}
}
impl Ad5328Config {
fn as_commands(&self) -> [u16; 2] {
[
0x8000
| self.gain.0.as_u16()
| self.gain.1.as_u16() << 1
| self.buf.0.as_u16()
| self.buf.1.as_u16() << 1
| self.vdd.0.as_u16()
| self.vdd.1.as_u16() << 1,
self.ldac.as_u16(),
]
}
}
pub struct Ad5328<SPI, EN> {
spi: SPI,
enable: EN,
cmd_buf: [u8; 2],
}
impl<SPI, EN, S, P> Ad5328<SPI, EN>
where
SPI: Write<u8, Error = S>,
EN: OutputPin<Error = P>,
{
fn write(&mut self, cmd: u16) -> Result<(), Error<S, P>> {
self.enable.set_low().map_err(Error::Pin)?;
self.cmd_buf[0] = (cmd >> 8) as u8;
self.cmd_buf[1] = (cmd & 0xff) as u8;
self.spi.write(&self.cmd_buf).map_err(Error::Spi)?;
self.enable.set_high().map_err(Error::Pin)?;
Ok(())
}
pub fn init(spi: SPI, enable: EN, config: Ad5328Config) -> Result<Self, Error<S, P>> {
let mut ad5328 = Self {
spi,
enable,
cmd_buf: [0; 2],
};
ad5328.configure(config)?;
Ok(ad5328)
}
pub fn configure(&mut self, config: Ad5328Config) -> Result<(), Error<S, P>> {
for cmd in config.as_commands() {
self.write(cmd)?;
}
Ok(())
}
pub fn reset(&mut self, full_reset: bool) -> Result<(), Error<S, P>> {
let cmd = if full_reset { 0xf000 } else { 0xe000 };
self.write(cmd)?;
Ok(())
}
pub fn power_down(&mut self, channels: [bool; 8]) -> Result<(), Error<S, P>> {
let mut cmd = 0xc000;
for (n, &power_down) in channels.iter().enumerate() {
cmd |= (if power_down { 1 } else { 0 }) << n;
}
self.write(cmd)?;
Ok(())
}
pub fn set_channel(&mut self, channel: Channel, value: u16) -> Result<(), Error<S, P>> {
if value > 4095 {
return Err(Error::Oob);
}
let cmd = channel.as_u16() | value;
self.write(cmd)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
}