lis3dh_async/
lib.rs

1//! Platform-agnostic LIS3DH accelerometer driver which uses I²C via
2//! [embedded-hal]. This driver implements the [`Accelerometer`][acc-trait]
3//! and [`RawAccelerometer`][raw-trait] traits from the [accelerometer] crate.
4//!
5//! [embedded-hal]: https://docs.rs/embedded-hal
6//! [accelerometer]: https://docs.rs/accelerometer
7//! [acc-trait]: https://docs.rs/accelerometer/latest/accelerometer/trait.Accelerometer.html
8//! [raw-trait]: https://docs.rs/accelerometer/latest/accelerometer/trait.RawAccelerometer.html
9//!
10
11#![no_std]
12#![allow(async_fn_in_trait)]
13
14use core::convert::{TryFrom, TryInto};
15use core::fmt::Debug;
16
17use accelerometer::vector::{F32x3, I16x3};
18use embedded_hal_async::i2c::I2c;
19use embedded_hal_async::spi::{self, SpiDevice};
20
21mod interrupts;
22mod register;
23
24use interrupts::*;
25pub use interrupts::{
26    Detect4D, Interrupt1, Interrupt2, InterruptConfig, InterruptMode, InterruptSource, IrqPin,
27    IrqPin1Config, IrqPin2Config, LatchInterruptRequest,
28};
29
30use register::*;
31pub use register::{
32    DataRate, DataStatus, Duration, FifoMode, FifoStatus, Mode, Range, Register, SlaveAddr,
33    Threshold,
34};
35
36/// Accelerometer errors, generic around another error type `E` representing
37/// an (optional) cause of this error.
38#[derive(Debug)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum Error<BusError> {
41    /// Bus error
42    Bus(BusError),
43
44    /// Invalid data rate selection
45    InvalidDataRate,
46
47    /// Invalid operating mode selection
48    InvalidMode,
49
50    /// Invalid full-scale selection
51    InvalidRange,
52
53    /// Attempted to write to a read-only register
54    WriteToReadOnly,
55
56    /// Invalid address provided
57    WrongAddress,
58}
59
60/// `LIS3DH` driver.
61pub struct Lis3dh<CORE> {
62    core: CORE,
63}
64
65impl<I2C, E> Lis3dh<Lis3dhI2C<I2C>>
66where
67    I2C: I2c<Error = E>,
68{
69    /// Create a new LIS3DH driver from the given I2C peripheral using the default config.
70    /// Default is Hz_400 HighResolution.
71    pub async fn new_i2c(i2c: I2C, address: SlaveAddr) -> Result<Self, Error<E>> {
72        Self::new_i2c_with_config(i2c, address, Configuration::default()).await
73    }
74
75    /// Create a new driver instance without talking to the LIS3DH.
76    /// This can be useful when the accelerometer was already on while the microcontroller rebooted and you need
77    /// continuous operation.
78    pub async fn new_i2c_without_config(i2c: I2C, address: SlaveAddr) -> Self {
79        let core = Lis3dhI2C {
80            i2c,
81            address: address.addr(),
82        };
83
84        Lis3dh { core }
85    }
86
87    pub async fn new_i2c_with_config(
88        i2c: I2C,
89        address: SlaveAddr,
90        config: Configuration,
91    ) -> Result<Self, Error<E>> {
92        let core = Lis3dhI2C {
93            i2c,
94            address: address.addr(),
95        };
96
97        let mut lis3dh = Lis3dh { core };
98
99        lis3dh.configure(config).await?;
100
101        Ok(lis3dh)
102    }
103}
104
105impl<SPI, ESPI> Lis3dh<Lis3dhSPI<SPI>>
106where
107    SPI: SpiDevice<Error = ESPI>,
108{
109    /// Create a new LIS3DH driver from the given SPI peripheral.
110    pub async fn new_spi(spi: SPI) -> Result<Self, Error<ESPI>> {
111        Self::new_spi_with_config(spi, Configuration::default()).await
112    }
113
114    /// Create a new driver instance without talking to the LIS3DH.
115    /// This can be useful when the accelerometer was already on while the microcontroller rebooted and you need
116    /// continuous operation.
117    pub async fn new_spi_without_config(spi: SPI) -> Self {
118        let core = Lis3dhSPI { spi };
119
120        Lis3dh { core }
121    }
122
123    pub async fn new_spi_with_config(spi: SPI, config: Configuration) -> Result<Self, Error<ESPI>> {
124        let core = Lis3dhSPI { spi };
125
126        let mut lis3dh = Lis3dh { core };
127
128        lis3dh.configure(config).await?;
129
130        Ok(lis3dh)
131    }
132}
133
134impl<CORE> Lis3dh<CORE>
135where
136    CORE: Lis3dhCore,
137{
138    /// Configure the device
139    pub async fn configure(&mut self, conf: Configuration) -> Result<(), Error<CORE::BusError>> {
140        if self.get_device_id().await? != DEVICE_ID {
141            return Err(Error::WrongAddress);
142        }
143
144        if conf.block_data_update || conf.enable_temperature {
145            // Block data update
146            self.write_register(Register::CTRL4, BDU).await?;
147        }
148
149        self.set_mode(conf.mode).await?;
150
151        self.set_datarate(conf.datarate).await?;
152
153        self.enable_axis((conf.enable_x_axis, conf.enable_y_axis, conf.enable_z_axis))
154            .await?;
155
156        if conf.enable_temperature {
157            self.enable_temp(true).await?;
158        }
159
160        // Enable ADCs.
161        self.write_register(Register::TEMP_CFG, ADC_EN).await
162    }
163
164    /// `WHO_AM_I` register.
165    pub async fn get_device_id(&mut self) -> Result<u8, Error<CORE::BusError>> {
166        self.read_register(Register::WHOAMI).await
167    }
168
169    /// X,Y,Z-axis enable.
170    /// `CTRL_REG1`: `Xen`, `Yen`, `Zen`
171    async fn enable_axis(
172        &mut self,
173        (x, y, z): (bool, bool, bool),
174    ) -> Result<(), Error<CORE::BusError>> {
175        self.modify_register(Register::CTRL1, |mut ctrl1| {
176            ctrl1 &= !(X_EN | Y_EN | Z_EN); // disable all axes
177
178            ctrl1 |= if x { X_EN } else { 0 };
179            ctrl1 |= if y { Y_EN } else { 0 };
180            ctrl1 |= if z { Z_EN } else { 0 };
181
182            ctrl1
183        })
184        .await
185    }
186
187    /// Operating mode selection.
188    /// `CTRL_REG1`: `LPen` bit, `CTRL_REG4`: `HR` bit.
189    /// You need to wait for stabilization after setting. In future this
190    /// function will be deprecated and instead take a `Delay` to do this for
191    /// you.
192    ///
193    /// | From           | To             | Wait for   |
194    /// |:---------------|:---------------|:-----------|
195    /// | HighResolution | LowPower       | 1/datarate |
196    /// | HighResolution | Normal         | 1/datarate |
197    /// | Normal         | LowPower       | 1/datarate |
198    /// | Normal         | HighResolution | 7/datarate |
199    /// | LowPower       | Normal         | 1/datarate |
200    /// | LowPower       | HighResolution | 7/datarate |
201    pub async fn set_mode(&mut self, mode: Mode) -> Result<(), Error<CORE::BusError>> {
202        match mode {
203            Mode::LowPower => {
204                self.register_set_bits(Register::CTRL1, LP_EN).await?;
205                self.register_clear_bits(Register::CTRL4, HR).await?;
206            }
207            Mode::Normal => {
208                self.register_clear_bits(Register::CTRL1, LP_EN).await?;
209                self.register_clear_bits(Register::CTRL4, HR).await?;
210            }
211            Mode::HighResolution => {
212                self.register_clear_bits(Register::CTRL1, LP_EN).await?;
213                self.register_set_bits(Register::CTRL4, HR).await?;
214            }
215        }
216
217        Ok(())
218    }
219
220    /// Read the current operating mode.
221    pub async fn get_mode(&mut self) -> Result<Mode, Error<CORE::BusError>> {
222        let ctrl1 = self.read_register(Register::CTRL1).await?;
223        let ctrl4 = self.read_register(Register::CTRL4).await?;
224
225        let is_lp_set = (ctrl1 >> 3) & 0x01 != 0;
226        let is_hr_set = (ctrl4 >> 3) & 0x01 != 0;
227
228        let mode = match (is_lp_set, is_hr_set) {
229            (true, false) => Mode::LowPower,
230            (false, false) => Mode::Normal,
231            (false, true) => Mode::HighResolution,
232            _ => return Err(Error::InvalidMode),
233        };
234
235        Ok(mode)
236    }
237
238    /// Data rate selection.
239    pub async fn set_datarate(&mut self, datarate: DataRate) -> Result<(), Error<CORE::BusError>> {
240        self.modify_register(Register::CTRL1, |mut ctrl1| {
241            // Mask off lowest 4 bits
242            ctrl1 &= !ODR_MASK;
243            // Write in new output data rate to highest 4 bits
244            ctrl1 |= datarate.bits() << 4;
245
246            ctrl1
247        })
248        .await
249    }
250
251    /// Read the current data selection rate.
252    pub async fn get_datarate(&mut self) -> Result<DataRate, Error<CORE::BusError>> {
253        let ctrl1 = self.read_register(Register::CTRL1).await?;
254        let odr = (ctrl1 >> 4) & 0x0F;
255
256        DataRate::try_from(odr).map_err(|_| Error::InvalidDataRate)
257    }
258
259    /// Full-scale selection.
260    pub async fn set_range(&mut self, range: Range) -> Result<(), Error<CORE::BusError>> {
261        self.modify_register(Register::CTRL4, |mut ctrl4| {
262            // Mask off lowest 4 bits
263            ctrl4 &= !FS_MASK;
264            // Write in new full-scale to highest 4 bits
265            ctrl4 |= range.bits() << 4;
266
267            ctrl4
268        })
269        .await
270    }
271
272    /// Read the current full-scale.
273    pub async fn get_range(&mut self) -> Result<Range, Error<CORE::BusError>> {
274        let ctrl4 = self.read_register(Register::CTRL4).await?;
275        let fs = (ctrl4 >> 4) & 0b0011;
276
277        Range::try_from(fs).map_err(|_| Error::InvalidRange)
278    }
279
280    /// Set `REFERENCE` register.
281    pub async fn set_ref(&mut self, reference: u8) -> Result<(), Error<CORE::BusError>> {
282        self.write_register(Register::REFERENCE, reference).await
283    }
284
285    /// Read the `REFERENCE` register.
286    pub async fn get_ref(&mut self) -> Result<u8, Error<CORE::BusError>> {
287        self.read_register(Register::REFERENCE).await
288    }
289
290    /// Accelerometer data-available status.
291    pub async fn get_status(&mut self) -> Result<DataStatus, Error<CORE::BusError>> {
292        let stat = self.read_register(Register::STATUS).await?;
293
294        Ok(DataStatus {
295            zyxor: (stat & ZYXOR) != 0,
296            xyzor: ((stat & XOR) != 0, (stat & YOR) != 0, (stat & ZOR) != 0),
297            zyxda: (stat & ZYXDA) != 0,
298            xyzda: ((stat & XDA) != 0, (stat & YDA) != 0, (stat & ZDA) != 0),
299        })
300    }
301
302    /// Convenience function for `STATUS_REG` to confirm all three X, Y and
303    /// Z-axis have new data available for reading by accel_raw and associated
304    /// function calls.
305    pub async fn is_data_ready(&mut self) -> Result<bool, Error<CORE::BusError>> {
306        let value = self.get_status().await?;
307
308        Ok(value.zyxda)
309    }
310
311    /// Temperature sensor enable.
312    /// `TEMP_CGF_REG`: `TEMP_EN`, the BDU bit in `CTRL_REG4` is also set.
313    pub async fn enable_temp(&mut self, enable: bool) -> Result<(), Error<CORE::BusError>> {
314        self.register_xset_bits(Register::TEMP_CFG, ADC_EN & TEMP_EN, enable)
315            .await?;
316
317        // enable block data update (required for temp reading)
318        if enable {
319            self.register_xset_bits(Register::CTRL4, BDU, true).await?;
320        }
321
322        Ok(())
323    }
324
325    /// Raw temperature sensor data as `i16`. The temperature sensor __must__
326    /// be enabled via `enable_temp` prior to reading.
327    pub async fn get_temp_out(&mut self) -> Result<i16, Error<CORE::BusError>> {
328        let out_l = self.read_register(Register::OUT_ADC3_L).await?;
329        let out_h = self.read_register(Register::OUT_ADC3_H).await?;
330
331        Ok(i16::from_le_bytes([out_l, out_h]))
332    }
333
334    /// Temperature sensor data converted to `f32`. Output is in degree
335    /// celsius. The temperature sensor __must__ be enabled via `enable_temp`
336    /// prior to reading.
337    pub async fn get_temp_outf(&mut self) -> Result<f32, Error<CORE::BusError>> {
338        let temp_out = self.get_temp_out().await?;
339
340        Ok(temp_out as f32 / 256.0 + 25.0)
341    }
342
343    /// Modify a register's value. Read the current value of the register,
344    /// update the value with the provided function, and set the register to
345    /// the return value.
346    async fn modify_register<F>(
347        &mut self,
348        register: Register,
349        f: F,
350    ) -> Result<(), Error<CORE::BusError>>
351    where
352        F: FnOnce(u8) -> u8,
353    {
354        let value = self.read_register(register).await?;
355
356        self.write_register(register, f(value)).await
357    }
358
359    /// Clear the given bits in the given register. For example:
360    ///
361    /// ```rust,ignore
362    /// lis3dh.register_clear_bits(0b0110)
363    /// ```
364    /// This call clears (sets to 0) the bits at index 1 and 2. Other bits of the register are not touched.
365    pub async fn register_clear_bits(
366        &mut self,
367        reg: Register,
368        bits: u8,
369    ) -> Result<(), Error<CORE::BusError>> {
370        self.modify_register(reg, |v| v & !bits).await
371    }
372
373    /// Set the given bits in the given register. For example:
374    ///
375    /// ```rust,ignore
376    /// lis3dh.register_set_bits(0b0110)
377    /// ```
378    ///
379    /// This call sets to 1 the bits at index 1 and 2. Other bits of the register are not touched.
380    pub async fn register_set_bits(
381        &mut self,
382        reg: Register,
383        bits: u8,
384    ) -> Result<(), Error<CORE::BusError>> {
385        self.modify_register(reg, |v| v | bits).await
386    }
387
388    /// Set or clear the given given bits in the given register, depending on
389    /// the value of `set`.
390    async fn register_xset_bits(
391        &mut self,
392        reg: Register,
393        bits: u8,
394        set: bool,
395    ) -> Result<(), Error<CORE::BusError>> {
396        if set {
397            self.register_set_bits(reg, bits).await
398        } else {
399            self.register_clear_bits(reg, bits).await
400        }
401    }
402
403    /// Configure one of the interrupt pins
404    ///
405    /// ```rust,ignore
406    /// lis3dh.configure_interrupt_pin(IrqPin1Config {
407    ///     // Raise if interrupt 1 is raised
408    ///     ia1_en: true,
409    ///     // Disable for all other interrupts
410    ///     ..IrqPin1Config::default()
411    /// })?;
412    /// ```
413    pub async fn configure_interrupt_pin<P: IrqPin>(
414        &mut self,
415        pin: P,
416    ) -> Result<(), Error<CORE::BusError>> {
417        self.write_register(P::ctrl_reg(), pin.bits()).await
418    }
419
420    /// Configure an IRQ source
421    ///
422    /// Example: configure interrupt 1 to fire when there is movement along any of the axes.
423    ///
424    /// ```rust,ignore
425    /// lis3dh.configure_irq_src(
426    ///     lis3dh::Interrupt1,
427    ///     lis3dh::InterruptMode::Movement,
428    ///     lis3dh::InterruptConfig::high_and_low(),
429    /// )?;
430    /// ```
431    pub async fn configure_irq_src<I: Interrupt>(
432        &mut self,
433        int: I,
434        interrupt_mode: InterruptMode,
435        interrupt_config: InterruptConfig,
436    ) -> Result<(), Error<CORE::BusError>> {
437        self.configure_irq_src_and_control(
438            int,
439            interrupt_mode,
440            interrupt_config,
441            LatchInterruptRequest::default(),
442            Detect4D::default(),
443        )
444        .await
445    }
446
447    /// Configure an IRQ source.
448    ///
449    /// LIS (latch interrupt request) will latch (keep active) the interrupt until the [`Lis3dh::get_irq_src`] is read.
450    ///
451    /// 4D detection is a subset of the 6D detection where detection on the Z axis is disabled.
452    /// This setting only has effect when the interrupt mode is either `Movement` or `Position`.
453    ///
454    /// Example: configure interrupt 1 to fire when there is movement along any of the axes.
455    ///
456    /// ```rust,ignore
457    /// lis3dh.configure_irq_src(
458    ///     lis3dh::Interrupt1,
459    ///     lis3dh::InterruptMode::Movement,
460    ///     lis3dh::InterruptConfig::high_and_low(),
461    ///     lis3dh::LatchInterruptRequest::Enable,
462    ///     lis3dh::Detect4D::Enable,
463    /// )?;
464    /// ```
465    pub async fn configure_irq_src_and_control<I: Interrupt>(
466        &mut self,
467        _int: I,
468        interrupt_mode: InterruptMode,
469        interrupt_config: InterruptConfig,
470        latch_interrupt_request: LatchInterruptRequest,
471        detect_4d: Detect4D,
472    ) -> Result<(), Error<CORE::BusError>> {
473        let latch_interrupt_request =
474            matches!(latch_interrupt_request, LatchInterruptRequest::Enable);
475
476        let detect_4d = matches!(detect_4d, Detect4D::Enable);
477
478        if latch_interrupt_request || detect_4d {
479            let latch = (latch_interrupt_request as u8) << I::lir_int_bit();
480            let d4d = (detect_4d as u8) << I::d4d_int_bit();
481            self.register_set_bits(Register::CTRL5, latch | d4d).await?;
482        }
483        self.write_register(I::cfg_reg(), interrupt_config.to_bits(interrupt_mode))
484            .await
485    }
486
487    /// Set the minimum duration for the Interrupt event to be recognized.
488    ///
489    /// Example: the event has to last at least 25 miliseconds to be recognized.
490    ///
491    /// ```rust,ignore
492    /// // let mut lis3dh = ...
493    /// let duration = Duration::miliseconds(DataRate::Hz_400, 25.0);
494    /// lis3dh.configure_irq_duration(duration);
495    /// ```
496    #[doc(alias = "INT1_DURATION")]
497    #[doc(alias = "INT2_DURATION")]
498    pub async fn configure_irq_duration<I: Interrupt>(
499        &mut self,
500        _int: I,
501        duration: Duration,
502    ) -> Result<(), Error<CORE::BusError>> {
503        self.write_register(I::duration_reg(), duration.0).await
504    }
505
506    /// Set the minimum magnitude for the Interrupt event to be recognized.
507    ///
508    /// Example: the event has to have a magnitude of at least 1.1g to be recognized.
509    ///
510    /// ```rust,ignore
511    /// // let mut lis3dh = ...
512    /// let threshold = Threshold::g(Range::G2, 1.1);
513    /// lis3dh.configure_irq_threshold(threshold);
514    /// ```
515    #[doc(alias = "INT1_THS")]
516    #[doc(alias = "INT2_THS")]
517    pub async fn configure_irq_threshold<I: Interrupt>(
518        &mut self,
519        _int: I,
520        threshold: Threshold,
521    ) -> Result<(), Error<CORE::BusError>> {
522        self.write_register(I::ths_reg(), threshold.0).await
523    }
524
525    /// Get interrupt source. The `interrupt_active` field is true when an interrupt is active.
526    /// The other fields specify what measurement caused the interrupt.
527    pub async fn get_irq_src<I: Interrupt>(
528        &mut self,
529        _int: I,
530    ) -> Result<InterruptSource, Error<CORE::BusError>> {
531        let irq_src = self.read_register(I::src_reg()).await?;
532        Ok(InterruptSource::from_bits(irq_src))
533    }
534
535    /// Configure 'Sleep to wake' and 'Return to sleep' threshold and duration.
536    ///
537    /// The LIS3DH can be programmed to automatically switch to low-power mode upon recognition of a determined event.  
538    /// Once the event condition is over, the device returns back to the preset normal or highresolution mode.
539    ///
540    /// Example: enter low-power mode. When a measurement above 1.1g is registered, then wake up
541    /// for 25ms to send the data.
542    ///
543    /// ```rust,ignore
544    /// // let mut lis3dh = ...
545    ///
546    /// let range = Range::default();
547    /// let data_rate = DataRate::Hz_400;
548    ///
549    /// let threshold = Threshold::g(range, 1.1);
550    /// let duration = Duration::miliseconds(data_rate, 25.0);
551    ///
552    /// lis3dh.configure_switch_to_low_power(threshold, duration)?;
553    ///
554    /// lis3dh.set_datarate(data_rate)?;
555    /// ```
556    #[doc(alias = "ACT_THS")]
557    #[doc(alias = "ACT_DUR")]
558    #[doc(alias = "act")]
559    pub async fn configure_switch_to_low_power(
560        &mut self,
561        threshold: Threshold,
562        duration: Duration,
563    ) -> Result<(), Error<CORE::BusError>> {
564        self.write_register(Register::ACT_THS, threshold.0 & 0b0111_1111)
565            .await?;
566        self.write_register(Register::ACT_DUR, duration.0).await
567    }
568
569    /// Reboot memory content
570    pub async fn reboot_memory_content(&mut self) -> Result<(), Error<CORE::BusError>> {
571        self.register_set_bits(Register::CTRL5, 0b1000_0000).await
572    }
573
574    const FIFO_ENABLE_BIT: u8 = 0b0100_0000;
575
576    /// Configures FIFO and then enables it
577    pub async fn enable_fifo(
578        &mut self,
579        mode: FifoMode,
580        threshold: u8,
581    ) -> Result<(), Error<CORE::BusError>> {
582        debug_assert!(threshold <= 0b0001_1111);
583
584        let bits = (threshold & 0b0001_1111) | mode.to_bits();
585        self.write_register(Register::FIFO_CTRL, bits).await?;
586        self.register_set_bits(Register::CTRL5, Self::FIFO_ENABLE_BIT)
587            .await
588    }
589
590    /// Disable FIFO. This resets the FIFO state
591    pub async fn disable_fifo(&mut self) -> Result<(), Error<CORE::BusError>> {
592        self.write_register(Register::FIFO_CTRL, 0x00).await?;
593        self.register_clear_bits(Register::CTRL5, Self::FIFO_ENABLE_BIT)
594            .await
595    }
596
597    /// Get the status of the FIFO
598    pub async fn get_fifo_status(&mut self) -> Result<FifoStatus, Error<CORE::BusError>> {
599        let status = self.read_register(Register::FIFO_SRC).await?;
600
601        Ok(FifoStatus::from_bits(status))
602    }
603
604    /// Get normalized ±g reading from the accelerometer. You should be reading
605    /// based on data ready interrupt or if reading in a tight loop you should
606    /// waiting for `is_data_ready`.
607    pub async fn accel_norm(&mut self) -> Result<F32x3, Error<CORE::BusError>> {
608        // The official driver from ST was used as a reference.
609        // https://github.com/STMicroelectronics/STMems_Standard_C_drivers/tree/master/lis3dh_STdC
610        let mode = self.get_mode().await?;
611        let range = self.get_range().await?;
612
613        // See "2.1 Mechanical characteristics" in the datasheet to find the
614        // values below. Scale values have all been divided by 1000 in order
615        // to convert the resulting values from mG to G, while avoiding doing
616        // any actual division on the hardware.
617        let scale = match (mode, range) {
618            // High Resolution mode
619            (Mode::HighResolution, Range::G2) => 0.001,
620            (Mode::HighResolution, Range::G4) => 0.002,
621            (Mode::HighResolution, Range::G8) => 0.004,
622            (Mode::HighResolution, Range::G16) => 0.012,
623            // Normal mode
624            (Mode::Normal, Range::G2) => 0.004,
625            (Mode::Normal, Range::G4) => 0.008,
626            (Mode::Normal, Range::G8) => 0.016,
627            (Mode::Normal, Range::G16) => 0.048,
628            // Low Power mode
629            (Mode::LowPower, Range::G2) => 0.016,
630            (Mode::LowPower, Range::G4) => 0.032,
631            (Mode::LowPower, Range::G8) => 0.064,
632            (Mode::LowPower, Range::G16) => 0.192,
633        };
634
635        // Depending on which Mode we are operating in, the data has different
636        // resolution. Using this knowledge, we determine how many bits the
637        // data needs to be shifted. This is necessary because the raw data
638        // is in left-justified two's complement and we would like for it to be
639        // right-justified instead.
640        let shift: u8 = match mode {
641            Mode::HighResolution => 4, // High Resolution:  12-bit
642            Mode::Normal => 6,         // Normal:           10-bit
643            Mode::LowPower => 8,       // Low Power:         8-bit
644        };
645
646        let acc_raw = self.accel_raw().await?;
647        let x = (acc_raw.x >> shift) as f32 * scale;
648        let y = (acc_raw.y >> shift) as f32 * scale;
649        let z = (acc_raw.z >> shift) as f32 * scale;
650
651        Ok(F32x3::new(x, y, z))
652    }
653
654    /// Get the sample rate of the accelerometer data.
655    pub async fn sample_rate(&mut self) -> Result<f32, Error<CORE::BusError>> {
656        Ok(self.get_datarate().await?.sample_rate())
657    }
658
659    /// Get raw acceleration data from the accelerometer. You should be reading
660    /// based on data ready interrupt or if reading in a tight loop you should
661    /// waiting for `is_data_ready`.
662    pub async fn accel_raw(&mut self) -> Result<I16x3, Error<CORE::BusError>> {
663        let accel_bytes = self.read_accel_bytes().await?;
664
665        let x = i16::from_le_bytes(accel_bytes[0..2].try_into().unwrap());
666        let y = i16::from_le_bytes(accel_bytes[2..4].try_into().unwrap());
667        let z = i16::from_le_bytes(accel_bytes[4..6].try_into().unwrap());
668
669        Ok(I16x3::new(x, y, z))
670    }
671}
672
673pub trait Lis3dhCore {
674    type BusError;
675
676    async fn write_register(
677        &mut self,
678        register: Register,
679        value: u8,
680    ) -> Result<(), Error<Self::BusError>>;
681
682    async fn read_register(&mut self, register: Register) -> Result<u8, Error<Self::BusError>>;
683
684    async fn read_accel_bytes(&mut self) -> Result<[u8; 6], Error<Self::BusError>>;
685}
686
687impl<CORE> Lis3dhCore for Lis3dh<CORE>
688where
689    CORE: Lis3dhCore,
690{
691    type BusError = CORE::BusError;
692
693    async fn write_register(
694        &mut self,
695        register: Register,
696        value: u8,
697    ) -> Result<(), Error<Self::BusError>> {
698        self.core.write_register(register, value).await
699    }
700
701    async fn read_register(&mut self, register: Register) -> Result<u8, Error<Self::BusError>> {
702        self.core.read_register(register).await
703    }
704
705    async fn read_accel_bytes(&mut self) -> Result<[u8; 6], Error<Self::BusError>> {
706        self.core.read_accel_bytes().await
707    }
708}
709
710/// Marker to indicate I2C is used to communicate with the Lis3dh
711pub struct Lis3dhI2C<I2C> {
712    /// Underlying I²C device
713    i2c: I2C,
714
715    /// Current I²C slave address
716    address: u8,
717}
718
719impl<I2C, E> Lis3dhCore for Lis3dhI2C<I2C>
720where
721    I2C: I2c<Error = E>,
722{
723    type BusError = E;
724
725    /// Write a byte to the given register.
726    async fn write_register(
727        &mut self,
728        register: Register,
729        value: u8,
730    ) -> Result<(), Error<Self::BusError>> {
731        if register.read_only() {
732            return Err(Error::WriteToReadOnly);
733        }
734
735        self.i2c
736            .write(self.address, &[register.addr(), value])
737            .await
738            .map_err(Error::Bus)
739    }
740
741    /// Read a byte from the given register.
742    async fn read_register(&mut self, register: Register) -> Result<u8, Error<Self::BusError>> {
743        let mut data = [0];
744
745        self.i2c
746            .write_read(self.address, &[register.addr()], &mut data)
747            .await
748            .map_err(Error::Bus)
749            .and(Ok(data[0]))
750    }
751
752    /// Read from the registers for each of the 3 axes.
753    async fn read_accel_bytes(&mut self) -> Result<[u8; 6], Error<Self::BusError>> {
754        let mut data = [0u8; 6];
755
756        self.i2c
757            .write_read(self.address, &[Register::OUT_X_L.addr() | 0x80], &mut data)
758            .await
759            .map_err(Error::Bus)
760            .and(Ok(data))
761    }
762}
763
764/// Marker to indicate SPI is used to communicate with the Lis3dh
765pub struct Lis3dhSPI<SPI> {
766    /// Underlying SPI device
767    spi: SPI,
768}
769
770impl<SPI, ESPI> Lis3dhSPI<SPI>
771where
772    SPI: SpiDevice<Error = ESPI>,
773{
774    /// Writes to many registers. Does not check whether all registers
775    /// can be written to
776    async unsafe fn write_multiple_regs(
777        &mut self,
778        start_register: Register,
779        data: &[u8],
780    ) -> Result<(), Error<ESPI>> {
781        self.spi
782            .transaction(&mut [
783                spi::Operation::Write(&[start_register.addr() | 0x40]),
784                spi::Operation::Write(data),
785            ])
786            .await
787            .map_err(Error::Bus)?;
788
789        Ok(())
790    }
791
792    /// Read from the registers for each of the 3 axes.
793    async fn read_multiple_regs(
794        &mut self,
795        start_register: Register,
796        buf: &mut [u8],
797    ) -> Result<(), Error<ESPI>> {
798        self.spi
799            .transaction(&mut [
800                spi::Operation::Write(&[start_register.addr() | 0xC0]),
801                spi::Operation::TransferInPlace(buf),
802            ])
803            .await
804            .map_err(Error::Bus)?;
805
806        Ok(())
807    }
808}
809
810impl<SPI, ESPI> Lis3dhCore for Lis3dhSPI<SPI>
811where
812    SPI: SpiDevice<Error = ESPI>,
813{
814    type BusError = ESPI;
815
816    /// Write a byte to the given register.
817    async fn write_register(
818        &mut self,
819        register: Register,
820        value: u8,
821    ) -> Result<(), Error<Self::BusError>> {
822        if register.read_only() {
823            return Err(Error::WriteToReadOnly);
824        }
825        unsafe { self.write_multiple_regs(register, &[value]).await }
826    }
827
828    /// Read a byte from the given register.
829    async fn read_register(&mut self, register: Register) -> Result<u8, Error<Self::BusError>> {
830        let mut data = [0];
831
832        self.spi
833            .transaction(&mut [
834                spi::Operation::Write(&[register.addr() | 0x80]),
835                spi::Operation::TransferInPlace(&mut data),
836            ])
837            .await
838            .map_err(Error::Bus)?;
839
840        Ok(data[0])
841    }
842
843    /// Read from the registers for each of the 3 axes.
844    async fn read_accel_bytes(&mut self) -> Result<[u8; 6], Error<Self::BusError>> {
845        let mut data = [0u8; 6];
846        self.read_multiple_regs(Register::OUT_X_L, &mut data)
847            .await?;
848        Ok(data)
849    }
850}
851
852/// Sensor configuration options
853#[derive(Debug, Clone, Copy)]
854#[cfg_attr(feature = "defmt", derive(defmt::Format))]
855pub struct Configuration {
856    /// The operating mode, default [`Mode::HighResolution`].
857    pub mode: Mode,
858    /// The output data rate, default [`DataRate::Hz_400`].
859    pub datarate: DataRate,
860    /// Measure changes in the x axis, default `true`.
861    pub enable_x_axis: bool,
862    /// Measure changes in the y axis, default `true`.
863    pub enable_y_axis: bool,
864    /// Measure changes in the z axis, default `true`.
865    pub enable_z_axis: bool,
866    /// When is data updated
867    ///
868    /// - when `true`: only after data is read
869    /// - when `false`: continually
870    ///
871    /// default `true`
872    pub block_data_update: bool,
873    /// Enable temperature measurements. When set, it implies `block_data_update = true`.
874    ///
875    /// default: `false`
876    pub enable_temperature: bool,
877}
878
879impl Default for Configuration {
880    fn default() -> Self {
881        Self {
882            enable_temperature: false,
883            block_data_update: true,
884            mode: Mode::HighResolution, // Question: should this be normal?
885            datarate: DataRate::Hz_400,
886            enable_x_axis: true,
887            enable_y_axis: true,
888            enable_z_axis: true,
889        }
890    }
891}