Skip to main content

variegated_ads124s08/
lib.rs

1//! # ADS124S08 Embassy Driver
2//!
3//! Embassy-based driver for the Texas Instruments ADS124S08 24-bit precision ADC.
4//! This driver provides async support for SPI communication with the ADS124S08,
5//! suitable for high-precision analog-to-digital conversion in espresso machine
6//! temperature and pressure sensing applications.
7//!
8//! The ADS124S08 is a precision, 24-bit, analog-to-digital converter (ADC) with
9//! 12 single-ended or 6 differential inputs, programmable gain amplifier (PGA),
10//! voltage reference, and two excitation current sources (IDACs).
11//!
12//! ## Usage Example
13//!
14//! ```no_run
15//! use variegated_ads124s08::{ADS124S08, WaitStrategy, PGAGain, ReferenceInput, IDACMagnitude, IDACMux};
16//! 
17//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
18//! # let spi_device = todo!();
19//! # let drdy_pin = todo!();
20//! # let delay = todo!();
21//! // Create the driver with SPI device, DRDY pin, and delay provider
22//! let wait_strategy = WaitStrategy::UseDrdyPin(drdy_pin);
23//! let mut adc = ADS124S08::new(spi_device, wait_strategy, delay);
24//!
25//! // Initialize the device
26//! adc.initialize().await?;
27//!
28//! // Perform a high-level measurement 
29//! let result = adc.measure_input_with_reference_and_pga(
30//!     InputP::AIN0,      // Positive input
31//!     InputN::AIN1,      // Negative input  
32//!     ReferenceInput::REF0P_REF0N,  // Reference
33//!     PGAGain::GAIN16,   // 16x gain
34//!     Some(IDACMagnitude::uA500),   // 500µA excitation current
35//!     IDACMux::AIN0,     // Current output to AIN0
36//! ).await?;
37//!
38//! // Convert to voltage
39//! let voltage = result.to_voltage();
40//! # Ok(())
41//! # }
42//! ```
43//!
44//! See the datasheet in `docs/datasheet.pdf` for complete technical specifications.
45
46#![no_std]
47#![warn(missing_docs)]
48
49/// Register definitions and configuration structures for the ADS124S08
50pub mod registers;
51
52#[cfg(feature = "defmt")]
53use defmt::Format;
54use embedded_hal_async::delay::DelayNs;
55use crate::registers::{Filter, IDACMagnitude, IDACMux, Mode, PGAGain, ReferenceInput, StatusRegisterValue, RegisterAddress, ByteRepresentation, ConfigurationRegisters};
56use embedded_hal::digital::InputPin;
57use embedded_hal::spi::Operation;
58use embedded_hal_async::digital::Wait;
59use embedded_hal_async::spi::SpiDevice;
60use embassy_futures::select::{select, Either};
61
62
63/// Strategy for waiting for data ready signal from the ADS124S08
64pub enum WaitStrategy<INPUT: InputPin + Wait> {
65    /// Use the dedicated DRDY pin to detect when data is ready
66    UseDrdyPin(INPUT),
67    /// Use delay-based polling instead of the DRDY pin
68    Delay
69}
70
71/// ADS124S08 commands as defined in the datasheet
72#[derive(Debug, Clone, Copy)]
73#[cfg_attr(feature = "defmt", derive(Format))]
74pub enum Command {
75    /// No operation
76    NOP,
77    /// Wake up from power-down mode
78    WAKEUP,
79    /// Enter power-down mode
80    POWERDOWN,
81    /// Reset the device
82    RESET,
83    /// Start ADC conversions
84    START,
85    /// Stop ADC conversions
86    STOP,
87    /// System offset calibration
88    SYOCAL,
89    /// System gain calibration
90    SYGCAL,
91    /// Self offset calibration
92    SFOCAL,
93    /// Read conversion data
94    RDATA,
95    /// Read register command
96    RREG { 
97        /// Starting register address
98        address: u8, 
99        /// Number of registers to read minus 1
100        n: u8 
101    },
102    /// Write register command
103    WREG { 
104        /// Starting register address
105        address: u8, 
106        /// Number of registers to write minus 1
107        n: u8 
108    },
109}
110
111impl Command {
112    fn bits(&self) -> (u8, Option<u8>) {
113        match self {
114            Command::NOP => (0b0000_0000, None),
115            Command::WAKEUP => (0b0000_0010, None),
116            Command::POWERDOWN => (0b0000_0100, None),
117            Command::RESET => (0b0000_0110, None),
118            Command::START => (0b0000_1000, None),
119            Command::STOP => (0b0000_1010, None),
120            Command::SYOCAL => (0b0001_0110, None),
121            Command::SYGCAL => (0b0001_0111, None),
122            Command::SFOCAL => (0b0001_1001, None),
123            Command::RDATA => (0b0001_0010, None),
124            Command::RREG { address, n } => (0b0010_0000 | (address & 0b1_1111), Some(n & 0b1_1111)),
125            Command::WREG { address, n } => (0b0100_0000 | (address & 0b1_1111), Some(n & 0b1_1111)),
126        }
127    }
128}
129
130/// Errors that can occur when communicating with the ADS124S08
131#[derive(Debug, Clone, Copy)]
132#[cfg_attr(feature = "defmt", derive(Format))]
133pub enum ADS124S08Error {
134    /// SPI communication error
135    SPIError,
136    /// Timeout occurred while reading data
137    ReadTimeoutError,
138    /// Timeout occurred while writing data
139    WriteTimeoutError,
140    /// Unable to restore previous configuration while handling another error
141    UnableToRestorePreviousConfigurationWhileHandlingError,
142    /// Invalid value read from or written to a register
143    InvalidRegisterValue(RegisterAddress, u8),
144    /// Invalid command sent to device
145    InvalidCommand,
146    /// Operation attempted when not in transaction mode
147    NotInTransaction,
148    /// Configuration readback verification failed
149    ConfigurationReadBackFailed(RegisterAddress)
150}
151
152/// Conversion result from the ADS124S08 ADC
153#[derive(Debug, Copy, Clone)]
154#[cfg_attr(feature = "defmt", derive(Format))]
155pub struct Code {
156    /// Raw 24-bit conversion data as 3 bytes
157    pub data: [u8; 3],
158    /// Reference input used for this conversion
159    pub reference: ReferenceInput,
160    /// Whether the PGA was enabled for this conversion
161    pub pga_enabled: bool,
162    /// PGA gain used for this conversion
163    pub gain: PGAGain,
164    /// IDAC1 magnitude if enabled, None if disabled
165    pub idac1_magnitude: Option<IDACMagnitude>,
166    /// IDAC2 magnitude if enabled, None if disabled
167    pub idac2_magnitude: Option<IDACMagnitude>,
168}
169
170impl Code {
171    /// Create a new Code from raw data and conversion parameters
172    pub fn new(data: [u8; 3], reference: ReferenceInput, pga_enabled: bool, gain: PGAGain, idac1_magnitude: Option<IDACMagnitude>, idac2_magnitude: Option<IDACMagnitude>) -> Self {
173        Code {
174            data,
175            reference,
176            pga_enabled,
177            gain,
178            idac1_magnitude,
179            idac2_magnitude,
180        }
181    }
182
183    /// Create a new Code from a signed 32-bit integer and conversion parameters
184    pub fn from_code(code: i32, reference: ReferenceInput, pga_enabled: bool, gain: PGAGain, idac1_magnitude: Option<IDACMagnitude>, idac2_magnitude: Option<IDACMagnitude>) -> Self {
185        let original: [u8; 4] = code.to_be_bytes();
186        let result: [u8; 3] = original[1..].try_into().unwrap();
187
188        Code {
189            data: result,
190            reference,
191            pga_enabled,
192            gain,
193            idac1_magnitude,
194            idac2_magnitude,
195        }
196    }
197
198    /// Check if the conversion result indicates over full scale
199    pub fn over_fs(&self) -> bool {
200        self.data[0] == 0x7f && self.data[1] == 0xff && self.data[2] == 0xff
201    }
202
203    /// Check if the conversion result indicates below full scale
204    pub fn below_fs(&self) -> bool {
205        self.data[0] == 0x80 && self.data[1] == 0x00 && self.data[2] == 0x00
206    }
207
208    /// Convert the raw data to a signed 32-bit integer
209    pub fn code(&self) -> i32 {
210        let fill = if self.data[0] & 0x80 == 0x80 { 0xff } else { 0x00 };
211
212        i32::from_be_bytes([fill, self.data[0], self.data[1], self.data[2]])
213    }
214
215    /// Convert to voltage using internal 2.5V reference
216    pub fn internally_referenced_voltage(&self) -> f32 {
217        self.externally_referenced_voltage(0.0, 2.5)
218    }
219
220    /// Convert to voltage using external reference voltages
221    pub fn externally_referenced_voltage(&self, v_ref_n: f32, v_ref_p: f32) -> f32 {
222        let code = self.code();
223        let v_ref = v_ref_p - v_ref_n;
224        let gain = if self.pga_enabled { self.gain.value() as f32 } else { 1.0 };
225        let v_per_lsb = (2.0 * v_ref) / (gain * (1 << 24) as f32);
226
227        code as f32 * v_per_lsb
228    }
229
230    /// Convert to resistance using ratiometric measurement with reference resistance
231    pub fn ratiometric_resistance(&self, r_ref: f32) -> f32 {
232        let code = self.code() as f32;
233        let gain = if self.pga_enabled { self.gain.value() as f32 } else { 1.0 };
234        (r_ref * code) / ((1 << 23) as f32 * gain)
235    }
236}
237
238macro_rules! define_read_write_register_ops {
239    ($base_name:ident, $reg:ident, $reg_type:ty) => {
240        paste::item! {
241            // Generate read function name
242            #[allow(dead_code)]
243            #[doc = concat!("Read the ", stringify!($base_name), " register")]
244            pub async fn [<read_ $base_name _reg>]<'a>(&mut self) -> Result<$reg_type, ADS124S08Error>
245             {
246                let bits = self.read_reg(registers::RegisterAddress::$reg).await?;
247                let res = $reg_type::from_bits(bits).ok_or(ADS124S08Error::InvalidRegisterValue(registers::RegisterAddress::$reg, bits));
248                if res.is_ok() {
249                    let d = res.unwrap();
250                    self.read_configuration_registers.$base_name = d.clone();
251                    return Ok(d)
252                }
253
254                res
255            }
256
257            // Generate write function name
258            #[allow(dead_code)]
259            #[doc = concat!("Write the ", stringify!($base_name), " register")]
260            pub async fn [<write_ $base_name _reg>]<'a>(&mut self, value: $reg_type) -> Result<(), ADS124S08Error>
261             {
262                self.write_reg(registers::RegisterAddress::$reg, value.bits()).await?;
263                self.configuration_registers.$base_name = value;
264                self.read_configuration_registers.$base_name = value;
265                Ok(())
266            }
267
268            // Generate swap function name
269            #[allow(dead_code)]
270            #[doc = concat!("Swap the ", stringify!($base_name), " register and return the previous value")]
271            pub async fn [<swap_ $base_name _reg>]<'a>(&mut self, value: $reg_type) -> Result<$reg_type, ADS124S08Error>
272             {
273                let current = self.[<read_ $base_name _reg>]().await?;
274                self.[<write_ $base_name _reg>](value).await?;
275                Ok(current)
276            }
277        }
278    };
279}
280
281macro_rules! define_read_only_register_ops {
282    ($base_name:ident, $reg:ident, $reg_type:ty) => {
283        paste::item! {
284            // Generate read function name
285            #[allow(dead_code)]
286            #[doc = concat!("Read the ", stringify!($base_name), " register")]
287            async fn [<read_ $base_name _reg>]<'a>(&mut self) -> Result<$reg_type, ADS124S08Error>
288             {
289                let bits = self.read_reg(registers::RegisterAddress::$reg).await?;
290                $reg_type::from_bits(bits).ok_or(ADS124S08Error::InvalidRegisterValue(registers::RegisterAddress::$reg, bits))
291            }
292        }
293    };
294}
295
296/// ADS124S08 ADC driver with Embassy async support
297pub struct ADS124S08<SpiDevT: SpiDevice, InputPinT: InputPin + Wait, D: DelayNs> {
298    spi: SpiDevT,
299    wait_strategy: WaitStrategy<InputPinT>,
300    delay: D,
301    configuration_registers: ConfigurationRegisters,
302
303    read_configuration_registers: ConfigurationRegisters,
304}
305
306impl<SpiDevT: SpiDevice, InputPinT: InputPin + Wait, D: DelayNs> ADS124S08<SpiDevT, InputPinT, D> {
307    // High level API
308    /// Create a new ADS124S08 driver instance
309    pub fn new(spi: SpiDevT, wait_strategy: WaitStrategy<InputPinT>, delay: D) -> ADS124S08<SpiDevT, InputPinT, D> {
310        ADS124S08 {
311            spi,
312            wait_strategy,
313            delay,
314            configuration_registers: ConfigurationRegisters::default(),
315            read_configuration_registers: ConfigurationRegisters::default(),
316        }
317    }
318
319    /// Perform a single-ended measurement on the specified input pin
320    pub async fn measure_single_ended<'a>(&mut self, input: registers::Mux, reference_input: ReferenceInput) -> Result<Code, ADS124S08Error>  {
321        // This assumes that AVss is connected to GND, not to a negative voltage, and that AINCOM is connected to 0V
322        let mut config = self.configuration_registers.clone();
323
324        config.inpmux.p = input;
325        config.inpmux.n = registers::Mux::AINCOM;
326        config.pga.enable = false;
327        config.pga.gain = registers::PGAGain::Gain1;
328        config.idacmag.imag = registers::IDACMagnitude::Off;
329        config.idacmux.i2mux = registers::IDACMux::Disconnected;
330        config.idacmux.i1mux = registers::IDACMux::Disconnected;
331        config.refctrl.refsel = reference_input;
332
333        config = self.swap_all_configuration_registers(config).await?;
334
335        let res = self.start_wait_for_drdy_read_and_stop().await;
336        self.swap_all_configuration_registers(config).await?;
337
338        res
339    }
340
341    /// Perform a ratiometric low-side measurement with excitation current
342    pub async fn measure_ratiometric_low_side<'a>(
343        &mut self,
344        input_p: registers::Mux,
345        input_n: registers::Mux,
346        idac1: registers::IDACMux,
347        idac2: registers::IDACMux,
348        reference_input: registers::ReferenceInput,
349        idac_magnitude: registers::IDACMagnitude,
350        gain: registers::PGAGain,
351    ) -> Result<Code, ADS124S08Error>  {
352        // See SBAA275A, 2.3 for schematic
353        // SBAA275A, 2.6 and 2.1 also works, but set idac2 to disconnected
354        let mut config = self.configuration_registers.clone();
355
356        config.inpmux.p = input_p;
357        config.inpmux.n = input_n;
358        config.idacmag.imag = idac_magnitude;
359        config.idacmux.i2mux = idac2;
360        config.idacmux.i1mux = idac1;
361        config.refctrl.n_refp_buf = true;
362        config.refctrl.n_refn_buf = true;
363        config.refctrl.refsel = reference_input;
364        config.refctrl.refcon = registers::InternalVoltageReferenceConfiguration::OnButPowersDown;
365        config.pga.enable = true;
366        config.pga.gain = gain;
367        config.datarate.mode = Mode::Continuous;
368        config.datarate.rate = registers::DataRate::SPS20;
369        config.datarate.filter = Filter::SINC3;
370
371        config = self.swap_all_configuration_registers(config).await?;
372
373        self.start_conversion().await?;
374//        let res = self.read_n_sample_average(10).await;
375        let res = self.start_wait_for_drdy_read_and_stop().await;
376
377        self.swap_all_configuration_registers(config).await?;
378
379        res
380    }
381
382    /// Perform a differential measurement between two input pins
383    pub async fn measure_differential<'a>(
384        &mut self,
385        input_p: registers::Mux,
386        input_n: registers::Mux,
387        reference_input: registers::ReferenceInput,
388        gain: registers::PGAGain,
389    ) -> Result<Code, ADS124S08Error>  {
390        let mut config = self.configuration_registers.clone();
391
392        config.inpmux.p = input_p;
393        config.inpmux.n = input_n;
394        config.pga.enable = gain != PGAGain::Gain1;
395        config.pga.gain = gain;
396        config.idacmag.imag = IDACMagnitude::Off;
397        config.idacmux.i2mux = IDACMux::Disconnected;
398        config.idacmux.i1mux = IDACMux::Disconnected;
399        config.refctrl.refsel = reference_input;
400
401        // Takes around 2 ms
402        config = self.swap_all_configuration_registers(config).await?;
403
404        // This call has about 2 ms of overhead
405        let res = self.start_wait_for_drdy_read_and_stop().await;
406
407        // Takes around 2 ms
408        self.swap_all_configuration_registers(config).await?;
409
410        res
411    }
412
413    /// Read the digital supply voltage (DVDD) divided by 4
414    pub async fn read_dvdd_by_4<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
415        let mut new_config = self.configuration_registers.sys.clone();
416        new_config.sys_mon = registers::SystemMonitorConfiguration::DvddBy4Measurement;
417        new_config.sendstat = true;
418        new_config.crc = true;
419
420        let prev_config = self.swap_sys_reg(
421            new_config
422        ).await?;
423
424        let mut new_refctl = self.configuration_registers.refctrl.clone();
425        new_refctl.refsel = registers::ReferenceInput::Internal;
426        new_refctl.refcon = registers::InternalVoltageReferenceConfiguration::AlwaysOn;
427
428        let prev_refctl = self.swap_refctrl_reg(new_refctl).await?;
429
430        let _curr_cfg_read = self.read_sys_reg().await?;
431        //log::info!("Current SYS: {:?}", curr_cfg_read);
432
433        let res = self.start_wait_for_drdy_and_read().await;
434
435        self.write_sys_reg(prev_config).await?;
436        self.write_refctrl_reg(prev_refctl).await?;
437
438        res
439    }
440
441    /// Read the analog supply voltage (AVDD) minus AVSS divided by 4
442    pub async fn read_avdd_by_4<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
443        let mut new_config = self.configuration_registers.sys.clone();
444        new_config.sys_mon = registers::SystemMonitorConfiguration::AvddMinusAvssBy4Measurement;
445        new_config.sendstat = true;
446        new_config.crc = true;
447
448        let prev_config = self.swap_sys_reg(
449            new_config
450        ).await?;
451
452        let mut new_refctl = self.configuration_registers.refctrl.clone();
453        new_refctl.refsel = registers::ReferenceInput::Internal;
454        new_refctl.refcon = registers::InternalVoltageReferenceConfiguration::AlwaysOn;
455
456        let prev_refctl = self.swap_refctrl_reg(new_refctl).await?;
457
458        let res = self.start_wait_for_drdy_read_and_stop().await;
459
460        self.write_sys_reg(prev_config).await?;
461        self.write_refctrl_reg(prev_refctl).await?;
462
463        res
464    }
465
466
467    /// Read the internal temperature sensor
468    pub async fn read_temperature<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
469        let mut new_config = self.configuration_registers.sys.clone();
470        new_config.sys_mon = registers::SystemMonitorConfiguration::InternalTemperatureSensor;
471        new_config.sendstat = true;
472        new_config.crc = true;
473
474        let prev_config = self.swap_sys_reg(
475            new_config
476        ).await?;
477
478        let mut new_refctl = self.configuration_registers.refctrl.clone();
479        new_refctl.refsel = registers::ReferenceInput::Internal;
480        new_refctl.refcon = registers::InternalVoltageReferenceConfiguration::AlwaysOn;
481
482        let prev_refctl = self.swap_refctrl_reg(new_refctl).await?;
483
484        let res = self.start_wait_for_drdy_read_and_stop().await;
485
486        self.write_sys_reg(prev_config).await?;
487        self.write_refctrl_reg(prev_refctl).await?;
488
489        res
490    }
491
492    /// Read the device identification register
493    pub async fn read_device_id<'a>(&mut self) -> Result<registers::DeviceId, ADS124S08Error>  {
494        self.read_id_reg().await
495    }
496
497    // Lower level API
498    /// Configure the ADC measurement parameters
499    pub async fn configure_measurement<'a>(&mut self, configuration_registers: ConfigurationRegisters) -> Result<(), ADS124S08Error>  {
500        self.configuration_registers = configuration_registers;
501        self.write_modified_configuration_registers_to_device().await
502    }
503
504    /// Start ADC conversions
505    pub async fn start_conversion<'a>(&mut self) -> Result<(), ADS124S08Error>  {
506        self.write_command(Command::START).await
507    }
508
509    /// Stop ADC conversions
510    pub async fn stop_conversion<'a>(&mut self) -> Result<(), ADS124S08Error>  {
511        self.write_command(Command::STOP).await
512    }
513
514    /// Wait for data ready signal and read the conversion result
515    pub async fn wait_for_drdy_and_read<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
516        self.wait_for_drdy().await?;
517        self.read_data().await
518    }
519
520    /// Start conversion, wait for data ready, and read the result
521    pub async fn start_wait_for_drdy_and_read<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
522        self.start_conversion().await?;
523        self.wait_for_drdy().await?;
524        self.read_data().await
525    }
526
527    /// Start conversion, wait for data ready, read result, and stop conversion
528    pub async fn start_wait_for_drdy_read_and_stop<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
529        self.start_conversion().await?;
530        self.wait_for_drdy().await?;
531
532        let d = self.read_data().await?;
533
534        self.stop_conversion().await?;
535
536        Ok(d)
537    }
538
539    /// Read and average multiple samples
540    pub async fn read_n_sample_average<'a>(&mut self, n: i32) -> Result<Code, ADS124S08Error>  {
541        let mut sum = 0;
542
543        for _ in 0..n {
544            self.wait_for_drdy().await?;
545            sum += self.read_data().await?.code();
546        }
547
548        Ok(Code::from_code(sum / n, ReferenceInput::Internal, false, PGAGain::Gain1, None, None))
549    }
550
551    /// Read the current configuration registers from the device
552    pub async fn read_configuration_registers<'a>(&mut self) -> Result<ConfigurationRegisters, ADS124S08Error>  {
553        self.read_configuration_registers_from_device().await?;
554        Ok(self.read_configuration_registers.clone())
555    }
556
557    // Why are you even looking at this?
558
559    /// Wait for the data ready signal
560    pub async fn wait_for_drdy<'a>(&mut self) -> Result<(), ADS124S08Error>  {
561        match &mut self.wait_strategy {
562            WaitStrategy::UseDrdyPin(drdy_input) => {
563                // Use timeout for DRDY pin waiting to prevent infinite hang
564                let timeout_ms = self.configuration_registers.datarate.rate.sample_period_ms() * 3; // 3x sample period timeout
565                let wait_future = drdy_input.wait_for_low();
566                let timeout_future = async {
567                    self.delay.delay_ms(timeout_ms).await;
568                    Err(ADS124S08Error::ReadTimeoutError)
569                };
570                
571                match select(wait_future, timeout_future).await {
572                    Either::First(result) => result.map_err(|_e| ADS124S08Error::SPIError),
573                    Either::Second(timeout_err) => timeout_err,
574                }
575            },
576            // Use delay based on configured sample rate with some margin
577            WaitStrategy::Delay => {
578                let base_period = self.configuration_registers.datarate.rate.sample_period_ms();
579                let margin = core::cmp::max(base_period * 5 / 100, 1); // 5% or 1ms, whichever is larger
580                let delay_ms = base_period + margin;
581                self.delay.delay_ms(delay_ms).await;
582                Ok(())
583            },
584        }
585    }
586
587    async fn swap_all_configuration_registers<'a>(&mut self, configuration_registers: ConfigurationRegisters) -> Result<ConfigurationRegisters, ADS124S08Error>  {
588        let prev = self.configuration_registers.clone();
589        self.configuration_registers = configuration_registers;
590        let res = self.write_modified_configuration_registers_to_device().await;
591
592        if res.is_err() {
593            self.configuration_registers = prev;
594            self.write_all_configuration_registers_to_device().await?;
595            return Err(ADS124S08Error::UnableToRestorePreviousConfigurationWhileHandlingError);
596        }
597
598        Ok(prev)
599    }
600
601    async fn read_configuration_registers_from_device<'a>(&mut self) -> Result<(), ADS124S08Error>  {
602        self.configuration_registers.inpmux = self.read_inpmux_reg().await?;
603        self.configuration_registers.pga = self.read_pga_reg().await?;
604        self.configuration_registers.datarate = self.read_datarate_reg().await?;
605        self.configuration_registers.refctrl = self.read_refctrl_reg().await?;
606        self.configuration_registers.idacmag = self.read_idacmag_reg().await?;
607        self.configuration_registers.idacmux = self.read_idacmux_reg().await?;
608        self.configuration_registers.vbias = self.read_vbias_reg().await?;
609        self.configuration_registers.sys = self.read_sys_reg().await?;
610
611        Ok(())
612    }
613
614    async fn write_all_configuration_registers_to_device<'a>(&mut self) -> Result<(), ADS124S08Error>  {
615        self.write_inpmux_reg(self.configuration_registers.inpmux).await?;
616        self.write_pga_reg(self.configuration_registers.pga).await?;
617        self.write_datarate_reg(self.configuration_registers.datarate).await?;
618        self.write_refctrl_reg(self.configuration_registers.refctrl).await?;
619        self.write_idacmag_reg(self.configuration_registers.idacmag).await?;
620        self.write_idacmux_reg(self.configuration_registers.idacmux).await?;
621        self.write_vbias_reg(self.configuration_registers.vbias).await?;
622        self.write_sys_reg(self.configuration_registers.sys).await?;
623
624        Ok(())
625    }
626
627    async fn write_modified_configuration_registers_to_device<'a>(&mut self) -> Result<(), ADS124S08Error>  {
628        if self.configuration_registers.inpmux != self.read_configuration_registers.inpmux {
629            self.write_inpmux_reg(self.configuration_registers.inpmux).await?;
630        }
631
632        if self.configuration_registers.pga != self.read_configuration_registers.pga {
633            self.write_pga_reg(self.configuration_registers.pga).await?;
634        }
635
636        if self.configuration_registers.datarate != self.read_configuration_registers.datarate {
637            self.write_datarate_reg(self.configuration_registers.datarate).await?;
638        }
639
640        if self.configuration_registers.refctrl != self.read_configuration_registers.refctrl {
641            self.write_refctrl_reg(self.configuration_registers.refctrl).await?;
642        }
643
644        if self.configuration_registers.idacmag != self.read_configuration_registers.idacmag {
645            self.write_idacmag_reg(self.configuration_registers.idacmag).await?;
646        }
647
648        if self.configuration_registers.idacmux != self.read_configuration_registers.idacmux {
649            self.write_idacmux_reg(self.configuration_registers.idacmux).await?;
650        }
651
652        if self.configuration_registers.vbias != self.read_configuration_registers.vbias {
653            self.write_vbias_reg(self.configuration_registers.vbias).await?;
654        }
655
656        if self.configuration_registers.sys != self.read_configuration_registers.sys {
657            self.write_sys_reg(self.configuration_registers.sys).await?;
658        }
659
660        Ok(())
661    }
662
663    define_read_only_register_ops!(id, ID, registers::DeviceId);
664    define_read_only_register_ops!(status, STATUS, registers::StatusRegisterValue);
665    define_read_write_register_ops!(inpmux, INPMUX, registers::InputMultiplexerRegister);
666    define_read_write_register_ops!(pga, PGA, registers::PgaRegister);
667    define_read_write_register_ops!(datarate, DATARATE, registers::DataRateRegister);
668    define_read_write_register_ops!(refctrl, REF, registers::ReferenceControlRegister);
669    define_read_write_register_ops!(idacmag, IDACMAG, registers::IDACMagnitudeRegister);
670    define_read_write_register_ops!(idacmux, IDACMUX, registers::IDACMultiplexerRegister);
671    define_read_write_register_ops!(vbias, VBIAS, registers::SensorBiasingRegister);
672    define_read_write_register_ops!(sys, SYS, registers::SystemControlRegister);
673
674    /// Read conversion data from the ADC
675    pub async fn read_data<'a>(&mut self) -> Result<Code, ADS124S08Error>  {
676        self.write_command(Command::RDATA).await?;
677
678        if self.configuration_registers.sys.sendstat {
679            let mut status_buf = [0x00];
680            self.spi_read(&mut status_buf).await?;
681
682            let _ = StatusRegisterValue::from_bits(status_buf[0]);
683            //log::info!("Status: {:?}", res);
684        }
685
686        let mut data_buf = [0x00; 3];
687        self.spi_read(&mut data_buf).await?;
688
689        //log::info!("Data: 0x{:x} 0x{:x} 0x{:x}", data_buf[0], data_buf[1], data_buf[2]);
690
691        if self.configuration_registers.sys.crc {
692            let mut crc_buf = [0x00];
693            self.spi_read(&mut crc_buf).await?;
694            //log::info!("CRC: 0x{:x}", crc_buf[0])
695        }
696
697        Ok(Code {
698            data: data_buf,
699            reference: self.configuration_registers.refctrl.refsel,
700            pga_enabled: self.configuration_registers.pga.enable,
701            gain: self.configuration_registers.pga.gain,
702            idac1_magnitude: if self.configuration_registers.idacmux.i1mux != IDACMux::Disconnected { Some(self.configuration_registers.idacmag.imag) } else { None },
703            idac2_magnitude: if self.configuration_registers.idacmux.i2mux != IDACMux::Disconnected { Some(self.configuration_registers.idacmag.imag) } else { None },
704        })
705    }
706
707    async fn write_reg<'a>(&mut self, reg: RegisterAddress, value: u8) -> Result<(), ADS124S08Error>  {
708        let command = Command::WREG { address: reg.addr(), n: 0 };
709
710        let (byte0, byte1) = command.bits();
711
712        if byte1.is_some() {
713            self.spi_transaction(&mut [Operation::DelayNs(100000), Operation::Write(&[byte0, byte1.unwrap()]), Operation::Write(&[value]), Operation::DelayNs(100000)]).await.map_err(|_e| ADS124S08Error::SPIError)?;
714        } else {
715            self.spi_transaction(&mut [Operation::DelayNs(100000), Operation::Write(&[byte0]), Operation::Write(&[value]), Operation::DelayNs(100000)]).await.map_err(|_e| ADS124S08Error::SPIError)?;
716        }
717
718        // @fixme Performance measurment workaround
719/*        let read_back = self.read_reg(spi, reg).await?;
720
721        if read_back != value {
722            return Err(ADS124S08Error::ConfigurationReadBackFailed(reg));
723        }*/
724
725        Ok(())
726    }
727
728    async fn read_reg<'a>(&mut self, register: RegisterAddress) -> Result<u8, ADS124S08Error>  {
729        let command = Command::RREG { address: register.addr(), n: 0 };
730        let mut reg_buf = [0x00];
731
732        let (byte0, byte1) = command.bits();
733        
734        if byte1.is_some() {
735            self.spi_transaction(&mut [Operation::DelayNs(100), Operation::Write(&[byte0, byte1.unwrap()]), Operation::Read(&mut reg_buf), Operation::DelayNs(100)]).await.map_err(|_e| ADS124S08Error::SPIError)?;
736        } else {
737            self.spi_transaction(&mut [Operation::DelayNs(100), Operation::Write(&[byte0]), Operation::Read(&mut reg_buf), Operation::DelayNs(100)]).await.map_err(|_e| ADS124S08Error::SPIError)?;
738        }
739
740//        log::info!("Read register: {:?} 0x{:x}", register, reg_buf[0]);
741
742        Ok(reg_buf[0])
743    }
744
745    /// Reset the ADC to its default configuration
746    pub async fn reset<'a>(&mut self) -> Result<(), ADS124S08Error>  {
747        self.write_command(Command::RESET).await?;
748        self.delay.delay_ms(100).await;
749        self.read_configuration_registers_from_device().await?;
750
751        Ok(())
752    }
753
754    async fn write_command<'a>(&mut self, command: Command) -> Result<(), ADS124S08Error>  {
755        let (byte0, byte1) = command.bits();
756
757        if byte1.is_some() {
758            self.spi_write(&[byte0, byte1.unwrap()]).await?;
759        } else {
760            self.spi_write(&[byte0]).await?;
761        }
762
763        //log::info!("Wrote command: {:?} 0x{:x} {:?}", command, byte0, byte1);
764
765        Ok(())
766    }
767    
768    async fn spi_read<'a>(&mut self, buffer: &mut [u8]) -> Result<(), ADS124S08Error>  {
769        let ret = self.spi.transaction(&mut[Operation::DelayNs(100), Operation::Read(buffer), Operation::DelayNs(100)]).await.map_err(|_e| ADS124S08Error::SPIError);
770
771        ret
772
773//        return self.spi.read(buffer).await.map_err(|e| ADS124S08Error::SPIError);
774
775        // @fixme Performance measurment workaround. Make this optional.
776/*
777        let t1 = self.spi.read(buffer);
778        let t2 = async {
779            Timer::after(Duration::from_millis(1)).await;
780        };
781
782        let either = select(t1, t2).await;
783
784        let res = match either {
785            Either::First(p) => p.map_err(|e| ADS124S08Error::SPIError(e)),
786            Either::Second(_) => Err(ADS124S08Error::ReadTimeoutError),
787        };
788
789        res*/
790    }
791
792    async fn spi_write<'a>(&mut self, buffer: &[u8]) -> Result<(), ADS124S08Error>  {
793        let ret = self.spi.transaction(&mut[Operation::DelayNs(100), Operation::Write(buffer), Operation::DelayNs(100)]).await.map_err(|_e| ADS124S08Error::SPIError);
794
795        ret
796
797        //return self.spi.write(buffer).await.map_err(|e| ADS124S08Error::SPIError);
798
799        // @fixme Performance measurment workaround. Make this optional.
800/*        let t1 = self.spi.write(buffer);
801        let t2 = async {
802            Timer::after(Duration::from_millis(1)).await;
803        };
804
805        let either = select(t1, t2).await;
806
807        let res = match either {
808            Either::First(p) => p.map_err(|e| ADS124S08Error::SPIError(e)),
809            Either::Second(_) => Err(ADS124S08Error::ReadTimeoutError),
810        };
811
812        res*/
813    }
814
815    async fn spi_transaction<'a>(&mut self, ops: &mut [Operation<'_, u8>]) -> Result<(), ADS124S08Error>  {
816        let ret = self.spi.transaction(ops).await.map_err(|_e| ADS124S08Error::SPIError);
817
818        ret
819    }
820}