diff --git a/crates/ads126x/src/lib.rs b/crates/ads126x/src/lib.rs index 16816d0..b646dbf 100644 --- a/crates/ads126x/src/lib.rs +++ b/crates/ads126x/src/lib.rs @@ -5,11 +5,22 @@ mod error; mod register; use error::ADS126xError; -use register::{Register, IdRegister, PowerRegister, InterfaceRegister}; +use register::{ + IdRegister, + InterfaceRegister, + Mode0Register, + Mode1Register, + Mode2Register, + PowerRegister, + Register +}; use embedded_hal::spi::FullDuplex; use heapless::Vec; +/// The [`Result`] type for ADS126x operations. +pub type Result = core::result::Result; + pub struct ADS126x where SPI: FullDuplex, @@ -44,7 +55,7 @@ where Self { spi } } - pub fn send_command(&mut self, command: ADCCommand) -> Result<(), ADS126xError> { + pub fn send_command(&mut self, command: ADCCommand) -> Result<()> { let (opcode1, opcode2) = match command { ADCCommand::NOP => (0x00, None), ADCCommand::RESET => (0x06, None), @@ -72,8 +83,8 @@ where } /// Reads data from multiple registers starting at the provided register. - /// To read a single register, see [read_register](ADS126x::read_register). - pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result, ADS126xError> { + /// To read a single register, see [`ADS126x::read_register`]. + pub fn read_multiple_registers(&mut self, reg: Register, num: u8) -> Result> { if num > 27 { return Err(ADS126xError::InvalidInputData); } @@ -88,8 +99,8 @@ where } /// Reads data from only the single provided register. - /// To read multiple registers, see [read_multiple_registers](ADS126x::read_multiple_registers). - pub fn read_register(&mut self, reg: Register) -> Result { + /// To read multiple registers, see [`ADS126x::read_multiple_registers`]. + pub fn read_register(&mut self, reg: Register) -> Result { // zero since number of registers read - 1, so 1-1=0. self.send_command(ADCCommand::RREG(reg, 0))?; let data = self.spi.read().map_err(|_| ADS126xError::IO)?; @@ -97,8 +108,8 @@ where } /// Writes data to multiple registers starting at the provided register. - /// To write data to a single register, see [write_register](ADS126x::write_register). - pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<(), ADS126xError> { + /// To write data to a single register, see [`ADS126x::write_register`]. + pub fn write_multiple_registers(&mut self, reg: Register, data: &[u8]) -> Result<()> { if data.len() > 27 { return Err(ADS126xError::InvalidInputData); } @@ -110,13 +121,13 @@ where } /// Writes data to only the single provided register. - /// To write data to multiple registers, see [write_multiple_registers](ADS126x::write_multiple_registers). - pub fn write_register(&mut self, reg: Register, data: u8) -> Result<(), ADS126xError> { + /// To write data to multiple registers, see [`ADS126x::write_multiple_registers`]. + pub fn write_register(&mut self, reg: Register, data: u8) -> Result<()> { self.send_command(ADCCommand::WREG(reg, 0))?; self.spi.send(data).map_err(|_| ADS126xError::IO) } - pub fn get_id(&mut self) -> Result { + pub fn get_id(&mut self) -> Result { let bits = self.read_register(Register::ID)?; let data = IdRegister::from_bits(bits); match data { @@ -125,7 +136,7 @@ where } } - pub fn get_power(&mut self) -> Result { + pub fn get_power(&mut self) -> Result { let bits = self.read_register(Register::POWER)?; let data = PowerRegister::from_bits(bits); match data { @@ -134,11 +145,11 @@ where } } - pub fn set_power(&mut self, reg: &PowerRegister) -> Result<(), ADS126xError> { + pub fn set_power(&mut self, reg: &PowerRegister) -> Result<()> { self.write_register(Register::POWER, reg.bits()) } - pub fn get_interface(&mut self) -> Result { + pub fn get_interface(&mut self) -> Result { let bits = self.read_register(Register::INTERFACE)?; let data = InterfaceRegister::from_bits(bits); match data { @@ -147,7 +158,46 @@ where } } - pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<(), ADS126xError> { + pub fn set_interface(&mut self, reg: &InterfaceRegister) -> Result<()> { self.write_register(Register::INTERFACE, reg.bits()) } + + pub fn get_mode0(&mut self) -> Result { + let bits = self.read_register(Register::MODE0)?; + let data = Mode0Register::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_mode0(&mut self, reg: &Mode0Register) -> Result<()> { + self.write_register(Register::MODE0, reg.bits()) + } + + pub fn get_mode1(&mut self) -> Result { + let bits = self.read_register(Register::MODE1)?; + let data = Mode1Register::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_mode1(&mut self, reg: &Mode1Register) -> Result<()> { + self.write_register(Register::MODE1, reg.bits()) + } + + pub fn get_mode2(&mut self) -> Result { + let bits = self.read_register(Register::MODE2)?; + let data = Mode2Register::from_bits(bits); + match data { + Some(reg) => Ok(reg), + None => Err(ADS126xError::InvalidInputData), + } + } + + pub fn set_mode2(&mut self, reg: &Mode2Register) -> Result<()> { + self.write_register(Register::MODE2, reg.bits()) + } } diff --git a/crates/ads126x/src/register.rs b/crates/ads126x/src/register.rs index fc2df66..ae2fb64 100644 --- a/crates/ads126x/src/register.rs +++ b/crates/ads126x/src/register.rs @@ -1,3 +1,6 @@ +mod enums; + +pub use enums::*; use bitflags::bitflags; #[repr(u8)] @@ -84,11 +87,6 @@ bitflags! { } } -pub enum DevId { - ADS1262 = 0b000, - ADS1263 = 0b001, -} - impl IdRegister { pub fn get_rev_id(&self) -> u8 { self.bits() & 0b0001_1111 @@ -121,3 +119,161 @@ bitflags! { const TIMEOUT = 0b0000_1000; } } + +bitflags! { + pub struct Mode0Register: u8 { + const RUNMODE = 0b0100_0000; + const REFREV = 0b1000_0000; + + const _ = !0; // Source may set any bits + } +} + +impl Mode0Register { + pub fn get_delay(&self) -> ConversionDelay { + match self.bits() & 0b0000_1111 { + 0b0000 => ConversionDelay::DNone, + 0b0001 => ConversionDelay::D8_7us, + 0b0010 => ConversionDelay::D17us, + 0b0011 => ConversionDelay::D35us, + 0b0100 => ConversionDelay::D69us, + 0b0101 => ConversionDelay::D139us, + 0b0110 => ConversionDelay::D278us, + 0b0111 => ConversionDelay::D555us, + 0b1000 => ConversionDelay::D1_1ms, + 0b1001 => ConversionDelay::D2_2ms, + 0b1010 => ConversionDelay::D4_4ms, + 0b1011 => ConversionDelay::D8_8ms, + + 0b1100..=0b1111 => panic!("Unknown conversion delay"), + _ => unreachable!(), + } + } + + pub fn set_delay(&mut self, delay: ConversionDelay) { + let bits = delay as u8; + self.insert(Mode0Register::from_bits_retain(bits)); + } + + pub fn get_chop(&self) -> ChopMode { + match (self.bits() & 0b0011_0000) >> 4 { + 0b00 => ChopMode::Disabled, + 0b01 => ChopMode::InChopEnabled, + 0b10 => ChopMode::IdacEnabled, + 0b11 => ChopMode::InChopAndIdacEnabled, + + _ => unreachable!(), + } + } + + pub fn set_chop(&mut self, chop: ChopMode) { + let bits = chop as u8; + self.insert(Mode0Register::from_bits_retain(bits << 4)); + } +} + +bitflags! { + pub struct Mode1Register: u8 { + const SBPOL = 0b0000_1000; + const SBADC = 0b0001_0000; + + const _ = !0; // Source may set any bits + } +} + +impl Mode1Register { + pub fn get_sbmag(&self) -> SensorBiasMagnitude { + match self.bits() & 0b0000_0111 { + 0b000 => SensorBiasMagnitude::BNone, + 0b001 => SensorBiasMagnitude::B0_5uA, + 0b010 => SensorBiasMagnitude::B2uA, + 0b011 => SensorBiasMagnitude::B10uA, + 0b100 => SensorBiasMagnitude::B50uA, + 0b101 => SensorBiasMagnitude::B200uA, + 0b110 => SensorBiasMagnitude::R10MOhm, + + 0b111 => panic!("Reserved SBMAG"), + _ => unreachable!() + } + } + + pub fn set_sbmag(&mut self, sbmag: SensorBiasMagnitude) { + let bits = sbmag as u8; + self.insert(Mode1Register::from_bits_retain(bits)); + } + + pub fn get_filter(&self) -> DigitalFilter { + match (self.bits() & 0b1110_0000) >> 5 { + 0b000 => DigitalFilter::Sinc1, + 0b001 => DigitalFilter::Sinc2, + 0b010 => DigitalFilter::Sinc3, + 0b011 => DigitalFilter::Sinc4, + 0b100 => DigitalFilter::FIR, + + 0b101..=0b111 => panic!("Reserved filter"), + _ => unreachable!() + } + } + + pub fn set_filter(&mut self, filter: DigitalFilter) { + let bits = filter as u8; + self.insert(Mode1Register::from_bits_retain(bits << 5)); + } +} + +bitflags! { + pub struct Mode2Register: u8 { + const BYPASS = 0b1000_0000; + + const _ = !0; // Source may set any bits + } +} + +impl Mode2Register { + pub fn get_dr(&self) -> DataRate { + match self.bits() & 0b0000_1111 { + 0b0000 => DataRate::SPS2_5, + 0b0001 => DataRate::SPS5, + 0b0010 => DataRate::SPS10, + 0b0011 => DataRate::SPS16_6, + 0b0100 => DataRate::SPS20, + 0b0101 => DataRate::SPS50, + 0b0110 => DataRate::SPS60, + 0b0111 => DataRate::SPS100, + 0b1000 => DataRate::SPS400, + 0b1001 => DataRate::SPS1200, + 0b1010 => DataRate::SPS2400, + 0b1011 => DataRate::SPS4800, + 0b1100 => DataRate::SPS7200, + 0b1101 => DataRate::SPS14400, + 0b1110 => DataRate::SPS19200, + 0b1111 => DataRate::SPS38400, + + _ => unreachable!() + } + } + + pub fn set_dr(&mut self, rate: DataRate) { + let bits = rate as u8; + self.insert(Mode2Register::from_bits_retain(bits)); + } + + pub fn get_gain(&self) -> PGAGain { + match (self.bits() & 0b0111_0000) >> 4 { + 0b000 => PGAGain::VV1, + 0b001 => PGAGain::VV2, + 0b010 => PGAGain::VV4, + 0b011 => PGAGain::VV8, + 0b100 => PGAGain::VV16, + 0b101 => PGAGain::VV32, + + 0b110 | 0b111 => panic!("Reserved gain"), + _ => unreachable!() + } + } + + pub fn set_gain(&mut self, gain: PGAGain) { + let bits = gain as u8; + self.insert(Mode2Register::from_bits_retain(bits << 4)); + } +} diff --git a/crates/ads126x/src/register/enums.rs b/crates/ads126x/src/register/enums.rs new file mode 100644 index 0000000..5ef296d --- /dev/null +++ b/crates/ads126x/src/register/enums.rs @@ -0,0 +1,112 @@ +pub enum DevId { + ADS1262 = 0b000, + ADS1263 = 0b001, +} + +/// Conversion delays follow the pattern `D`. +/// - `len` is the length of time where _ is a substitute for a decimal point. +/// - `units` are the units of time where us is microseconds and ms is milliseconds. +/// +/// D8_7us = delay of 8.7 microseconds. D8_8ms = delay of 8.8 milliseconds. +#[repr(u8)] +pub enum ConversionDelay { + DNone = 0b0000, + D8_7us = 0b0001, + D17us = 0b0010, + D35us = 0b0011, + D69us = 0b0100, + D139us = 0b0101, + D278us = 0b0110, + D555us = 0b0111, + D1_1ms = 0b1000, + D2_2ms = 0b1001, + D4_4ms = 0b1010, + D8_8ms = 0b1011, +} + +impl ConversionDelay { + /// Returns the delay in nanoseconds. + pub fn delay(&self) -> u32 { + match self { + Self::DNone => 0, + Self::D8_7us => 8_700, + Self::D17us => 17_000, + Self::D35us => 35_000, + Self::D69us => 69_000, + Self::D139us => 139_000, + Self::D278us => 278_000, + Self::D555us => 555_000, + Self::D1_1ms => 1_100_000, + Self::D2_2ms => 2_200_000, + Self::D4_4ms => 4_400_000, + Self::D8_8ms => 8_800_000, + } + } +} + +#[repr(u8)] +pub enum ChopMode { + Disabled = 0b00, + InChopEnabled = 0b01, + IdacEnabled = 0b10, + InChopAndIdacEnabled = 0b11, +} + +/// SBMAGs follow the pattern `B` or `R`. +/// - `mag` is the magnitude of current or resistance where _ is a substitute for a decimal point. +/// - `units` are the units of current or resistance where uA is microamperes and MOhm is megaohms. +/// +/// B0_5uA = 0.5 microamps of current. R10MOhm = resistance of 10 megaohms. +#[repr(u8)] +pub enum SensorBiasMagnitude { + BNone = 0b000, + B0_5uA = 0b001, + B2uA = 0b010, + B10uA = 0b011, + B50uA = 0b100, + B200uA = 0b101, + R10MOhm = 0b110, +} + +#[repr(u8)] +pub enum DigitalFilter { + Sinc1 = 0b000, + Sinc2 = 0b001, + Sinc3 = 0b010, + Sinc4 = 0b011, + FIR = 0b100, +} + +/// Data rates follow the pattern `SPS`. +/// - `num` is the SPS rate where _ is a substitute for a decimal point. +/// +/// SPS2_5 = 2.5 SPS. +#[repr(u8)] +pub enum DataRate { + SPS2_5 = 0b0000, + SPS5 = 0b0001, + SPS10 = 0b0010, + SPS16_6 = 0b0011, // 16.6666... = 50/3 + SPS20 = 0b0100, + SPS50 = 0b0101, + SPS60 = 0b0110, + SPS100 = 0b0111, + SPS400 = 0b1000, + SPS1200 = 0b1001, + SPS2400 = 0b1010, + SPS4800 = 0b1011, + SPS7200 = 0b1100, + SPS14400 = 0b1101, + SPS19200 = 0b1110, + SPS38400 = 0b1111, +} + +#[repr(u8)] +pub enum PGAGain { + VV1 = 0b000, + VV2 = 0b001, + VV4 = 0b010, + VV8 = 0b011, + VV16 = 0b100, + VV32 = 0b101, +}