max553x/
lib.rs

1//! Driver for MAX5532/MAX5533/MAX5534/MAX5535 DACs.
2//!
3//! Implemented according to <https://datasheets.maximintegrated.com/en/ds/MAX5532-MAX5535.pdf>.
4#![no_std]
5
6use core::marker::PhantomData;
7
8use embedded_hal::spi::SpiDevice;
9
10/// Marks a DAC in normal operation mode.
11pub enum Normal {}
12
13/// Marks a DAC in standby mode.
14pub enum Standby {}
15
16/// Marks a DAC in shutdown mode.
17pub enum Shutdown {}
18
19const fn command_bytes(control_bits: u8, mut data_bits: u16) -> [u8; 2] {
20  if data_bits > 0b1111_1111_1111 {
21    data_bits = 0b1111_1111_1111
22  }
23
24  [(control_bits << 4) | ((data_bits >> 8) as u8 & 0xf), data_bits as u8]
25}
26
27const fn vref_command_bytes(control_bits: u8, vref: Vref) -> [u8; 2] {
28  [(control_bits << 4) | ((vref as u8) << 2), 0]
29}
30
31macro_rules! impl_into_mode {
32  ($desc:expr, Max5532, Standby, $fn_name:ident, $control_bits:expr) => {
33    // MAX5532 does not have standby mode.
34  };
35  ($desc:expr, Max5533, $mode_ty:ident, $fn_name:ident, $control_bits:expr) => {
36    impl_into_mode!(@with_vref $desc, Max5533, $mode_ty, $fn_name, $control_bits);
37  };
38  ($desc:expr, Max5534, Standby, $fn_name:ident, $control_bits:expr) => {
39    // MAX5534 does not have standby mode.
40  };
41  ($desc:expr, Max5535, $mode_ty:ident, $fn_name:ident, $control_bits:expr) => {
42    impl_into_mode!(@with_vref $desc, Max5535, $mode_ty, $fn_name, $control_bits);
43  };
44  ($desc:expr, $max_ty:ident, $mode_ty:ident, $fn_name:ident, $control_bits:expr) => {
45    /// Enter
46    #[doc = $desc]
47    /// mode.
48    pub fn $fn_name(mut self) -> Result<$max_ty<SPI, $mode_ty>, SPI::Error> {
49      self.spi.write(&command_bytes($control_bits, 0))?;
50      Ok($max_ty { spi: self.spi, _mode: PhantomData })
51    }
52  };
53  (@with_vref $desc:expr, $max_ty:ident, $mode_ty:ident, $fn_name:ident, $control_bits:expr) => {
54    /// Enter
55    #[doc = $desc]
56    /// mode and set the internal voltage reference.
57    pub fn $fn_name(mut self, vref: Vref) -> Result<$max_ty<SPI, $mode_ty>, SPI::Error> {
58      self.spi.write(&vref_command_bytes($control_bits, vref))?;
59      Ok($max_ty { spi: self.spi, _mode: PhantomData })
60    }
61  };
62}
63
64macro_rules! doc_imports {
65  (Max5533) => {
66    "max553x::{Max5533, Vref}"
67  };
68  (Max5535) => {
69    "max553x::{Max5535, Vref}"
70  };
71  ($max_ty:ident) => {
72    concat!("max553x::", stringify!($max_ty))
73  };
74}
75
76macro_rules! doc_vref_value {
77  (Max5533) => {
78    0b0100
79  };
80  (Max5535) => {
81    0b0100
82  };
83  ($max_ty:ident) => {
84    0b0000
85  };
86}
87
88macro_rules! doc_vref {
89  (Max5533) => {
90    "Vref::M1940"
91  };
92  (Max5535) => {
93    "Vref::M1940"
94  };
95  ($max_ty:ident) => {
96    ""
97  };
98}
99
100macro_rules! impl_standby_shutdown {
101  (Max5533) => {
102    impl_standby_shutdown!(@inner Max5533, Standby);
103    impl_standby_shutdown!(@inner Max5533, Shutdown);
104  };
105  (Max5535) => {
106    impl_standby_shutdown!(@inner Max5535, Standby);
107    impl_standby_shutdown!(@inner Max5535, Shutdown);
108  };
109  ($max_ty:ident) => {
110    impl_standby_shutdown!(@inner $max_ty, Shutdown);
111  };
112  (@inner $max_ty:ident, $mode_ty:ident) => {
113    impl<SPI> $max_ty<SPI, $mode_ty>
114    where
115      SPI: SpiDevice<u8>
116    {
117      /// Load DAC registers A and B from respective input registers, update
118      /// respective DAC outputs and enter normal operation mode.
119      #[inline]
120      pub fn dac_ab(self) -> Result<$max_ty<SPI, Normal>, SPI::Error> {
121        let mut max_553x: $max_ty<SPI, Normal> = $max_ty { spi: self.spi, _mode: PhantomData };
122        max_553x.dac_ab()?;
123        Ok(max_553x)
124      }
125
126      /// Load input and DAC register A from shift register A,
127      /// load DAC register B from input register B
128      /// and enter normal operation mode.
129      pub fn input_a_dac_ab(self, value: u16) -> Result<$max_ty<SPI, Normal>, SPI::Error> {
130        let mut max_553x: $max_ty<SPI, Normal> = $max_ty { spi: self.spi, _mode: PhantomData };
131        max_553x.input_a_dac_ab(value)?;
132        Ok(max_553x)
133      }
134
135      /// Load input and DAC register B from shift register A,
136      /// load DAC register A from input register A
137      /// and enter normal operation mode.
138      pub fn input_b_dac_ab(self, value: u16) -> Result<$max_ty<SPI, Normal>, SPI::Error> {
139        let mut max_553x: $max_ty<SPI, Normal> = $max_ty { spi: self.spi, _mode: PhantomData };
140        max_553x.input_b_dac_ab(value)?;
141        Ok(max_553x)
142      }
143
144      /// Load input registers A and B and DAC registers A and B from shift register
145      /// and enter normal operation mode.
146      pub fn input_ab_dac_ab(self, value: u16) -> Result<$max_ty<SPI, Normal>, SPI::Error> {
147        let mut max_553x: $max_ty<SPI, Normal> = $max_ty { spi: self.spi, _mode: PhantomData };
148        max_553x.input_ab_dac_ab(value)?;
149        Ok(max_553x)
150      }
151    }
152  }
153}
154
155macro_rules! impl_max {
156  ($(#[$attr:meta]),* $max_ty:ident) => {
157    $(
158      #[$attr]
159    )*
160    /// # Usage
161    ///
162    /// ```rust
163    /// # fn main() -> Result<(), embedded_hal::spi::ErrorKind> {
164    /// # use embedded_hal_mock::eh1::{spi::{Mock as SpiMock, Transaction as SpiTransaction}};
165    #[doc = concat!("use ", doc_imports!($max_ty), ";")]
166    /// #
167    /// # let mut spi = SpiMock::new(&[
168    /// #   SpiTransaction::transaction_start(),
169    #[doc = concat!("#   SpiTransaction::write_vec(vec![0b1101_0000 | ", doc_vref_value!($max_ty), ", 0b00000000]), // Into normal mode.")]
170    /// #   SpiTransaction::transaction_end(),
171    /// #   SpiTransaction::transaction_start(),
172    /// #   SpiTransaction::write_vec(vec![0b0001_0100, 0b11010010]), // Load input register A with value 1234.
173    /// #   SpiTransaction::transaction_end(),
174    /// #   SpiTransaction::transaction_start(),
175    /// #   SpiTransaction::write_vec(vec![0b0010_1111, 0b11111111]), // Load input register B with value 4095.
176    /// #   SpiTransaction::transaction_end(),
177    /// #   SpiTransaction::transaction_start(),
178    /// #   SpiTransaction::write_vec(vec![0b1000_0000, 0b00000000]), // Load DAC registers from input registers.
179    /// #   SpiTransaction::transaction_end(),
180    /// #   SpiTransaction::transaction_start(),
181    /// #   SpiTransaction::write_vec(vec![0b1001_0100, 0b11010010]), // Load input register A with value 1234 and load DAC register A.
182    /// #   SpiTransaction::transaction_end(),
183    /// #   SpiTransaction::transaction_start(),
184    /// #   SpiTransaction::write_vec(vec![0b1010_1111, 0b11111111]), // Load input register B with value 4095 and load DAC register B.
185    /// #   SpiTransaction::transaction_end(),
186    /// #   SpiTransaction::transaction_start(),
187    #[doc = concat!("#   SpiTransaction::write_vec(vec![0b1110_0000 | ", doc_vref_value!($max_ty), ", 0b00000000]), // Into shutdown mode.")]
188    /// #   SpiTransaction::transaction_end(),
189    /// # ]);
190    ///
191    #[doc = concat!("let dac = ", stringify!($max_ty), "::new(spi);")]
192    ///
193    /// // Turn on.
194    #[doc = concat!("let mut dac = dac.into_normal(", doc_vref!($max_ty), ")?;")]
195    ///
196    /// // The following two sequences have the same end result:
197    /// // DAC register A set to 1234 and DAC register B set to 4095.
198    ///
199    /// // Set input register A.
200    /// dac.input_a(1234)?;
201    /// // Set input register B.
202    /// dac.input_b(4095)?;
203    /// // Load DAC registers from input registers.
204    /// dac.dac_ab()?;
205    ///
206    /// // Set input register A and DAC register A and load DAC register B from input register B.
207    /// dac.input_a_dac_ab(1234)?;
208    /// // Set input register B and DAC register B and load DAC register A from input register A.
209    /// dac.input_b_dac_ab(4095)?;
210    ///
211    /// // Turn off.
212    #[doc = concat!("let dac = dac.into_shutdown(", doc_vref!($max_ty), ")?;")]
213    ///
214    /// // Release SPI peripheral again.
215    /// let spi = dac.release();
216    /// # let mut spi = spi;
217    /// # spi.done();
218    /// drop(spi);
219    /// # Ok(())
220    /// # }
221    /// ```
222    #[derive(Debug)]
223    pub struct $max_ty<SPI, MODE> {
224      spi: SPI,
225      _mode: PhantomData<MODE>,
226    }
227
228    impl<SPI> $max_ty<SPI, Shutdown> {
229      /// Create a new DAC with the given spi.
230      pub const fn new(spi: SPI) -> $max_ty<SPI, Shutdown> {
231        $max_ty { spi, _mode: PhantomData }
232      }
233
234      /// Release the contained spi.
235      pub fn release(self) -> SPI {
236        self.spi
237      }
238    }
239
240    impl<SPI, MODE> $max_ty<SPI, MODE>
241    where
242      SPI: SpiDevice<u8>
243    {
244      /// Load input register A from shift register.
245      #[inline]
246      pub fn input_a(&mut self, value: u16) -> Result<(), SPI::Error> {
247        self.spi.write(&command_bytes(0b0001, value))
248      }
249
250      /// Load input register B from shift register.
251      #[inline]
252      pub fn input_b(&mut self, value: u16) -> Result<(), SPI::Error> {
253        self.spi.write(&command_bytes(0b0010, value))
254      }
255
256      impl_into_mode!("normal operation", $max_ty, Normal,   into_normal,   0b1101);
257      impl_into_mode!("shutdown",         $max_ty, Shutdown, into_shutdown, 0b1110);
258    }
259
260    impl<SPI> $max_ty<SPI, Normal>
261    where
262      SPI: SpiDevice<u8>
263    {
264      /// Load DAC registers A and B from respective input registers
265      /// and update respective DAC outputs.
266      #[inline]
267      pub fn dac_ab(&mut self) -> Result<(), SPI::Error> {
268        self.spi.write(&command_bytes(0b1000, 0))
269      }
270
271      /// Load input and DAC register A from shift register A and
272      /// load DAC register B from input register B.
273      pub fn input_a_dac_ab(&mut self, value: u16) -> Result<(), SPI::Error> {
274        self.spi.write(&command_bytes(0b1001, value))
275      }
276
277      /// Load input and DAC register B from shift register B and
278      /// load DAC register A from input register A.
279      pub fn input_b_dac_ab(&mut self, value: u16) -> Result<(), SPI::Error> {
280        self.spi.write(&command_bytes(0b1010, value))
281      }
282
283      /// Load input registers A and B and DAC registers A and B from shift register.
284      pub fn input_ab_dac_ab(&mut self, value: u16) -> Result<(), SPI::Error> {
285        self.spi.write(&command_bytes(0b1111, value))
286      }
287
288      impl_into_mode!("standby", $max_ty, Standby, into_standby, 0b1100);
289    }
290
291    impl_standby_shutdown!($max_ty);
292  }
293}
294
295impl_max!(
296  /// Struct representing a MAX5532 DAC.
297  Max5532
298);
299impl_max!(
300  /// Struct representing a MAX5533 DAC.
301  Max5533
302);
303impl_max!(
304  /// Struct representing a MAX5534 DAC.
305  Max5534
306);
307impl_max!(
308  /// Struct representing a MAX5535 DAC.
309  Max5535
310);
311
312/// Internal voltage reference for MAX5533/MAX5535.
313#[derive(Debug, Clone, Copy)]
314pub enum Vref {
315  /// 1.214 V
316  M1214 = 0b00,
317  /// 1.940 V
318  M1940 = 0b01,
319  /// 2.425 V
320  M2425 = 0b10,
321  /// 3.885 V
322  M3885 = 0b11,
323}