Skip to main content

lis2mdl_rs/
driver.rs

1use super::{
2    BusOperation, DelayNs, I2c, RegisterOperation, SensorOperation, SevenBitAddress, SpiDevice,
3    bisync, i2c, prelude::*, spi,
4};
5
6use core::fmt::Debug;
7use core::marker::PhantomData;
8
9/// Driver for LIS2MDL sensor.
10///
11/// The struct takes a bus object to write to the registers.
12/// The bus is generalized over the BusOperation trait, allowing the use
13/// of I2C or SPI protocols; this also allows the user to implement sharing
14/// techniques to share the underlying bus.
15#[bisync]
16pub struct Lis2mdl<B, T, S>
17where
18    B: BusOperation,
19    T: DelayNs,
20    S: SensorState,
21{
22    /// The bus driver.
23    pub bus: B,
24    pub tim: T,
25    _state: PhantomData<S>,
26}
27
28/// Driver errors.
29#[derive(Debug)]
30#[bisync]
31pub enum Error<B> {
32    Bus(B),          // Error at the bus level
33    UnexpectedValue, // Unexpected value read from a register
34    InvalidConfiguration,
35    HwNoResponse,
36}
37
38#[bisync]
39impl<B, T, S> Lis2mdl<B, T, S>
40where
41    B: BusOperation,
42    T: DelayNs,
43    S: SensorState,
44{
45    /// Constructor method using a generic Bus that implements BusOperation
46    pub fn new_bus(bus: B, tim: T) -> Self {
47        Self {
48            bus,
49            tim,
50            _state: PhantomData,
51        }
52    }
53}
54
55#[bisync]
56impl<P, T> Lis2mdl<i2c::I2cBus<P>, T, OnState>
57where
58    P: I2c,
59    T: DelayNs,
60{
61    /// Constructor method for using the I2C bus.
62    pub fn new_i2c(i2c: P, address: I2CAddress, tim: T) -> Self {
63        // Initialize the I2C bus with the COMPONENT address
64        let bus = i2c::I2cBus::new(i2c, address as SevenBitAddress);
65        Self {
66            bus,
67            tim,
68            _state: PhantomData,
69        }
70    }
71}
72
73#[bisync]
74impl<P, T, S> Lis2mdl<spi::SpiBus<P>, T, S>
75where
76    P: SpiDevice,
77    T: DelayNs,
78    S: SensorState,
79{
80    /// Constructor method for using the SPI bus.
81    pub fn new_spi(spi: P, tim: T) -> Self {
82        // Initialize the SPI bus
83        let bus = spi::SpiBus::new(spi);
84        Self {
85            bus,
86            tim,
87            _state: PhantomData,
88        }
89    }
90}
91
92#[bisync]
93impl<B, T, S> SensorOperation for Lis2mdl<B, T, S>
94where
95    B: BusOperation,
96    T: DelayNs,
97    S: SensorState,
98{
99    type Error = Error<B::Error>;
100
101    async fn write_to_register(&mut self, reg: u8, buf: &[u8]) -> Result<(), Error<B::Error>> {
102        self.bus
103            .write_to_register(reg, buf)
104            .await
105            .map_err(Error::Bus)
106    }
107
108    async fn read_from_register(&mut self, reg: u8, buf: &mut [u8]) -> Result<(), Error<B::Error>> {
109        self.bus
110            .read_from_register(reg, buf)
111            .await
112            .map_err(Error::Bus)
113    }
114}
115
116#[bisync]
117impl<B, T> Lis2mdl<B, T, OnState>
118where
119    B: BusOperation,
120    T: DelayNs,
121{
122    /// Set magnetic user offset for hard-iron to compensate environmental effects.
123    ///
124    /// Data format is the same of output data raw: two's complement
125    /// with 1LSb = 1.5mg. These values act on the magnetic output data
126    /// value in order to delete the environmental offset.
127    pub async fn mag_user_offset_set(&mut self, val: &[i16; 3]) -> Result<(), Error<B::Error>> {
128        let offset = OffsetXYZ {
129            x: val[0],
130            y: val[1],
131            z: val[2],
132        };
133        offset.write(self).await?;
134
135        Ok(())
136    }
137
138    /// Get magnetic user offset for hard-iron to compensate environmental effects.
139    ///
140    /// Data format is the same of output data raw: two's complement
141    /// with 1LSb = 1.5mg. These values act on the magnetic output data
142    /// value in order to delete the environmental offset.
143    pub async fn mag_user_offset_get(&mut self) -> Result<[i16; 3], Error<B::Error>> {
144        let val = OffsetXYZ::read(self).await?;
145
146        Ok([val.x, val.y, val.z])
147    }
148
149    /// Set Operating mode.
150    pub async fn operating_mode_set(&mut self, val: Md) -> Result<(), Error<B::Error>> {
151        let mut reg = CfgRegA::read(self).await?;
152        reg.set_md(val as u8);
153        reg.write(self).await
154    }
155    /// Get Operating mode.
156    pub async fn operating_mode_get(&mut self) -> Result<Md, Error<B::Error>> {
157        let reg = CfgRegA::read(self).await?;
158
159        let val = Md::try_from(reg.md()).unwrap_or_default();
160        Ok(val)
161    }
162    /// Set Output data rate(ODR).
163    pub async fn data_rate_set(&mut self, val: Odr) -> Result<(), Error<B::Error>> {
164        let mut reg = CfgRegA::read(self).await?;
165        reg.set_odr(val as u8);
166        reg.write(self).await
167    }
168    /// Get Output data rate(ODR).
169    pub async fn data_rate_get(&mut self) -> Result<Odr, Error<B::Error>> {
170        let reg = CfgRegA::read(self).await?;
171        let val = Odr::try_from(reg.odr()).unwrap_or_default();
172        Ok(val)
173    }
174    /// Enables/Disable high-resolution/low-power mode.
175    pub async fn power_mode_set(&mut self, val: PowerMode) -> Result<(), Error<B::Error>> {
176        let mut reg = CfgRegA::read(self).await?;
177        reg.set_lp(val as u8);
178        reg.write(self).await?;
179
180        Ok(())
181    }
182    /// Get high-resolution/low-power mode.
183    pub async fn power_mode_get(&mut self) -> Result<PowerMode, Error<B::Error>> {
184        let reg = CfgRegA::read(self).await?;
185
186        let val = PowerMode::try_from(reg.lp()).unwrap_or_default();
187        Ok(val)
188    }
189    /// Enables/Disables the magnetometer temperature compensation.
190    pub async fn offset_temp_comp_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
191        let mut reg = CfgRegA::read(self).await?;
192        reg.set_comp_temp_en(val);
193        reg.write(self).await?;
194
195        Ok(())
196    }
197    /// Get configuration (enable/disable) for magnetometer temperature compensation.
198    pub async fn offset_temp_comp_get(&mut self) -> Result<u8, Error<B::Error>> {
199        let val: u8 = CfgRegA::read(self).await?.comp_temp_en();
200
201        Ok(val)
202    }
203    /// Set Low-pass bandwidth selection.
204    pub async fn low_pass_bandwidth_set(
205        &mut self,
206        val: LowPassFilter,
207    ) -> Result<(), Error<B::Error>> {
208        let mut reg = CfgRegB::read(self).await?;
209        reg.set_lpf(val as u8);
210        reg.write(self).await?;
211
212        Ok(())
213    }
214    /// Get Low-pass bandwidth.
215    pub async fn low_pass_bandwidth_get(&mut self) -> Result<LowPassFilter, Error<B::Error>> {
216        let reg = CfgRegB::read(self).await?;
217
218        let val = LowPassFilter::try_from(reg.lpf()).unwrap_or_default();
219        Ok(val)
220    }
221    /// Set Reset mode.
222    pub async fn set_rst_mode_set(&mut self, val: SetRst) -> Result<(), Error<B::Error>> {
223        let mut reg = CfgRegB::read(self).await?;
224        reg.set_set_rst(val as u8);
225        reg.write(self).await?;
226
227        Ok(())
228    }
229    /// Get Reset mode.
230    pub async fn set_rst_mode_get(&mut self) -> Result<SetRst, Error<B::Error>> {
231        let reg = CfgRegB::read(self).await?;
232
233        let val = SetRst::try_from(reg.set_rst()).unwrap_or_default();
234        Ok(val)
235    }
236    /// Enables/Disables offset cancellation in single measurement mode.
237    ///
238    /// The OFF_CANC bit must be set to 1 when enabling offset
239    /// cancellation in single measurement mode, which means a
240    /// call function: set_rst_mode(SENS_OFF_CANC_EVERY_ODR)
241    /// is needed.
242    pub async fn set_rst_sensor_single_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
243        let mut reg = CfgRegB::read(self).await?;
244        let rst = SetRst::try_from(reg.set_rst()).map_err(|_| Error::UnexpectedValue)?;
245
246        if val == 1 && rst != SetRst::SensOffCancEveryOdr {
247            return Err(Error::InvalidConfiguration);
248        }
249
250        reg.set_off_canc_one_shot(val);
251        reg.write(self).await?;
252
253        Ok(())
254    }
255    /// Get configuration (enable/disable) for offset cancellation in single measurement mode.
256    ///
257    /// The OFF_CANC bit must be set to 1 when enabling offset
258    /// cancellation in single measurement mode. This means calling
259    /// the function set_rst_mode(SensOffCancEveryOdr) is needed.
260    pub async fn set_rst_sensor_single_get(&mut self) -> Result<u8, Error<B::Error>> {
261        let val: u8 = CfgRegB::read(self).await?.off_canc_one_shot();
262
263        Ok(val)
264    }
265    /// Enable/Disable Block data update.
266    ///
267    /// If val is 1: BDU is active
268    pub async fn block_data_update_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
269        let mut reg = CfgRegC::read(self).await?;
270        reg.set_bdu(val);
271        reg.write(self).await?;
272
273        Ok(())
274    }
275    /// Get Block data update configuration (enable/disable).
276    pub async fn block_data_update_get(&mut self) -> Result<u8, Error<B::Error>> {
277        let val: u8 = CfgRegC::read(self).await?.bdu();
278
279        Ok(val)
280    }
281    /// Get magnetic data ready data available.
282    ///
283    /// If event available returns 1.
284    pub async fn mag_data_ready_get(&mut self) -> Result<u8, Error<B::Error>> {
285        let val: u8 = StatusReg::read(self).await?.zyxda();
286
287        Ok(val)
288    }
289    /// Get magnetic data overrun event.
290    ///
291    /// 0: no overrun has occurred. 1: a new set of data has overwritten the previous set
292    pub async fn mag_data_ovr_get(&mut self) -> Result<u8, Error<B::Error>> {
293        let val: u8 = StatusReg::read(self).await?.zyxor();
294
295        Ok(val)
296    }
297    /// Get Magnetic raw value.
298    ///
299    /// Need conversion using `from_lsb_to_mgauss`
300    pub async fn magnetic_raw_get(&mut self) -> Result<[i16; 3], Error<B::Error>> {
301        let val = OutXYZ::read(self).await?;
302
303        Ok([val.x, val.y, val.z])
304    }
305
306    /// Get temperature raw value.
307    pub async fn temperature_raw_get(&mut self) -> Result<i16, Error<B::Error>> {
308        TempOut::read(self).await.map(|temp| temp.0)
309    }
310
311    /// Get Device Id.
312    ///
313    /// Reads the WHO_AM_I register.
314    pub async fn device_id_get(&mut self) -> Result<u8, Error<B::Error>> {
315        WhoAmI::read(self).await.map(|reg| reg.who_am_i())
316    }
317
318    /// Execute a software reset.
319    ///
320    /// Resets control registers to their default values.
321    /// The software reset procedure takes approximately 5 µs; this function handles the wait internally
322    /// (one reading after 5 us for a maximum of 3 attempts).
323    ///
324    /// Returns `Error::HwNoResponse` if the SOFT_RST bit is not cleared by hardware within 3 ms.
325    pub async fn sw_reset(&mut self) -> Result<(), Error<B::Error>> {
326        let mut cfg_reg_a = CfgRegA::default();
327        let mut retry: u8 = 0;
328
329        /* 1. Set the SOFT_RST bit of the CFG_REG_A register to 1. */
330        cfg_reg_a.set_soft_rst(1);
331        cfg_reg_a.write(self).await?;
332
333        /* 2. Poll the SOFT_RST bit of the CFG_REG_A register until il returns to 0. (should require 5us) */
334        loop {
335            cfg_reg_a = CfgRegA::read(self).await?;
336
337            if cfg_reg_a.soft_rst() == 0 {
338                return Ok(());
339            }
340
341            retry += 1;
342            if retry > 3 {
343                break;
344            }
345
346            self.tim.delay_us(5).await;
347        }
348
349        Err(Error::HwNoResponse)
350    }
351
352    /// Set Software reset.
353    ///
354    /// If val is 1: Restore the default values in user registers.
355    /// Flash register keep their values.
356    #[deprecated(since = "2.0.0", note = "please use sw_reset")]
357    pub async fn reset_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
358        let mut reg = CfgRegA::read(self).await?;
359        reg.set_soft_rst(val);
360        reg.write(self).await?;
361
362        Ok(())
363    }
364    /// Get Software reset configuration.
365    ///
366    /// If set to 1: Restore the default values in user registers.
367    #[deprecated(since = "2.0.0", note = "please use sw_reset")]
368    pub async fn reset_get(&mut self) -> Result<u8, Error<B::Error>> {
369        let val: u8 = CfgRegA::read(self).await?.soft_rst();
370
371        Ok(val)
372    }
373
374    pub async fn reboot(&mut self) -> Result<(), Error<B::Error>> {
375        let mut reg = CfgRegA::read(self).await?;
376        reg.set_reboot(1);
377        reg.write(self).await?;
378
379        self.tim.delay_ms(20).await;
380
381        Ok(())
382    }
383
384    /// Set Reboot memory content.
385    ///
386    /// If val is 1: Reload the calibration parameters.
387    #[deprecated(since = "2.0.0", note = "please use reboot")]
388    pub async fn boot_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
389        let mut reg = CfgRegA::read(self).await?;
390        reg.set_reboot(val);
391        reg.write(self).await?;
392
393        Ok(())
394    }
395    /// Reboot memory content. Reload the calibration parameters.
396    #[deprecated(since = "2.0.0", note = "please use reboot")]
397    pub async fn boot_get(&mut self) -> Result<u8, Error<B::Error>> {
398        let val: u8 = CfgRegA::read(self).await?.reboot();
399
400        Ok(val)
401    }
402    /// Set Selftest mode.
403    pub async fn self_test_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
404        let mut reg = CfgRegC::read(self).await?;
405        reg.set_self_test(val);
406        reg.write(self).await?;
407
408        Ok(())
409    }
410    /// Get Selftest configuration.
411    pub async fn self_test_get(&mut self) -> Result<u8, Error<B::Error>> {
412        let val: u8 = CfgRegC::read(self).await?.self_test();
413
414        Ok(val)
415    }
416    /// Set Big/Little Endian data format.
417    pub async fn data_format_set(&mut self, val: Ble) -> Result<(), Error<B::Error>> {
418        let mut reg = CfgRegC::read(self).await?;
419        reg.set_ble(val as u8);
420        reg.write(self).await?;
421
422        Ok(())
423    }
424    /// Get Big/Little Endian data format.
425    pub async fn data_format_get(&mut self) -> Result<Ble, Error<B::Error>> {
426        let reg = CfgRegC::read(self).await?;
427
428        let val = Ble::try_from(reg.ble()).unwrap_or_default();
429        Ok(val)
430    }
431    /// Get info about device status.
432    pub async fn status_get(&mut self) -> Result<StatusReg, Error<B::Error>> {
433        let val = StatusReg::read(self).await?;
434
435        Ok(val)
436    }
437    /// Set the interrupt block recognition checks data after/before the
438    /// hard-iron correction to discover the interrupt.
439    pub async fn offset_int_conf_set(&mut self, val: IntOnDataoff) -> Result<(), Error<B::Error>> {
440        let mut reg = CfgRegB::read(self).await?;
441        reg.set_int_on_dataoff(val as u8);
442        reg.write(self).await?;
443
444        Ok(())
445    }
446    /// Retrive the interrupt block recognition checks data after/before the
447    /// hard-iron correction to discover the interrupt.
448    pub async fn offset_int_conf_get(&mut self) -> Result<IntOnDataoff, Error<B::Error>> {
449        let reg = CfgRegB::read(self).await?;
450
451        let val = IntOnDataoff::try_from(reg.int_on_dataoff()).unwrap_or_default();
452        Ok(val)
453    }
454    /// Set Data-ready signal on INT_DRDY pin.
455    pub async fn drdy_on_pin_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
456        let mut reg = CfgRegC::read(self).await?;
457        reg.set_drdy_on_pin(val);
458        reg.write(self).await?;
459
460        Ok(())
461    }
462    /// Get Data-ready signal on INT_DRDY pin.
463    pub async fn drdy_on_pin_get(&mut self) -> Result<u8, Error<B::Error>> {
464        let val: u8 = CfgRegC::read(self).await?.drdy_on_pin();
465
466        Ok(val)
467    }
468    /// Set Interrupt signal on INT_DRDY pin.
469    pub async fn int_on_pin_set(&mut self, val: u8) -> Result<(), Error<B::Error>> {
470        let mut reg = CfgRegC::read(self).await?;
471        reg.set_int_on_pin(val);
472        reg.write(self).await?;
473
474        Ok(())
475    }
476    /// Get Interrupt signal on INT_DRDY pin.
477    pub async fn int_on_pin_get(&mut self) -> Result<u8, Error<B::Error>> {
478        let val: u8 = CfgRegC::read(self).await?.int_on_pin();
479
480        Ok(val)
481    }
482    /// Set Interrupt generator configuration register.
483    pub async fn int_gen_conf_set(&mut self, val: &IntCrtlReg) -> Result<(), Error<B::Error>> {
484        val.write(self).await
485    }
486    /// Get Interrupt generator configuration register.
487    pub async fn int_gen_conf_get(&mut self) -> Result<IntCrtlReg, Error<B::Error>> {
488        IntCrtlReg::read(self).await
489    }
490    /// Get Interrupt generator source register.
491    pub async fn int_gen_source_get(&mut self) -> Result<IntSourceReg, Error<B::Error>> {
492        IntSourceReg::read(self).await
493    }
494    /// Set User-defined threshold value for xl interrupt event on generator.
495    ///
496    /// Data format is the same as output data raw: two's complement with
497    /// 1LSb = 1.5mg.
498    pub async fn int_gen_threshold_set(&mut self, val: u16) -> Result<(), Error<B::Error>> {
499        IntThs::new().with_threshold(val).write(self).await
500    }
501    /// Get User-defined threshold value for xl interrupt event on generator.
502    ///
503    /// Data format is the same as output data raw: two�s complement with
504    /// 1LSb = 1.5mg.
505    pub async fn int_gen_threshold_get(&mut self) -> Result<u16, Error<B::Error>> {
506        Ok(IntThs::read(self).await?.threshold())
507    }
508    /// Set SPI Serial Interface Mode.
509    ///
510    /// If Sim::Spi4Wire enable SDO line on pin 7.
511    pub async fn spi_mode_set(&mut self, val: Sim) -> Result<(), Error<B::Error>> {
512        let mut reg_val = CfgRegC::read(self).await?;
513        reg_val.set_four_wire_spi(val as u8);
514        reg_val.write(self).await?;
515
516        Ok(())
517    }
518
519    /// Get SPI Serial Interface Mode.
520    pub async fn spi_mode_get(&mut self) -> Result<Sim, Error<B::Error>> {
521        let reg_val = CfgRegC::read(self).await?;
522
523        let val = Sim::try_from(reg_val.four_wire_spi()).unwrap_or_default();
524        Ok(val)
525    }
526
527    /// Disable/Enable I2C interface.
528    ///
529    /// As default I2C interface is enabled, use this function to switch if needed
530    pub async fn i2c_interface_set(&mut self, val: I2cSwitch) -> Result<(), Error<B::Error>> {
531        let mut reg = CfgRegC::read(self).await?;
532        reg.set_i2c_dis(val as u8);
533        reg.write(self).await?;
534
535        Ok(())
536    }
537    /// Get I2C interface configuration (enable/disable).
538    pub async fn i2c_interface_get(&mut self) -> Result<I2cSwitch, Error<B::Error>> {
539        let reg = CfgRegC::read(self).await?;
540
541        let val = I2cSwitch::try_from(reg.i2c_dis()).unwrap_or_default();
542        Ok(val)
543    }
544}
545
546#[bisync]
547pub fn from_lsb_to_mgauss(lsb: i16) -> f32 {
548    lsb as f32 * 1.5
549}
550
551#[bisync]
552pub fn from_lsb_to_celsius(lsb: i16) -> f32 {
553    lsb as f32 / 8.0 + 25.0
554}
555
556#[repr(u8)]
557#[derive(Clone, Copy, PartialEq)]
558#[bisync]
559pub enum I2CAddress {
560    I2cAdd = 0x1E,
561}
562
563#[bisync]
564pub const ID: u8 = 0x40;