mc3479/lib.rs
1#![no_std]
2//! # MC3479
3//!
4//! A Rust driver for the MEMSIC MC3479 16-bit 3-axis accelerometer.
5//!
6//! The device has two different operational states, standby and wake, and reconfiguring the device
7//! is only allowed in the standby state. These two states are realized in the form of two
8//! different Rust types, [`StandbyState`] and [`WakeState`], with methods that allow for
9//! transitioning from one state to the other.
10//!
11//! ## Example
12//!
13//! ```rust
14//! # use embedded_hal::i2c::I2c;
15//! # use mc3479::{SampleRate, Range, TargetAddr};
16//! # fn example<I2C: I2c>(i2c: I2C) {
17//! let mut standby = match mc3479::StandbyState::new(i2c, TargetAddr::Addr0) {
18//! Ok(standby) => standby,
19//! Err((err, _i2c)) => {
20//! panic!("Failed to initialize MC3479 driver: {err}");
21//! },
22//! };
23//! standby.set_sample_rate(SampleRate::_1000Hz).unwrap();
24//! standby.set_range(Range::_8g).unwrap();
25//! standby.set_fifo_enabled(true).unwrap();
26//! let wake = match standby.wake() {
27//! Ok(wake) => wake,
28//! Err((err, _standby)) => panic!("Failed to transition to wake state: {err}"),
29//! };
30//! # }
31//! ```
32
33use core::{error::Error, fmt::Debug, fmt::Display};
34
35pub use crate::{
36 inner::{
37 fifo_control_register::FifoControl, fifo_status_register::FifoStatus,
38 range_register::Range, sample_rate_register::SampleRate,
39 },
40 standby_state::{InitializationError, StandbyState},
41 wake_state::WakeState,
42};
43
44mod inner;
45mod standby_state;
46mod wake_state;
47
48/// Expected chip ID of the device.
49pub const MC3479_CHIP_ID: u8 = 0xA4;
50
51/// # I2C address of the target
52///
53/// The device is available either at address 0x4C or 0x6C depending on whether or not the
54/// `DOUT_A6` pin is tied low or high.
55#[derive(Clone, Copy, Debug)]
56#[repr(u8)]
57pub enum TargetAddr {
58 Addr0 = 0x4C,
59 Addr1 = 0x6C,
60}
61
62#[derive(Clone, Copy, Debug)]
63pub enum Register {
64 DevStat = 0x05,
65 Mode = 0x07,
66 SampleRate = 0x08,
67 FifoStatus = 0x0A,
68 XoutLow = 0x0D,
69 ChipId = 0x18,
70 RangeAndScaleCtrl = 0x20,
71 FifoControl = 0x2D,
72}
73
74/// Accelerometer sensor values expressed in milli g-force.
75pub struct AccelerometerData {
76 pub x_mg: f32,
77 pub y_mg: f32,
78 pub z_mg: f32,
79}
80
81#[derive(Debug)]
82pub struct I2cReadError<I2cError> {
83 pub register: Register,
84 pub source: I2cError,
85}
86
87impl<I2cError> Display for I2cReadError<I2cError> {
88 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
89 write!(
90 f,
91 "Could not read from register {:?} ({:#X})",
92 self.register, self.register as u8,
93 )
94 }
95}
96
97impl<I2cError> Error for I2cReadError<I2cError>
98where
99 Self: Debug,
100{
101 // We can't implement `source` because `embedded_hal::i2c::Error` doesn't require
102 // `core::error::Error`
103}
104
105#[derive(Debug)]
106pub struct I2cWriteError<I2cError> {
107 pub register: Register,
108 pub source: I2cError,
109}
110
111impl<I2cError> Display for I2cWriteError<I2cError> {
112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
113 write!(
114 f,
115 "Could not write to register {:?} ({:#X})",
116 self.register, self.register as u8,
117 )
118 }
119}
120
121impl<I2cError> Error for I2cWriteError<I2cError>
122where
123 Self: Debug,
124{
125 // We can't implement `source` because `embedded_hal::i2c::Error` doesn't require
126 // `core::error::Error`
127}