stk8ba58/registers/
mod.rs

1//! STK8BA58 register addresses
2#![allow(non_camel_case_types, clippy::unreadable_literal)]
3
4use accelerometer_hal::Error;
5use bitflags::{bitflags, Flags};
6use core::fmt::Debug;
7mod read;
8mod write;
9
10/// Register addresses
11/// Taken from the STK8BA58 data sheet (Register Map, p.13)
12/// <https://datasheet.lcsc.com/lcsc/2101081835_SENSORTEK-STK8BA58_C966931.pdf>
13#[derive(Copy, Clone, Debug, Eq, PartialEq)]
14#[repr(u8)]
15pub enum Register {
16    /// Contains the chip identification code.
17    CHIP_ID = 0x00,
18
19    /// XOUT1 contains the 4 LSBs of the X-axis acceleration data and the new data
20    /// flag for the X-axis
21    XOUT1 = 0x02,
22
23    /// XOUT2 contains the 8 MSBs of the X-axis acceleration data and the new data
24    /// flag for the X-axis
25    XOUT2 = 0x03,
26
27    /// YOUT1 contains the 4 LSBs of the Y-axis acceleration data and the new data
28    /// flag for the Y-axis
29    YOUT1 = 0x04,
30
31    /// YOUT2 contains the 8 MSBs of the Y-axis acceleration data and the new data
32    /// flag for the Y-axis
33    YOUT2 = 0x05,
34
35    /// ZOUT1 contains the 4 LSBs of the Z-axis acceleration data and the new data
36    /// flag for the Z-axis
37    ZOUT1 = 0x06,
38
39    /// ZOUT2 contains the 8 MSBs of the Z-axis acceleration data and the new data
40    /// flag for the Z-axis
41    ZOUT2 = 0x07,
42
43    /// Contains the interrupts' status
44    INTSTS1 = 0x09,
45
46    /// Contains the new data interrupt status
47    INTSTS2 = 0x0A,
48
49    /// Contains slope detection information
50    EVENTINFO1 = 0x0B,
51
52    /// Contains the acceleration sensing range
53    RANGESEL = 0x0F,
54
55    /// Contains the output bandwidth selection
56    BWSEL = 0x10,
57
58    /// Contains the power mode selection and the sleep time duration setting
59    POWMODE = 0x11,
60
61    /// Used to select if the output data is filtered or unfiltered
62    /// and how the output data contained in the register XOUT1/XOUT2,
63    /// YOUT1/YOUT2, ZOUT1/ZOUT2 is updated
64    DATASETUP = 0x13,
65
66    // Used to software reset. Write `0xB6` (`SWRST`) to reset all registers
67    // to the default value
68    SWRST = 0x14,
69
70    /// Contans the X, Y, Z slope interrupt enable bits
71    INTEN1 = 0x16,
72
73    /// Contains the new data interrupt bit
74    INTEN2 = 0x17,
75
76    /// Used to map the related interrupt to the desired INT pin
77    INTMAP1 = 0x19,
78
79    /// Used to map the related interrupt to the desired INT pin
80    INTMAP2 = 0x1A,
81
82    /// Used to the fine the INT1 pin output type and active level
83    INTCFG1 = 0x20,
84
85    /// Used to reset the latched interrupt pin and select the interrupt mode
86    INTCFG2 = 0x21,
87
88    /// Used to set the number of samples needed in slope detection
89    SLOPEDLY = 0x27,
90
91    /// Used to set the threshold value for slope detection
92    SLOPETHD = 0x28,
93
94    /// Used to set the skip time for significant motion
95    SIGMOT1 = 0x29,
96
97    /// Contains the MSB of the SKIP_TIME for the significant motion and the
98    /// significant motion interrupt enable bit
99    SIGMOT2 = 0x2A,
100
101    /// Used to set the proof time for the significant motion
102    SIGMOT3 = 0x2B,
103
104    /// Contains the digital interface parameters for the I2C interface
105    INTFCFG = 0x34,
106
107    /// Used to define the setting for the offset compensation
108    OFSTCOMP1 = 0x36,
109
110    /// Contains the offset compensation for the X-axis
111    OFSTX = 0x38,
112
113    /// Contains the offset compensation for the Y-axis
114    OFSTY = 0x39,
115
116    /// Contains the ofsset compensation for the Z-axis
117    OFSTZ = 0x3A,
118}
119
120impl Register {
121    /// Get register address
122    pub const fn addr(self) -> u8 {
123        self as u8
124    }
125
126    /// Returns if the register is read only or not
127    pub const fn read_only(self) -> bool {
128        matches!(
129            self,
130            Self::CHIP_ID
131                | Self::XOUT1
132                | Self::XOUT2
133                | Self::YOUT1
134                | Self::YOUT2
135                | Self::ZOUT1
136                | Self::ZOUT2
137                | Self::INTSTS1
138                | Self::INTSTS2
139                | Self::EVENTINFO1,
140        )
141    }
142}
143
144// Maybe this could be done with a derive?
145/// Expands to implement From<FLAGS_STRUCT> for Register so `.read_flags()` can be called for the
146/// type of flag passed
147macro_rules! reg_from_flags {
148    ($f:ident) => {
149        impl From<$f> for Register {
150            fn from(_value: $f) -> Self {
151                Self::$f
152            }
153        }
154    };
155}
156
157reg_from_flags!(INTSTS1);
158reg_from_flags!(INTSTS2);
159reg_from_flags!(EVENTINFO1);
160reg_from_flags!(POWMODE);
161reg_from_flags!(DATASETUP);
162reg_from_flags!(INTEN1);
163reg_from_flags!(INTEN2);
164reg_from_flags!(INTMAP1);
165reg_from_flags!(INTMAP2);
166reg_from_flags!(INTCFG1);
167reg_from_flags!(INTCFG2);
168reg_from_flags!(SIGMOT2);
169reg_from_flags!(INTFCFG);
170reg_from_flags!(OFSTCOMP1);
171
172/// `X`, `Y` and `Z` axis. Used for `.axis_lsb()`, `.axis_msb()` and `.axis_newdata()`
173pub enum Axis {
174    X,
175    Y,
176    Z,
177}
178
179bitflags! {
180    /// [`Register::INTSTS1`] options
181    #[derive(Copy, Clone)]
182    pub struct INTSTS1: u8 {
183        /// Significant motion interrupt status
184        const SIG_MOT_STS = 0b1;
185
186        /// Any-motion (slope) detection interrupt status
187        const ANY_MOT_STS = 0b100;
188    }
189
190    /// [`Register::INTSTS2`] options
191    #[derive(Copy, Clone)]
192    pub struct INTSTS2: u8 {
193        /// New data interrupt status
194        const DATA_STS = 0b1000_0000;
195    }
196
197    /// [`Register::EVENTINFO1`] options
198    #[derive(Copy, Clone)]
199    pub struct EVENTINFO1: u8 {
200        /// Slope interrupt triggered on the X axis
201        const SLP_1ST_X = 0b1;
202
203        /// Slope interrupt triggered on the Y axis
204        const SLP_1ST_Y = 0b10;
205
206        /// Slope interrupt triggered on the Z axis
207        const SLP_1ST_Z = 0b100;
208
209        /// Acceleration on the X axis was negative
210        const SLPSIGN_X = 0b1_0000;
211
212        /// Acceleration on the Y axis was negative
213        const SLPSIGN_Y = 0b10_0000;
214
215        /// Acceleration on the Z axis was negative
216        const SLPSIGN_Z = 0b100_0000;
217    }
218}
219
220/// Acceleration sensing ranges [`Register::RANGESEL`] supports
221#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
222#[repr(u8)]
223pub enum RangeSel {
224    /// ±2g
225    #[default]
226    PM2G = 0b0011,
227
228    /// ±4g
229    PM4G = 0b0101,
230
231    /// ±8g
232    PM8G = 0b1000,
233
234    /// Undefined range
235    Undefined = 0b0,
236}
237
238impl From<u8> for RangeSel {
239    fn from(value: u8) -> Self {
240        // Only last 4 bits are relevant
241        match value & 0b1111 {
242            0b0011 => Self::PM2G,
243            0b0101 => Self::PM4G,
244            0b1000 => Self::PM8G,
245            _ => Self::Undefined,
246        }
247    }
248}
249
250impl From<RangeSel> for Register {
251    fn from(_value: RangeSel) -> Self {
252        Self::RANGESEL
253    }
254}
255
256impl From<RangeSel> for f32 {
257    fn from(value: RangeSel) -> Self {
258        match value {
259            RangeSel::PM2G => 2.0,
260            RangeSel::PM4G => 4.0,
261            RangeSel::PM8G => 8.0,
262            RangeSel::Undefined => 0.0,
263        }
264    }
265}
266
267/// Bandwidths [`Register::BWSEL`] supports
268#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
269#[repr(u8)]
270pub enum BwSel {
271    /// 7.81Hz
272    Hz7C81 = 0b1000,
273
274    /// 15.63Hz
275    Hz15C64 = 0b1001,
276
277    /// 31.25Hz
278    Hz31C25 = 0b1010,
279
280    /// 62.5Hz
281    Hz62C5 = 0b1011,
282
283    /// 125Hz
284    Hz125 = 0b1100,
285
286    /// 250Hz
287    Hz250 = 0b1101,
288
289    /// 500Hz
290    Hz500 = 0b1110,
291
292    /// 1000Hz
293    #[default]
294    Hz1000 = 0b1111,
295}
296
297impl From<u8> for BwSel {
298    fn from(value: u8) -> Self {
299        // The 3 MSBs are reserved.
300        match value & 0b00011111 {
301            0..=0b1000 => Self::Hz7C81, // Anything smaller than 0b1001 is equal to 7.81Hz
302            0b1001 => Self::Hz15C64,
303            0b1010 => Self::Hz31C25,
304            0b1011 => Self::Hz62C5,
305            0b1100 => Self::Hz125,
306            0b1101 => Self::Hz250,
307            0b1110 => Self::Hz500,
308            _ => Self::Hz1000, // Anything larger than 0b1110 is equal to 1000Hz
309        }
310    }
311}
312
313impl From<BwSel> for f32 {
314    fn from(value: BwSel) -> Self {
315        match value {
316            BwSel::Hz7C81 => 7.81,
317            BwSel::Hz15C64 => 15.64,
318            BwSel::Hz31C25 => 31.25,
319            BwSel::Hz62C5 => 62.5,
320            BwSel::Hz125 => 125.0,
321            BwSel::Hz250 => 250.0,
322            BwSel::Hz500 => 500.0,
323            BwSel::Hz1000 => 1000.0,
324        }
325    }
326}
327
328impl From<BwSel> for Register {
329    fn from(_value: BwSel) -> Self {
330        Self::BWSEL
331    }
332}
333
334/// Sleep durations [`Register::POWMODE`] supports
335#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
336#[repr(u8)]
337pub enum SleepDuration {
338    /// 0.5ms
339    #[default]
340    Ms0C5 = 0b0101_0,
341
342    /// 1ms
343    Ms1 = 0b0110_0,
344
345    /// 2ms
346    Ms2 = 0b0111_0,
347
348    /// 4ms
349    Ms4 = 0b1000_0,
350
351    /// 6ms
352    Ms6 = 0b1001_0,
353
354    /// 10ms
355    Ms10 = 0b1010_0,
356
357    /// 25ms
358    Ms25 = 0b1011_0,
359
360    /// 50ms
361    Ms50 = 0b1100_0,
362
363    /// 100ms
364    Ms100 = 0b1101_0,
365
366    /// 500ms
367    Ms500 = 0b1110_0,
368
369    /// 1000ms
370    Ms1000 = 0b1111_0,
371}
372
373impl From<u8> for SleepDuration {
374    fn from(value: u8) -> Self {
375        // Only bits 4-1 are relevant
376        match value & 0b1111_0 {
377            0b0110_0 => Self::Ms1,
378            0b0111_0 => Self::Ms2,
379            0b1000_0 => Self::Ms4,
380            0b1001_0 => Self::Ms6,
381            0b1010_0 => Self::Ms10,
382            0b1011_0 => Self::Ms25,
383            0b1100_0 => Self::Ms50,
384            0b1101_0 => Self::Ms100,
385            0b1110_0 => Self::Ms500,
386            0b1111_0 => Self::Ms1000,
387            _ => Self::Ms0C5, // Anything smaller than 0b0110_0 is 0.5ms
388        }
389    }
390}
391
392impl From<SleepDuration> for Register {
393    fn from(_value: SleepDuration) -> Self {
394        Self::POWMODE
395    }
396}
397
398bitflags! {
399    /// [`Register::POWMODE`] options
400    #[derive(Copy, Clone)]
401    pub struct POWMODE: u8 {
402        /// Enable low-power mode (Default: Disabled)
403        const LOWPOWER = 0b01000000;
404
405        /// Enable suspend mode (Default: Disabled)
406        const SUSPEND = 0b10000000;
407    }
408
409    /// [`Register::DATASETUP`] options
410    #[derive(Copy, Clone)]
411    pub struct DATASETUP: u8 {
412        /// Disable data protection function (Default: Enabled)
413        const PROTECT_DIS = 0b01000000;
414
415        /// Disable data filtering (Default: Enabled)
416        const DATA_SEL = 0b10000000;
417    }
418
419    /// [`Register::INTEN1`] options
420    #[derive(Copy, Clone)]
421    pub struct INTEN1: u8 {
422        /// Enable X-axis any-motion (slope) interrupt
423        /// (Default: Disabled)
424        const SLP_EN_X = 0b00000001;
425
426        /// Enable Y-axis any-motion (slope) interrupt
427        /// (Default: Disabled)
428        const SLP_EN_Y = 0b00000010;
429
430        /// Enable Z-axis any-motion (slope) interrupt
431        /// (Default: Disabled)
432        const SLP_EN_Z = 0b00000100;
433    }
434
435    /// [`Register::INTEN2`] options
436    #[derive(Copy, Clone)]
437    pub struct INTEN2: u8 {
438        /// Enable new data interrupt
439        /// (Default: Disabled)
440        const DATA_EN = 0b00001000;
441    }
442
443    /// [`Register::INTMAP1`] options
444    #[derive(Copy, Clone)]
445    pub struct INTMAP1: u8 {
446        /// Map significant motion interrupt to INT1
447        /// (Default: Disabled)
448        const SIGMOT2INT1 = 0b00000001;
449
450        /// Map any-motion (slope) interrupt to INT1
451        /// (Default: Disabled)
452        const ANYMOT2INT1 = 0b0000100;
453    }
454
455    /// [`Register::INTMAP2`] options
456    #[derive(Copy, Clone)]
457    pub struct INTMAP2: u8 {
458        /// Map new data interrput to INT1
459        /// (Default: Disabled)
460        const DATA2INT1 = 0b00000001;
461    }
462
463    /// [`Register::INTCFG1`] options
464    #[derive(Copy, Clone)]
465    pub struct INTCFG1: u8 {
466        /// Set INT1 to active high (Default: Enabled)
467        const INT1_LV = 0b00000001;
468
469        /// Set INT1 to open drain output (Default: Disabled, Push-pull output)
470        const INT1_OD = 0b00000010;
471    }
472}
473
474/// Interrupt latch modes [`Register::INTCFG2`] supports
475#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
476#[repr(u8)]
477pub enum IntLatch {
478    #[default]
479    NON_LATCHED = 0b0000,
480    LATCHED = 0b0111,
481
482    /// Temporary 250us interrupt signal
483    TEMP250US = 0b1001,
484
485    /// Temporary 500us interrupt signal
486    TEMP500US = 0b1010,
487
488    /// Temporary 1ms interrupt signal
489    TEMP1MS = 0b1011,
490
491    /// Temporary 12.5ms interrupt signal
492    TEMP12C5MS = 0b1100,
493
494    /// Temporary 25ms interrupt signal
495    TEMP25MS = 0b1101,
496
497    /// Temporary 50ms interrupt signal
498    TEMP50MS = 0b1110,
499
500    /// Temporary 250ms interrupt signal
501    TEMP250MS = 0b0001,
502
503    /// Temporary 500ms interrupt signal
504    TEMP500MS = 0b0010,
505
506    /// Temporary 1s interrupt signal
507    TEMP1S = 0b0011,
508
509    /// Temporary 2s interrupt signal
510    TEMP2S = 0b0100,
511
512    /// Temporary 4s interrupt signal
513    TEMP4S = 0b0101,
514
515    /// Temporary 8s interrupt signal
516    TEMP8S = 0b0110,
517}
518
519impl From<u8> for IntLatch {
520    fn from(value: u8) -> Self {
521        match value & 0b1111 {
522            0b0111 | 0b1111 => Self::LATCHED,
523            0b0001 => Self::TEMP250MS,
524            0b0010 => Self::TEMP500MS,
525            0b0011 => Self::TEMP1S,
526            0b0100 => Self::TEMP2S,
527            0b0101 => Self::TEMP4S,
528            0b0110 => Self::TEMP8S,
529            0b1001 => Self::TEMP250US,
530            0b1010 => Self::TEMP500US,
531            0b1011 => Self::TEMP1MS,
532            0b1100 => Self::TEMP12C5MS,
533            0b1101 => Self::TEMP25MS,
534            0b1110 => Self::TEMP50MS,
535            _ => Self::NON_LATCHED,
536        }
537    }
538}
539
540impl From<IntLatch> for Register {
541    fn from(_value: IntLatch) -> Self {
542        Self::INTCFG2
543    }
544}
545
546bitflags! {
547    /// Reset any latched interrupt pins
548    #[derive(Copy, Clone)]
549    pub struct INTCFG2: u8 {
550        const INT_RST = 0b10000000;
551    }
552
553    /// [`Register::SIGMOT2`] options
554    #[derive(Copy, Clone)]
555    pub struct SIGMOT2: u8 {
556        /// Enable significant motion (Default: Enabled)
557        const SIG_MOT_EN = 0b00000010;
558
559        /// Enable any-motion (Default: Disabled)
560        const ANY_MOT_EN = 0b00000100;
561    }
562
563    /// [`Register::INTFCFG`] options
564    #[derive(Copy, Clone)]
565    pub struct INTFCFG: u8 {
566        /// Set watchdog timer to 50ms (Default: 1ms)
567        const I2C_WDT_SEL = 0b00000010;
568
569        /// Enable I2C watchdog timer (Default: Disabled)
570        const I2C_WDT_EN = 0b00000100;
571    }
572
573    /// Reset offset compensation registers
574    #[derive(Copy, Clone)]
575    pub struct OFSTCOMP1: u8 {
576        const OFST_RST = 0b10000000;
577    }
578}
579
580/// Import this trait if you want to read from the accelerometer's registers
581pub trait Read<I2C, E> {
582    fn chip_id(&mut self) -> Result<u8, E>;
583    fn axis_lsb(&mut self, axis: &Axis) -> Result<u8, E>;
584    fn axis_msb(&mut self, axis: &Axis) -> Result<u8, E>;
585    fn axis_newdata(&mut self, axis: &Axis) -> Result<bool, E>;
586
587    fn read_flags<F: Flags<Bits = u8> + Into<Register>>(&mut self, flags: F) -> Result<F, E>;
588    fn read_mode<M: From<u8> + Into<Register>>(&mut self, mode: M) -> Result<M, E>;
589}
590
591/// Import this trait if you want to write to the accelerometer's registers
592pub trait Write<I2C, E>
593where
594    E: Debug,
595{
596    fn set_range(&mut self, range: RangeSel) -> Result<&mut Self, Error<E>>;
597    fn set_bandwidth(&mut self, bandwidth: BwSel) -> Result<&mut Self, Error<E>>;
598    fn set_sleep_duration(&mut self, sleep_duration: SleepDuration) -> Result<&mut Self, Error<E>>;
599    fn set_int_latch(&mut self, latch: IntLatch) -> Result<&mut Self, Error<E>>;
600
601    fn set_flags<F: Flags<Bits = u8> + Into<Register> + Copy>(
602        &mut self,
603        flags: F,
604    ) -> Result<&mut Self, Error<E>>;
605
606    fn reset_all(&mut self) -> Result<&mut Self, Error<E>>;
607}