ad7124_rs/
registers.rs

1//! Register definitions and configuration structures for AD7124
2//!
3//! Provides type-safe register access and bit manipulation
4
5/// AD7124 register addresses
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u8)]
8pub enum Register {
9    /// Status register (read-only)
10    Status = 0x00,
11    /// ADC control register
12    AdcCtrl = 0x01,
13    /// Data register (read-only)
14    Data = 0x02,
15    /// IO control register 1
16    IoCtrl1 = 0x03,
17    /// IO control register 2
18    IoCtrl2 = 0x04,
19    /// Device ID register (read-only)
20    Id = 0x05,
21    /// Error register (read-only)
22    Error = 0x06,
23    /// Error enable register
24    ErrorEn = 0x07,
25    /// MCLK count register (read-only)
26    MclkCount = 0x08,
27    /// Channel 0 configuration
28    Channel0 = 0x09,
29    /// Channel 1 configuration
30    Channel1 = 0x0A,
31    /// Channel 2 configuration
32    Channel2 = 0x0B,
33    /// Channel 3 configuration
34    Channel3 = 0x0C,
35    /// Channel 4 configuration (AD7124-8 only)
36    Channel4 = 0x0D,
37    /// Channel 5 configuration (AD7124-8 only)
38    Channel5 = 0x0E,
39    /// Channel 6 configuration (AD7124-8 only)
40    Channel6 = 0x0F,
41    /// Channel 7 configuration (AD7124-8 only)
42    Channel7 = 0x10,
43    /// Configuration 0 register
44    Config0 = 0x19,
45    /// Configuration 1 register
46    Config1 = 0x1A,
47    /// Configuration 2 register
48    Config2 = 0x1B,
49    /// Configuration 3 register
50    Config3 = 0x1C,
51    /// Configuration 4 register
52    Config4 = 0x1D,
53    /// Configuration 5 register
54    Config5 = 0x1E,
55    /// Configuration 6 register
56    Config6 = 0x1F,
57    /// Configuration 7 register
58    Config7 = 0x20,
59    /// Filter 0 register
60    Filter0 = 0x21,
61    /// Filter 1 register
62    Filter1 = 0x22,
63    /// Filter 2 register
64    Filter2 = 0x23,
65    /// Filter 3 register
66    Filter3 = 0x24,
67    /// Filter 4 register
68    Filter4 = 0x25,
69    /// Filter 5 register
70    Filter5 = 0x26,
71    /// Filter 6 register
72    Filter6 = 0x27,
73    /// Filter 7 register
74    Filter7 = 0x28,
75    /// Offset 0 register
76    Offset0 = 0x29,
77    /// Offset 1 register
78    Offset1 = 0x2A,
79    /// Offset 2 register
80    Offset2 = 0x2B,
81    /// Offset 3 register
82    Offset3 = 0x2C,
83    /// Offset 4 register
84    Offset4 = 0x2D,
85    /// Offset 5 register
86    Offset5 = 0x2E,
87    /// Offset 6 register
88    Offset6 = 0x2F,
89    /// Offset 7 register
90    Offset7 = 0x30,
91    /// Gain 0 register
92    Gain0 = 0x31,
93    /// Gain 1 register
94    Gain1 = 0x32,
95    /// Gain 2 register
96    Gain2 = 0x33,
97    /// Gain 3 register
98    Gain3 = 0x34,
99    /// Gain 4 register
100    Gain4 = 0x35,
101    /// Gain 5 register
102    Gain5 = 0x36,
103    /// Gain 6 register
104    Gain6 = 0x37,
105    /// Gain 7 register
106    Gain7 = 0x38,
107}
108
109impl Register {
110    /// Get register address as u8
111    pub fn addr(self) -> u8 {
112        self as u8
113    }
114
115    /// Check if register is read-only
116    pub fn is_readonly(self) -> bool {
117        matches!(
118            self,
119            Register::Status
120                | Register::Data
121                | Register::Id
122                | Register::Error
123                | Register::MclkCount
124        )
125    }
126
127    /// Get register size in bytes
128    pub fn size(self) -> u8 {
129        match self {
130            Register::Status => 1,
131            Register::AdcCtrl => 2,
132            Register::Data => 3,
133            Register::IoCtrl1 => 3,
134            Register::IoCtrl2 => 2,
135            Register::Id => 1,
136            Register::Error => 3,
137            Register::ErrorEn => 3,
138            Register::MclkCount => 1,
139            Register::Channel0
140            | Register::Channel1
141            | Register::Channel2
142            | Register::Channel3
143            | Register::Channel4
144            | Register::Channel5
145            | Register::Channel6
146            | Register::Channel7 => 2,
147            Register::Config0
148            | Register::Config1
149            | Register::Config2
150            | Register::Config3
151            | Register::Config4
152            | Register::Config5
153            | Register::Config6
154            | Register::Config7 => 2,
155            Register::Filter0
156            | Register::Filter1
157            | Register::Filter2
158            | Register::Filter3
159            | Register::Filter4
160            | Register::Filter5
161            | Register::Filter6
162            | Register::Filter7 => 3,
163            Register::Offset0
164            | Register::Offset1
165            | Register::Offset2
166            | Register::Offset3
167            | Register::Offset4
168            | Register::Offset5
169            | Register::Offset6
170            | Register::Offset7 => 3,
171            Register::Gain0
172            | Register::Gain1
173            | Register::Gain2
174            | Register::Gain3
175            | Register::Gain4
176            | Register::Gain5
177            | Register::Gain6
178            | Register::Gain7 => 3,
179        }
180    }
181}
182
183/// Operating modes for AD7124
184#[derive(Debug, Clone, Copy, PartialEq, Eq)]
185#[repr(u8)]
186pub enum OperatingMode {
187    /// Continuous conversion mode
188    Continuous = 0,
189    /// Single conversion mode
190    SingleConv = 1,
191    /// Standby mode
192    Standby = 2,
193    /// Power-down mode
194    PowerDown = 3,
195    /// Idle mode
196    Idle = 4,
197    /// Internal zero-scale calibration
198    InternalZeroScale = 5,
199    /// Internal full-scale calibration
200    InternalFullScale = 6,
201    /// System zero-scale calibration
202    SystemZeroScale = 7,
203    /// System full-scale calibration
204    SystemFullScale = 8,
205}
206
207/// Power modes for AD7124
208#[derive(Debug, Clone, Copy, PartialEq, Eq)]
209#[repr(u8)]
210pub enum PowerMode {
211    /// Low power mode
212    LowPower = 0,
213    /// Mid power mode
214    MidPower = 1,
215    /// Full power mode
216    FullPower = 2,
217}
218
219/// Clock source selection
220#[derive(Debug, Clone, Copy, PartialEq, Eq)]
221#[repr(u8)]
222pub enum ClockSource {
223    /// Internal clock (default)
224    Internal = 0,
225    /// Internal clock with output
226    InternalOutput = 1,
227    /// External clock
228    External = 2,
229    /// External clock divided by 4
230    ExternalDiv4 = 3,
231}
232
233/// Reference source selection
234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
235#[repr(u8)]
236pub enum ReferenceSource {
237    /// External reference 1 (REFIN1)  
238    External1 = 0,
239    /// External reference 2 (REFIN2)
240    External2 = 1,
241    /// Internal 2.5V reference - matches C code REF_SEL=2
242    Internal = 2,
243    /// AVDD - AVSS
244    Avdd = 3,
245}
246
247/// Programmable gain amplifier settings
248#[derive(Debug, Clone, Copy, PartialEq, Eq)]
249#[cfg_attr(feature = "defmt", derive(defmt::Format))]
250#[repr(u8)]
251pub enum PgaGain {
252    /// Gain = 1
253    Gain1 = 0,
254    /// Gain = 2
255    Gain2 = 1,
256    /// Gain = 4
257    Gain4 = 2,
258    /// Gain = 8
259    Gain8 = 3,
260    /// Gain = 16
261    Gain16 = 4,
262    /// Gain = 32
263    Gain32 = 5,
264    /// Gain = 64
265    Gain64 = 6,
266    /// Gain = 128
267    Gain128 = 7,
268}
269
270impl PgaGain {
271    /// Create PgaGain from raw bits
272    pub fn from_bits(bits: u8) -> Result<Self, crate::errors::AD7124CoreError> {
273        match bits & 0x07 {
274            0 => Ok(PgaGain::Gain1),
275            1 => Ok(PgaGain::Gain2),
276            2 => Ok(PgaGain::Gain4),
277            3 => Ok(PgaGain::Gain8),
278            4 => Ok(PgaGain::Gain16),
279            5 => Ok(PgaGain::Gain32),
280            6 => Ok(PgaGain::Gain64),
281            7 => Ok(PgaGain::Gain128),
282            _ => Err(crate::errors::AD7124CoreError::InvalidParameter),
283        }
284    }
285
286    /// Get the numerical gain value
287    pub fn value(self) -> u32 {
288        match self {
289            PgaGain::Gain1 => 1,
290            PgaGain::Gain2 => 2,
291            PgaGain::Gain4 => 4,
292            PgaGain::Gain8 => 8,
293            PgaGain::Gain16 => 16,
294            PgaGain::Gain32 => 32,
295            PgaGain::Gain64 => 64,
296            PgaGain::Gain128 => 128,
297        }
298    }
299
300    /// Get the numerical gain value as f32
301    pub fn gain_value(self) -> f32 {
302        self.value() as f32
303    }
304}
305
306/// Burnout current sources
307#[derive(Debug, Clone, Copy, PartialEq, Eq)]
308#[repr(u8)]
309pub enum BurnoutCurrent {
310    /// No burnout current
311    Off = 0,
312    /// 0.5 µA burnout current
313    Current0_5uA = 1,
314    /// 2 µA burnout current
315    Current2uA = 2,
316    /// 4 µA burnout current
317    Current4uA = 3,
318}
319
320/// Digital filter selection
321#[derive(Debug, Clone, Copy, PartialEq, Eq)]
322#[repr(u8)]
323pub enum FilterType {
324    /// SINC4 filter
325    Sinc4 = 0,
326    /// SINC3 filter
327    Sinc3 = 5,
328    /// Fast settling filter
329    FastSettle = 4,
330}
331
332/// Channel input selection
333#[derive(Debug, Clone, Copy, PartialEq, Eq)]
334#[cfg_attr(feature = "defmt", derive(defmt::Format))]
335#[repr(u8)]
336pub enum ChannelInput {
337    /// Analog input 0
338    Ain0 = 0,
339    /// Analog input 1
340    Ain1 = 1,
341    /// Analog input 2
342    Ain2 = 2,
343    /// Analog input 3
344    Ain3 = 3,
345    /// Analog input 4
346    Ain4 = 4,
347    /// Analog input 5
348    Ain5 = 5,
349    /// Analog input 6
350    Ain6 = 6,
351    /// Analog input 7
352    Ain7 = 7,
353    /// Analog input 8
354    Ain8 = 8,
355    /// Analog input 9
356    Ain9 = 9,
357    /// Analog input 10
358    Ain10 = 10,
359    /// Analog input 11
360    Ain11 = 11,
361    /// Analog input 12
362    Ain12 = 12,
363    /// Analog input 13
364    Ain13 = 13,
365    /// Analog input 14
366    Ain14 = 14,
367    /// Analog input 15
368    Ain15 = 15,
369    /// Temperature sensor
370    TempSensor = 16,
371    /// Internal reference
372    IntRef = 17,
373    /// DGND
374    Dgnd = 18,
375    /// (AVDD - AVSS)/5
376    AvddAvssDiv5 = 19,
377}
378
379/// Device status structure
380#[derive(Debug, Clone, Copy, PartialEq, Eq)]
381#[cfg_attr(feature = "defmt", derive(defmt::Format))]
382pub struct DeviceStatus {
383    /// Raw 8-bit status register value
384    pub raw: u8,
385}
386
387impl DeviceStatus {
388    /// Create status from raw register value
389    pub fn new(raw: u8) -> Self {
390        Self { raw }
391    }
392
393    /// Check if ADC is ready for data
394    pub fn rdy(&self) -> bool {
395        (self.raw & 0x80) == 0
396    }
397
398    /// Check for error condition
399    pub fn error(&self) -> bool {
400        (self.raw & 0x40) != 0
401    }
402
403    /// Check for power-on reset
404    pub fn por_flag(&self) -> bool {
405        (self.raw & 0x10) != 0
406    }
407
408    /// Get active channel
409    pub fn channel(&self) -> u8 {
410        self.raw & 0x0F
411    }
412
413    /// Get active channel as Option (None if no channel is active)
414    pub fn active_channel(&self) -> Option<u8> {
415        let ch = self.channel();
416        if ch < 16 {
417            Some(ch)
418        } else {
419            None
420        }
421    }
422
423    /// Check if conversion is ready (non-blocking check)
424    pub fn is_ready(&self) -> bool {
425        self.rdy()
426    }
427
428    /// Check if there's an error
429    pub fn has_error(&self) -> bool {
430        self.error()
431    }
432
433    /// Check if specific channel is ready
434    pub fn is_channel_ready(&self, channel: u8) -> bool {
435        self.is_ready() && self.channel() == channel
436    }
437}
438
439impl core::fmt::Display for DeviceStatus {
440    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
441        write!(f, "Status(0x{:02X})", self.raw)?;
442        if self.rdy() {
443            write!(f, " RDY")?;
444        }
445        if self.error() {
446            write!(f, " ERROR")?;
447        }
448        if self.por_flag() {
449            write!(f, " POR")?;
450        }
451        write!(f, " CH{}", self.channel())?;
452        Ok(())
453    }
454}
455
456/// Bit field manipulation utilities
457pub mod bit_fields {
458    /// Extract bit field from register value
459    pub fn extract_bits(value: u32, offset: u8, width: u8) -> u32 {
460        let mask = (1u32 << width) - 1;
461        (value >> offset) & mask
462    }
463
464    /// Insert bit field into register value
465    pub fn insert_bits(value: u32, field: u32, offset: u8, width: u8) -> u32 {
466        let mask = (1u32 << width) - 1;
467        (value & !(mask << offset)) | ((field & mask) << offset)
468    }
469
470    /// Set single bit
471    pub fn set_bit(value: u32, bit: u8) -> u32 {
472        value | (1 << bit)
473    }
474
475    /// Clear single bit
476    pub fn clear_bit(value: u32, bit: u8) -> u32 {
477        value & !(1 << bit)
478    }
479
480    /// Check if bit is set
481    pub fn is_bit_set(value: u32, bit: u8) -> bool {
482        (value & (1 << bit)) != 0
483    }
484}