initial commit

This commit is contained in:
baldeau 2025-02-23 21:24:37 +01:00
commit b368f6200c
56 changed files with 2573 additions and 0 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[registries.crates-io]
protocol = "sparse"

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.pdf filter=lfs diff=lfs merge=lfs -text

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
/Cargo.lock
.vscode/

34
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,34 @@
default:
# https://gitlab.com/mtczekajlo/lsm6ds3tr-rs-docker
image: registry.gitlab.com/mtczekajlo/lsm6ds3tr-rs-docker:f3598e64faee1b7e66b2bb792fce3290
stages:
- check
- build
- test
check:
stage: check
dependencies: []
script:
- ci/jobs/check
doc:
stage: check
dependencies: []
script:
- ci/jobs/doc
build:
stage: build
needs: ["check"]
dependencies: ["check"]
script:
- ci/jobs/build
test:
stage: test
needs: ["build"]
dependencies: ["build"]
script:
- ci/jobs/test

19
Cargo.toml Normal file
View File

@ -0,0 +1,19 @@
[package]
name = "lsm6ds3tr"
version = "0.3.0"
edition = "2021"
description = "LSM6DS3TR 6-axis (DOF) IMU accelerometer & gyroscope rust driver library"
authors = ["Marcin Czekajło <mtczekajlo@gmail.com>"]
repository = "https://gitlab.com/mtczekajlo/lsm6ds3tr-rs"
readme = "readme.md"
license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
defmt = { version = "0.3.6", optional = true }
embedded-hal = "1.0.0"
heapless = "0.8.0"
[features]
default = []
defmt = ["dep:defmt"]

6
ci/build Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo build "$@"

6
ci/cargo-sort Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo sort --check "$@"

6
ci/check Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo check "$@"

6
ci/clippy Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo clippy "$@" -- --deny warnings

6
ci/doc Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo doc "$@"

6
ci/format Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo fmt -- --check

9
ci/jobs/build Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
ci/build
ci/build --features defmt
ci/build --release
ci/build --features defmt --release

15
ci/jobs/check Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
ci/format
ci/check
ci/check --features defmt
ci/check --release
ci/check --features defmt --release
ci/clippy
ci/clippy --release
ci/cargo-sort
ci/udeps
ci/udeps --release

7
ci/jobs/doc Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
ci/doc
ci/doc --features defmt

7
ci/jobs/test Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
ci/test
ci/test --release

9
ci/pipeline Executable file
View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
./ci/jobs/check
./ci/jobs/build
./ci/jobs/test
./ci/jobs/doc

6
ci/test Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo test "$@"

6
ci/udeps Executable file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -xEeuo pipefail
cd "$(git rev-parse --show-toplevel)"
cargo +nightly udeps "$@"

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0e2089de13ab537736e174c76eaee17fc6ac164c69324862716859688db9e963
size 135994

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:15b90b0ccca09f1cd6f561ecc67c7620714f452ad3f2c07e0f1cbce7e1ebb1c6
size 1577264

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:251737db70e3b6cdc217a5681dd4634a05faffd5288aff6a576078a6464a1b2b
size 1839683

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:541e1501d15cc3a1be1e45f4e98a91d4005c9e94b471407ed3b9775fe4023c5d
size 220256

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0837f80f41f215a1ee9556bdb0c3637f0c36e23e422320832dfa223b3bd87ea0
size 202544

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:21ad5fa9ea2ae4076585c569bd8ffc502221fe9b700b2a7a04767b412535ff48
size 631742

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f6eb4483119f6fadc3088f7318078743a58c6bca5738383ea98f37c3d0066e19
size 197066

21
license Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Marcin Czekajło
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

5
readme.md Normal file
View File

@ -0,0 +1,5 @@
# LSM6DS3TR-C Rust
LSM6DS3TR-C 6-axis (DOF) IMU accelerometer & gyroscope rust driver library.
_Inspired by [LSM9DS1 rust driver](https://gitlab.com/mtczekajlo/lsm6ds3tr-rs)._

8
src/consts.rs Normal file
View File

@ -0,0 +1,8 @@
/// LSM6DS3TR-C's ID
pub const LSM6DS3TR_ID: u8 = 0x6A;
/// Temperature scale = 256 LSB/°C
pub const TEMP_SCALE: f32 = 256.0;
/// The output of the temperature sensor is 0 (typ.) at 25 °C
pub const TEMP_BIAS: f32 = 25.0;

28
src/data.rs Normal file
View File

@ -0,0 +1,28 @@
use core::fmt::{Display, Result};
#[allow(clippy::upper_case_acronyms)]
#[derive(Default)]
pub struct XYZ<T> {
pub x: T,
pub y: T,
pub z: T,
}
impl<T> Display for XYZ<T>
where
T: Display,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result {
write!(f, "X:{} Y:{} Z:{}", self.x, self.y, self.z)
}
}
#[cfg(feature = "defmt")]
impl<T> defmt::Format for XYZ<T>
where
T: defmt::Format,
{
fn format(&self, f: defmt::Formatter) {
defmt::write!(f, "X:{} Y:{} Z:{}", self.x, self.y, self.z)
}
}

34
src/interface/i2c.rs Normal file
View File

@ -0,0 +1,34 @@
use embedded_hal::i2c::I2c;
use super::Interface;
const I2C_ADDRESS: u8 = 0x6A;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub enum InterfaceE<CommE> {
Comm(CommE),
}
/// I2C communication interface
pub struct I2cInterface<I2C> {
i2c: I2C,
}
impl<I2C> I2cInterface<I2C> {
pub fn new(i2c: I2C) -> Self {
Self { i2c }
}
}
impl<I2C: I2c> Interface for I2cInterface<I2C> {
type Error = I2C::Error;
fn write(&mut self, addr: u8, value: u8) -> Result<(), Self::Error> {
self.i2c.write(I2C_ADDRESS, &[addr, value])
}
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.i2c.write_read(I2C_ADDRESS, &[addr], buffer)
}
}

13
src/interface/mod.rs Normal file
View File

@ -0,0 +1,13 @@
pub mod i2c;
pub mod spi;
pub use self::i2c::I2cInterface;
pub use self::spi::SpiInterface;
/// Communication interface
pub trait Interface {
type Error;
fn write(&mut self, addr: u8, value: u8) -> Result<(), Self::Error>;
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error>;
}

34
src/interface/spi.rs Normal file
View File

@ -0,0 +1,34 @@
use embedded_hal::spi::{Operation, SpiDevice};
use super::Interface;
/// SPI communication interface
pub struct SpiInterface<SPI> {
spi: SPI,
}
impl<SPI> SpiInterface<SPI> {
pub fn new(spi: SPI) -> Self {
Self { spi }
}
}
impl<SPI> Interface for SpiInterface<SPI>
where
SPI: SpiDevice,
{
type Error = SPI::Error;
fn write(&mut self, addr: u8, value: u8) -> Result<(), Self::Error> {
let bytes = [addr, value];
self.spi.write(&bytes)
}
fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
self.spi.transaction(&mut [
Operation::Write(&[0b1000_0000 | addr]),
Operation::Read(buffer),
])?;
Ok(())
}
}

220
src/lib.rs Normal file
View File

@ -0,0 +1,220 @@
#![cfg_attr(not(test), no_std)]
#![allow(dead_code)]
#![allow(async_fn_in_trait)]
mod consts;
mod data;
pub mod interface;
pub mod registers;
mod settings;
use heapless::Vec;
use consts::*;
pub use data::XYZ;
use interface::Interface;
pub use registers::{AccelSampleRate, AccelScale, InactivityGyroMode};
use registers::{
Ctrl3C, GyroSampleRate, GyroScale, RegisterAddress, RegisterBits, RegisterConfig,
RegisterValue, TapSrc, WakeUpSrc,
};
pub use settings::{
irq::{InterruptRoute, TapIrqSettings, TapRecognitionMode},
AccelSettings, GyroSettings, IrqSettings, LsmSettings,
};
/// Device driver
pub struct LSM6DS3TR<I>
where
I: Interface,
{
interface: I,
pub settings: LsmSettings,
}
impl<I> LSM6DS3TR<I>
where
I: Interface,
{
/// Returns uninitialized device object with default settings
pub fn new(interface: I) -> Self {
Self {
interface,
settings: Default::default(),
}
}
/// Returns uninitialized device object with provided settings
pub fn with_settings(mut self, settings: LsmSettings) -> Self {
self.settings = settings;
self
}
/// Initializes device with stored settings
pub fn init(&mut self) -> Result<(), I::Error> {
self.init_accel()?;
self.init_gyro()?;
self.init_irqs()?;
self.init_other()?;
Ok(())
}
/// Returns if device is reachable
pub fn is_reachable(&mut self) -> Result<bool, I::Error> {
Ok(self.read_register(RegisterAddress::WHO_AM_I.address())? == LSM6DS3TR_ID)
}
/// Performs a software reset
pub fn software_reset(&mut self) -> Result<(), I::Error> {
let ctrl3_c = Ctrl3C {
software_reset: RegisterBits::new(1),
..Default::default()
};
self.write_register_config(ctrl3_c.config())?;
Ok(())
}
/// Initializes accelerometer with stored settings
pub fn init_accel(&mut self) -> Result<(), I::Error> {
self.write_register_config(self.settings.accel.config())?;
Ok(())
}
/// Initializes gyroscope with stored settings
pub fn init_gyro(&mut self) -> Result<(), I::Error> {
self.write_register_config(self.settings.gyro.config())?;
Ok(())
}
/// Initializes interrupts with stored settings
pub fn init_irqs(&mut self) -> Result<(), I::Error> {
for config in self.settings.irq.configs() {
self.write_register_config(config)?;
}
Ok(())
}
/// Initializes other options with stored settings
pub fn init_other(&mut self) -> Result<(), I::Error> {
if self.settings.low_performance_mode {
self.write_register(RegisterAddress::CTRL6_C.address(), 1 << 4)?; // TODO make it right like the others
self.write_register(RegisterAddress::CTRL7_G.address(), 1 << 7)?; // TODO make it right like the others
}
Ok(())
}
/// Returns accelerometer raw readings
pub fn read_accel_raw(&mut self) -> Result<XYZ<i16>, I::Error> {
self.read_sensor_raw(RegisterAddress::OUTX_L_XL.address())
}
/// Returns accelerometer scaled readings \[g]
pub fn read_accel(&mut self) -> Result<XYZ<f32>, I::Error> {
let xyz = self.read_accel_raw()?;
let sensitivity = self.settings.accel.scale.sensitivity();
Ok(XYZ {
x: xyz.x as f32 * sensitivity,
y: xyz.y as f32 * sensitivity,
z: xyz.z as f32 * sensitivity,
})
}
/// Returns gyroscope raw readings
pub fn read_gyro_raw(&mut self) -> Result<XYZ<i16>, I::Error> {
self.read_sensor_raw(RegisterAddress::OUTX_L_G.address())
}
/// Returns gyroscope scaled readings [°/s]
pub fn read_gyro(&mut self) -> Result<XYZ<f32>, I::Error> {
let xyz = self.read_gyro_raw()?;
let sensitivity = self.settings.gyro.scale.sensitivity();
Ok(XYZ {
x: xyz.x as f32 * sensitivity,
y: xyz.y as f32 * sensitivity,
z: xyz.z as f32 * sensitivity,
})
}
/// Returns temperature sensor raw reading
pub fn read_temp_raw(&mut self) -> Result<i16, I::Error> {
let mut bytes = [0u8; 2];
self.interface
.read(RegisterAddress::OUT_TEMP_L.address(), &mut bytes)?;
let temp: i16 = (bytes[1] as i16) << 8 | bytes[0] as i16;
Ok(temp)
}
/// Returns temperature sensor scaled reading [°C]
pub fn read_temp(&mut self) -> Result<f32, I::Error> {
let temp = self.read_temp_raw()?;
Ok(temp as f32 / TEMP_SCALE + TEMP_BIAS)
}
/// Returns last interrupt sources
pub fn read_interrupt_sources(&mut self) -> Result<Vec<IrqSource, 2>, I::Error> {
let mut wake_up_src = WakeUpSrc::default();
let mut tap_src = TapSrc::default();
// TODO add FUNC_SRC1 reading
// TODO add FUNC_SRC2 reading
wake_up_src = self.read_register(wake_up_src.address())?.into();
tap_src = self.read_register(tap_src.address())?.into();
let mut irq_sources = Vec::new();
for source in wake_up_src.get_irq_sources() {
irq_sources.push(source).unwrap();
}
for source in tap_src.get_irq_sources() {
irq_sources.push(source).unwrap();
}
Ok(irq_sources)
}
fn read_sensor_raw(&mut self, addr: u8) -> Result<XYZ<i16>, I::Error> {
let mut bytes = [0u8; 6];
self.interface.read(addr, &mut bytes)?;
let x: i16 = (bytes[1] as i16) << 8 | bytes[0] as i16;
let y: i16 = (bytes[3] as i16) << 8 | bytes[2] as i16;
let z: i16 = (bytes[5] as i16) << 8 | bytes[4] as i16;
Ok(XYZ { x, y, z })
}
fn read_register(&mut self, address: u8) -> Result<u8, I::Error> {
let mut value = [0u8];
self.interface.read(address, &mut value)?;
Ok(value[0])
}
fn write_register(&mut self, address: u8, value: u8) -> Result<(), I::Error> {
self.interface.write(address, value)?;
Ok(())
}
fn read_register_config(&mut self, address: u8) -> Result<RegisterConfig, I::Error> {
let mut value = [0u8];
self.interface.read(address, &mut value)?;
let value = value[0];
Ok(RegisterConfig { address, value })
}
fn write_register_config(&mut self, register_config: RegisterConfig) -> Result<(), I::Error> {
self.write_register(register_config.address, register_config.value)?;
Ok(())
}
}
/// Interrupt sources
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum IrqSource {
FreeFall,
Sleep,
WakeUp,
WakeUpOnX,
WakeUpOnY,
WakeUpOnZ,
Tap,
SingleTap,
DoubleTap,
TapOnX,
TapOnY,
TapOnZ,
}

540
src/registers/addresses.rs Normal file
View File

@ -0,0 +1,540 @@
/// Registers list
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
pub enum RegisterAddress {
// RESERVED = 0x00,
/// Embedded functions configuration register
FUNC_CFG_ACCESS = 0x01,
// RESERVED = [0x02..0x03],
/// Sensor sync configuration register
SENSOR_SYNC_TIME_FRAME = 0x04,
/// Sensor sync configuration register
SENSOR_SYNC_RES_RATIO = 0x05,
/// FIFO configuration registers
FIFO_CTRL1 = 0x06,
/// FIFO configuration registers
FIFO_CTRL2 = 0x07,
/// FIFO configuration registers
FIFO_CTRL3 = 0x08,
/// FIFO configuration registers
FIFO_CTRL4 = 0x09,
/// FIFO configuration registers
FIFO_CTRL5 = 0x0A,
/// (no comment)
DRDY_PULSE_CFG_G = 0x0B,
// RESERVED = 0x0C,
/// INT1 pin control
INT1_CTRL = 0x0D,
/// INT2 pin control
INT2_CTRL = 0x0E,
/// Who I am ID
WHO_AM_I = 0x0F,
/// Accelerometer and gyroscope control registers
CTRL1_XL = 0x10,
/// Accelerometer and gyroscope control registers
CTRL2_G = 0x11,
/// Accelerometer and gyroscope control registers
CTRL3_C = 0x12,
/// Accelerometer and gyroscope control registers
CTRL4_C = 0x13,
/// Accelerometer and gyroscope control registers
CTRL5_C = 0x14,
/// Accelerometer and gyroscope control registers
CTRL6_C = 0x15,
/// Accelerometer and gyroscope control registers
CTRL7_G = 0x16,
/// Accelerometer and gyroscope control registers
CTRL8_XL = 0x17,
/// Accelerometer and gyroscope control registers
CTRL9_XL = 0x18,
/// Accelerometer and gyroscope control registers
CTRL10_C = 0x19,
/// I2C master configuration register
MASTER_CONFIG = 0x1A,
/// Interrupt registers
WAKE_UP_SRC = 0x1B,
/// Interrupt registers
TAP_SRC = 0x1C,
/// Interrupt registers
D6D_SRC = 0x1D,
/// Status data register for user interface
STATUS_REG = 0x1E,
// RESERVED = 0x1F,
/// Temperature output data registers
OUT_TEMP_L = 0x20,
/// Temperature output data registers
OUT_TEMP_H = 0x21,
/// Gyroscope output registers for user interface
OUTX_L_G = 0x22,
/// Gyroscope output registers for user interface
OUTX_H_G = 0x23,
/// Gyroscope output registers for user interface
OUTY_L_G = 0x24,
/// Gyroscope output registers for user interface
OUTY_H_G = 0x25,
/// Gyroscope output registers for user interface
OUTZ_L_G = 0x26,
/// Gyroscope output registers for user interface
OUTZ_H_G = 0x27,
/// Accelerometer output registers
OUTX_L_XL = 0x28,
/// Accelerometer output registers
OUTX_H_XL = 0x29,
/// Accelerometer output registers
OUTY_L_XL = 0x2A,
/// Accelerometer output registers
OUTY_H_XL = 0x2B,
/// Accelerometer output registers
OUTZ_L_XL = 0x2C,
/// Accelerometer output registers
OUTZ_H_XL = 0x2D,
/// Sensor hub output registers
SENSORHUB1_REG = 0x2E,
/// Sensor hub output registers
SENSORHUB2_REG = 0x2F,
/// Sensor hub output registers
SENSORHUB3_REG = 0x30,
/// Sensor hub output registers
SENSORHUB4_REG = 0x31,
/// Sensor hub output registers
SENSORHUB5_REG = 0x32,
/// Sensor hub output registers
SENSORHUB6_REG = 0x33,
/// Sensor hub output registers
SENSORHUB7_REG = 0x34,
/// Sensor hub output registers
SENSORHUB8_REG = 0x35,
/// Sensor hub output registers
SENSORHUB9_REG = 0x36,
/// Sensor hub output registers
SENSORHUB10_REG = 0x37,
/// Sensor hub output registers
SENSORHUB11_REG = 0x38,
/// Sensor hub output registers
SENSORHUB12_REG = 0x39,
/// FIFO status registers
FIFO_STATUS1 = 0x3A,
/// FIFO status registers
FIFO_STATUS2 = 0x3B,
/// FIFO status registers
FIFO_STATUS3 = 0x3C,
/// FIFO status registers
FIFO_STATUS4 = 0x3D,
/// FIFO data output registers
FIFO_DATA_OUT_L = 0x3E,
/// FIFO data output registers
FIFO_DATA_OUT_H = 0x3F,
/// Timestamp output registers
TIMESTAMP0_REG = 0x40,
/// Timestamp output registers
TIMESTAMP1_REG = 0x41,
/// Timestamp output registers
TIMESTAMP2_REG = 0x42,
// RESERVED = [0x43..0x48],
/// Step counter timestamp registers
STEP_TIMESTAMP_L = 0x49,
/// Step counter timestamp registers
STEP_TIMESTAMP_H = 0x4A,
/// Step counter output registers
STEP_COUNTER_L = 0x4B,
/// Step counter output registers
STEP_COUNTER_H = 0x4C,
/// Sensor hub output registers
SENSORHUB13_REG = 0x4D,
/// Sensor hub output registers
SENSORHUB14_REG = 0x4E,
/// Sensor hub output registers
SENSORHUB15_REG = 0x4F,
/// Sensor hub output registers
SENSORHUB16_REG = 0x50,
/// Sensor hub output registers
SENSORHUB17_REG = 0x51,
/// Sensor hub output registers
SENSORHUB18_REG = 0x52,
/// Interrupt registers
FUNC_SRC1 = 0x53,
/// Interrupt registers
FUNC_SRC2 = 0x54,
/// Interrupt register
WRIST_TILT_IA = 0x55,
// RESERVED = [0x56..0x57],
/// Interrupt registers
TAP_CFG = 0x58,
/// Interrupt registers
TAP_THS_6D = 0x59,
/// Interrupt registers
INT_DUR2 = 0x5A,
/// Interrupt registers
WAKE_UP_THS = 0x5B,
/// Interrupt registers
WAKE_UP_DUR = 0x5C,
/// Interrupt registers
FREE_FALL = 0x5D,
/// Interrupt registers
MD1_CFG = 0x5E,
/// Interrupt registers
MD2_CFG = 0x5F,
/// (no comment)
MASTER_CMD_CODE = 0x60,
/// (no comment)
SENS_SYNC_SPI_ERROR_CODE = 0x61,
// RESERVED = [0x62..0x65],
/// External magnetometer raw data output registers
OUT_MAG_RAW_X_L = 0x66,
/// External magnetometer raw data output registers
OUT_MAG_RAW_X_H = 0x67,
/// External magnetometer raw data output registers
OUT_MAG_RAW_Y_L = 0x68,
/// External magnetometer raw data output registers
OUT_MAG_RAW_Y_H = 0x69,
/// External magnetometer raw data output registers
OUT_MAG_RAW_Z_L = 0x6A,
/// External magnetometer raw data output registers
OUT_MAG_RAW_Z_H = 0x6B,
// RESERVED = [0x6C..0x72],
/// Accelerometer user offset correction
X_OFS_USR = 0x73,
/// Accelerometer user offset correction
Y_OFS_USR = 0x74,
/// Accelerometer user offset correction
Z_OFS_USR = 0x75,
// RESERVED = [0x76..0x7F],
}
impl RegisterAddress {
pub fn address(self) -> u8 {
self as u8
}
}
/// Register address+value container
pub struct RegisterConfig {
pub address: u8,
pub value: u8,
}
/// Simple bit-field structure
#[derive(Default)]
pub struct RegisterBits<const BITS_NUM: u8, const BITS_POS: u8> {
value: u8,
}
impl<const BITS_NUM: u8, const BITS_POS: u8> RegisterBits<BITS_NUM, BITS_POS> {
/// New object with (unshifted) value set
pub fn new(value: u8) -> Self {
Self::from(value)
}
/// New object with value set by extracting (shifting) relevant bits from register value
pub fn from_reg(value: u8) -> Self {
let mut s = Self::default();
s.set_from_reg(value);
s
}
/// Sets value by extracting (shifting) relevant bits from register value
pub fn set_from_reg(&mut self, value: u8) {
self.value = (value >> BITS_POS) & Self::bit_mask();
}
/// Returns unshifted value
pub fn value(&self) -> u8 {
self.value
}
/// Returns unshifted bit mask
pub fn bit_mask() -> u8 {
(1 << BITS_NUM) - 1
}
/// Returns shifted bit mask
pub fn bit_shifted_mask() -> u8 {
Self::bit_mask() << BITS_POS
}
}
pub trait RegisterValue {
fn shifted(&self) -> u8;
}
impl<const BITS_NUM: u8, const BITS_POS: u8> RegisterValue for RegisterBits<BITS_NUM, BITS_POS> {
/// Returns shifted value to be OR-ed into register value
fn shifted(&self) -> u8 {
(self.value & Self::bit_mask()) << BITS_POS
}
}
impl<const BITS_NUM: u8, const BITS_POS: u8> From<u8> for RegisterBits<BITS_NUM, BITS_POS> {
fn from(value: u8) -> Self {
Self {
value: value & Self::bit_mask(),
}
}
}
impl<const BITS_NUM: u8, const BITS_POS: u8> From<bool> for RegisterBits<BITS_NUM, BITS_POS> {
fn from(value: bool) -> Self {
Self::from(value as u8)
}
}
#[cfg(test)]
mod tests {
use super::{RegisterBits, RegisterValue};
#[test]
fn new_1_0() {
const BITS: u8 = 1;
const POS: u8 = 0;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b1);
}
#[test]
fn new_1_1() {
const BITS: u8 = 1;
const POS: u8 = 1;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b1);
}
#[test]
fn new_1_2() {
const BITS: u8 = 1;
const POS: u8 = 2;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b1);
}
#[test]
fn new_2_0() {
const BITS: u8 = 2;
const POS: u8 = 0;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b11);
}
#[test]
fn new_2_1() {
const BITS: u8 = 2;
const POS: u8 = 1;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b11);
}
#[test]
fn new_2_2() {
const BITS: u8 = 2;
const POS: u8 = 2;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b11);
}
#[test]
fn shifted_1_0() {
const BITS: u8 = 1;
const POS: u8 = 0;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b1);
}
#[test]
fn shifted_1_1() {
const BITS: u8 = 1;
const POS: u8 = 1;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b10);
}
#[test]
fn shifted_1_2() {
const BITS: u8 = 1;
const POS: u8 = 2;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b100);
}
#[test]
fn shifted_2_1() {
const BITS: u8 = 2;
const POS: u8 = 1;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b110);
}
#[test]
fn shifted_2_2() {
const BITS: u8 = 2;
const POS: u8 = 2;
let rb = RegisterBits::<BITS, POS>::new(0b11111111);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b1100);
}
#[test]
fn new_from_reg_1_0() {
const BITS: u8 = 1;
const POS: u8 = 0;
let rb = RegisterBits::<BITS, POS>::from_reg(0b11111111);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b1);
}
#[test]
fn new_from_reg_1_1() {
const BITS: u8 = 1;
const POS: u8 = 1;
let rb = RegisterBits::<BITS, POS>::from_reg(0b11111111);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b10);
}
#[test]
fn new_from_reg_2_0() {
const BITS: u8 = 2;
const POS: u8 = 0;
let rb = RegisterBits::<BITS, POS>::from_reg(0b11111111);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b11);
}
#[test]
fn new_from_reg_2_1() {
const BITS: u8 = 2;
const POS: u8 = 1;
let rb = RegisterBits::<BITS, POS>::from_reg(0b11111111);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b110);
}
#[test]
fn new_from_reg_2_2() {
const BITS: u8 = 2;
const POS: u8 = 2;
let rb = RegisterBits::<BITS, POS>::from_reg(0b11111111);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b1100);
}
#[test]
fn from_reg_1_0() {
const BITS: u8 = 1;
const POS: u8 = 0;
let mut rb = RegisterBits::<BITS, POS>::default();
let reg: u8 = 0b11111111;
rb.set_from_reg(reg);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b1);
}
#[test]
fn from_reg_1_1() {
const BITS: u8 = 1;
const POS: u8 = 1;
let mut rb = RegisterBits::<BITS, POS>::default();
let reg: u8 = 0b11111111;
rb.set_from_reg(reg);
assert_eq!(rb.value, 0b1);
assert_eq!(rb.shifted(), 0b10);
}
#[test]
fn from_reg_2_0() {
const BITS: u8 = 2;
const POS: u8 = 0;
let mut rb = RegisterBits::<BITS, POS>::default();
let reg: u8 = 0b11111111;
rb.set_from_reg(reg);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b11);
}
#[test]
fn from_reg_2_1() {
const BITS: u8 = 2;
const POS: u8 = 1;
let mut rb = RegisterBits::<BITS, POS>::default();
let reg: u8 = 0b11111111;
rb.set_from_reg(reg);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b110);
}
#[test]
fn from_reg_2_2() {
const BITS: u8 = 2;
const POS: u8 = 2;
let mut rb = RegisterBits::<BITS, POS>::default();
let reg: u8 = 0b11111111;
rb.set_from_reg(reg);
assert_eq!(rb.value, 0b11);
assert_eq!(rb.shifted(), 0b1100);
}
#[test]
fn bit_mask_1_0() {
const BITS: u8 = 1;
const POS: u8 = 0;
assert_eq!(RegisterBits::<BITS, POS>::bit_mask(), 0b1);
}
#[test]
fn bit_mask_2_0() {
const BITS: u8 = 2;
const POS: u8 = 0;
assert_eq!(RegisterBits::<BITS, POS>::bit_mask(), 0b11);
}
#[test]
fn bit_mask_3_0() {
const BITS: u8 = 3;
const POS: u8 = 0;
assert_eq!(RegisterBits::<BITS, POS>::bit_mask(), 0b111);
}
#[test]
fn bit_shifted_mask_1_0() {
const BITS: u8 = 1;
const POS: u8 = 0;
assert_eq!(RegisterBits::<BITS, POS>::bit_shifted_mask(), 0b1);
}
#[test]
fn bit_shifted_mask_1_1() {
const BITS: u8 = 1;
const POS: u8 = 1;
assert_eq!(RegisterBits::<BITS, POS>::bit_shifted_mask(), 0b10);
}
#[test]
fn bit_shifted_mask_2_0() {
const BITS: u8 = 2;
const POS: u8 = 0;
assert_eq!(RegisterBits::<BITS, POS>::bit_shifted_mask(), 0b11);
}
#[test]
fn bit_shifted_mask_2_1() {
const BITS: u8 = 2;
const POS: u8 = 1;
assert_eq!(RegisterBits::<BITS, POS>::bit_shifted_mask(), 0b110);
}
#[test]
fn bit_shifted_mask_3_0() {
const BITS: u8 = 3;
const POS: u8 = 0;
assert_eq!(RegisterBits::<BITS, POS>::bit_shifted_mask(), 0b111);
}
#[test]
fn bit_shifted_mask_3_1() {
const BITS: u8 = 3;
const POS: u8 = 1;
assert_eq!(RegisterBits::<BITS, POS>::bit_shifted_mask(), 0b1110);
}
}

103
src/registers/ctrl1_xl.rs Normal file
View File

@ -0,0 +1,103 @@
//! Linear acceleration sensor control register 1 (r/w).
#![allow(non_camel_case_types)]
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Linear acceleration sensor control register 1 (r/w).
#[derive(Default)]
pub struct Ctrl1Xl {
/// Output data rate and power mode selection. Default value: 0000 (see Table 52).
pub sample_rate: AccelSampleRate,
/// Accelerometer full-scale selection. Default value: 00.
/// (00: ±2 g; 01: ±16 g; 10: ±4 g; 11: ±8 g)
pub scale: AccelScale,
/// Accelerometer digital LPF (LPF1) bandwidth selection. For bandwidth selection refer to CTRL8_XL (17h).
pub low_pass_filter: RegisterBits<1, 6>, // TODO
/// Accelerometer analog chain bandwidth selection (only for accelerometer ODR ≥ 1.67 kHz).
/// (0: BW @ 1.5 kHz; 1: BW @ 400 Hz)
pub analog_chain_bandwidth: RegisterBits<1, 7>, // TODO
}
impl Ctrl1Xl {
pub fn address(&self) -> u8 {
RegisterAddress::CTRL1_XL.address()
}
pub fn value(&self) -> u8 {
self.sample_rate.shifted()
| self.scale.shifted()
| self.low_pass_filter.shifted()
| self.analog_chain_bandwidth.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}
#[derive(Default, Clone, Copy)]
pub enum AccelScale {
#[default]
_2G = 0b00,
_16G = 0b01,
_4G = 0b10,
_8G = 0b11,
}
impl AccelScale {
pub fn sensitivity(self) -> f32 {
use AccelScale::*;
match self {
_2G => 0.000_061,
_4G => 0.000_122,
_8G => 0.000_244,
_16G => 0.000_488,
}
}
}
impl RegisterValue for AccelScale {
fn shifted(&self) -> u8 {
(*self as u8) << 2
}
}
#[derive(Default, Clone, Copy)]
pub enum AccelSampleRate {
/// Power Down (disabled)
#[default]
PowerDown = 0b0000,
/// 12.5 Hz
_12_5Hz = 0b0001,
/// 26 Hz
_26Hz = 0b0010,
/// 52 Hz
_52Hz = 0b0011,
/// 104 Hz
_104Hz = 0b0100,
/// 208 Hz
_208Hz = 0b0101,
/// 416 Hz
_416Hz = 0b0110,
/// 833 Hz
_833Hz = 0b0111,
/// 1.66 kHz
_1660Hz = 0b1000,
/// 3.33 kHz
_3330Hz = 0b1001,
/// 6.66 kHz
_6660Hz = 0b1010,
/// 1.6 Hz in low power mode; 12.5 Hz in high performance mode
_1_6Hz_LP_or_12_5Hz_HP = 0b1011,
// Not allowed = [0b1100..0b1111]
}
impl RegisterValue for AccelSampleRate {
fn shifted(&self) -> u8 {
(*self as u8) << 4
}
}

98
src/registers/ctrl2_g.rs Normal file
View File

@ -0,0 +1,98 @@
//! Angular rate sensor control register 2 (r/w).
#![allow(non_camel_case_types)]
use crate::registers::RegisterConfig;
use crate::RegisterAddress;
use super::RegisterValue;
#[derive(Default)]
/// Angular rate sensor control register 2 (r/w).
pub struct Ctrl2G {
/// Gyroscope output data rate selection. Default value: 0000 (Refer to Table 55)
pub sample_rate: GyroSampleRate,
/// Gyroscope full-scale selection. Default value: 00 (00: 245 dps; 01: 500 dps; 10: 1000 dps; 11: 2000 dps)
/// Gyroscope full-scale at 125 dps. Default value: 0 (0: disabled; 1: enabled)
pub scale: GyroScale,
}
impl Ctrl2G {
pub fn address(&self) -> u8 {
RegisterAddress::CTRL2_G.address()
}
pub fn value(&self) -> u8 {
self.sample_rate.shifted() | self.scale.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}
#[derive(Default, Debug, Clone, Copy)]
pub enum GyroScale {
_125DPS = 0b001,
#[default]
_250DPS = 0b000,
_500DPS = 0b010,
_1000DPS = 0b100,
_2000DPS = 0b110,
}
impl GyroScale {
pub fn sensitivity(self) -> f32 {
use GyroScale::*;
match self {
_125DPS => 0.004_375,
_250DPS => 0.008_750,
_500DPS => 0.017_500,
_1000DPS => 0.035_000,
_2000DPS => 0.070_000,
}
}
}
impl RegisterValue for GyroScale {
fn shifted(&self) -> u8 {
(*self as u8) << 1
}
}
#[derive(Default, Debug, Clone, Copy)]
pub enum GyroSampleRate {
/// Power Down (disabled)
#[default]
PowerDown = 0b0000,
/// 12.5 Hz
_12_5Hz = 0b0001,
/// 26 Hz
_26Hz = 0b0010,
/// 52 Hz
_52Hz = 0b0011,
/// 104 Hz
_104Hz = 0b0100,
/// 208 Hz
_208Hz = 0b0101,
/// 416 Hz
_416Hz = 0b0110,
/// 833 Hz
_833Hz = 0b0111,
/// 1.66 kHz
_1660Hz = 0b1000,
/// 3.33 kHz
_3330Hz = 0b1001,
/// 6.66 kHz
_6660Hz = 0b1010,
// Not allowed = [0b1011..0b1111]
}
impl RegisterValue for GyroSampleRate {
fn shifted(&self) -> u8 {
(*self as u8) << 4
}
}

73
src/registers/ctrl3_c.rs Normal file
View File

@ -0,0 +1,73 @@
//! Control register 3 (r/w).
#![allow(non_camel_case_types)]
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Control register 3 (r/w).
pub struct Ctrl3C {
/// Reboot memory content. Default value: 0
/// (0: normal mode; 1: reboot memory content)
pub reboot_memory_content: RegisterBits<1, 7>,
/// Block Data Update. Default value: 0
/// (0: continuous update; 1: output registers not updated until MSB and LSB have been read)
pub block_data_update: RegisterBits<1, 6>,
/// Interrupt activation level. Default value: 0
/// (0: interrupt output pads active high; 1: interrupt output pads active low)
pub high_low_active: RegisterBits<1, 5>,
/// Push-pull/open-drain selection on INT1 and INT2 pads. Default value: 0
/// (0: push-pull mode; 1: open-drain mode)
pub push_pull_open_drain: RegisterBits<1, 4>,
/// SPI Serial Interface Mode selection. Default value: 0
/// (0: 4-wire interface; 1: 3-wire interface).
pub spi_interface_mode: RegisterBits<1, 3>,
/// Register address automatically incremented during a multiple byte access with a serial interface (I2C or SPI). Default value: 1
/// (0: disabled; 1: enabled)
pub interface_auto_address_increment: RegisterBits<1, 2>,
/// Big/Little Endian Data selection. Default value 0
/// (0: data LSB @ lower address; 1: data MSB @ lower address)
pub big_little_endian: RegisterBits<1, 1>,
/// Software reset. Default value: 0
/// (0: normal mode; 1: reset device)
/// This bit is automatically cleared.
pub software_reset: RegisterBits<1, 0>,
}
impl Default for Ctrl3C {
fn default() -> Self {
Self {
interface_auto_address_increment: RegisterBits::new(1),
reboot_memory_content: RegisterBits::default(),
block_data_update: RegisterBits::default(),
high_low_active: RegisterBits::default(),
push_pull_open_drain: RegisterBits::default(),
spi_interface_mode: RegisterBits::default(),
big_little_endian: RegisterBits::default(),
software_reset: RegisterBits::default(),
}
}
}
impl Ctrl3C {
pub fn address(&self) -> u8 {
RegisterAddress::CTRL3_C.address()
}
pub fn value(&self) -> u8 {
self.reboot_memory_content.shifted()
| self.block_data_update.shifted()
| self.high_low_active.shifted()
| self.push_pull_open_drain.shifted()
| self.spi_interface_mode.shifted()
| self.interface_auto_address_increment.shifted()
| self.big_little_endian.shifted()
| self.software_reset.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

56
src/registers/ctrl4_c.rs Normal file
View File

@ -0,0 +1,56 @@
//! Control register 4 (r/w).
#![allow(non_camel_case_types)]
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Control register 4 (r/w).
#[derive(Default)]
pub struct Ctrl4C {
/// Extend DEN functionality to accelerometer sensor. Default value: 0
/// (0: disabled; 1: enabled)
pub extend_den: RegisterBits<1, 7>,
/// Gyroscope sleep mode enable. Default value: 0
/// (0: disabled; 1: enabled)
pub gyroscope_sleep: RegisterBits<1, 6>,
/// DEN DRDY signal on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub den_data_ready_int1: RegisterBits<1, 5>,
/// All interrupt signals available on INT1 pad enable. Default value: 0
/// (0: interrupt signals divided between INT1 and INT2 pads;
/// 1: all interrupt signals in logic or on INT1 pad)
pub int2_on_int1: RegisterBits<1, 4>,
/// Configuration 1 data available enable bit. Default value: 0
/// (0: DA timer disabled; 1: DA timer enabled)
pub data_ready_mask: RegisterBits<1, 3>,
/// Disable I2C interface. Default value: 0
/// (0: both I2C and SPI enabled; 1: I2C disabled, SPI only enabled)
pub i2c_disable: RegisterBits<1, 2>,
/// Enable gyroscope digital LPF1. The bandwidth can be selected through
/// FTYPE[1\:0] in FUNC_CFG_ACCESS (01h).
/// (0: disabled; 1: enabled)
pub gyroscope_low_pass_filter_selection: RegisterBits<1, 1>,
}
impl Ctrl4C {
pub fn address(&self) -> u8 {
RegisterAddress::CTRL4_C.address()
}
pub fn value(&self) -> u8 {
self.extend_den.shifted()
| self.gyroscope_sleep.shifted()
| self.den_data_ready_int1.shifted()
| self.int2_on_int1.shifted()
| self.data_ready_mask.shifted()
| self.i2c_disable.shifted()
| self.gyroscope_low_pass_filter_selection.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

View File

@ -0,0 +1,34 @@
//! DataReady configuration register (r/w).
#![allow(non_camel_case_types)]
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// DataReady configuration register (r/w).
#[derive(Default)]
pub struct DrdyPulseCfgG {
/// Enable pulsed DataReady mode. Default value: 0
/// (0: DataReady latched mode. Returns to 0 only after output data have been read;
/// 1: DataReady pulsed mode. The DataReady pulses are 75 μs long.)
pub pulsed_data_ready: RegisterBits<1, 7>,
/// Wrist tilt interrupt on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub int2_wrist_tilt: RegisterBits<1, 0>,
}
impl DrdyPulseCfgG {
pub fn address(&self) -> u8 {
RegisterAddress::DRDY_PULSE_CFG_G.address()
}
pub fn value(&self) -> u8 {
self.pulsed_data_ready.shifted() | self.int2_wrist_tilt.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

View File

@ -0,0 +1,52 @@
//! Free-fall function duration setting register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Free-fall function duration setting register (r/w).
#[derive(Default)]
pub struct FreeFall {
/// Free-fall duration event. Default: 0
/// For the complete configuration of the free fall duration, refer to FF_DUR5 in WAKE_UP_DUR (5Ch) configuration
pub duration_event: RegisterBits<5, 3>,
/// Free fall threshold setting. Default: 000
/// For details refer to Table 196.
pub threshold: FreeFallThreshold,
}
impl FreeFall {
pub fn address(&self) -> u8 {
RegisterAddress::FREE_FALL.address()
}
pub fn value(&self) -> u8 {
self.duration_event.shifted() | self.threshold.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}
#[allow(non_camel_case_types)]
#[repr(u8)]
#[derive(Default, Clone, Copy)]
pub enum FreeFallThreshold {
#[default]
_156_mg = 0b000,
_219_mg = 0b001,
_250_mg = 0b010,
_312_mg = 0b011,
_344_mg = 0b100,
_406_mg = 0b101,
_469_mg = 0b110,
_500_mg = 0b111,
}
impl RegisterValue for FreeFallThreshold {
fn shifted(&self) -> u8 {
*self as u8
}
}

View File

@ -0,0 +1,57 @@
//! INT1 pad control register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// INT1 pad control register (r/w).
/// Each bit in this register enables a signal to be carried through INT1. The pads output will supply the OR combination of the selected signals.
#[derive(Default)]
pub struct Int1Ctrl {
/// Pedometer step recognition interrupt enable on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub pedometer_step_recognition: RegisterBits<1, 7>,
/// Significant motion interrupt enable on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub significant_motion: RegisterBits<1, 6>,
/// FIFO full flag interrupt enable on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub fifo_full: RegisterBits<1, 5>,
/// FIFO overrun interrupt on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub fifo_overrun: RegisterBits<1, 4>,
/// FIFO threshold interrupt on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub fifo_threshold: RegisterBits<1, 3>,
/// Boot status available on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub boot_status_available: RegisterBits<1, 2>,
/// Gyroscope Data Ready on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub gyroscope_data_ready: RegisterBits<1, 1>,
/// Accelerometer Data Ready on INT1 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub accelerometer_data_ready: RegisterBits<1, 0>,
}
impl Int1Ctrl {
pub fn address(&self) -> u8 {
RegisterAddress::INT1_CTRL.address()
}
pub fn value(&self) -> u8 {
self.pedometer_step_recognition.shifted()
| self.significant_motion.shifted()
| self.fifo_full.shifted()
| self.fifo_overrun.shifted()
| self.fifo_threshold.shifted()
| self.boot_status_available.shifted()
| self.gyroscope_data_ready.shifted()
| self.accelerometer_data_ready.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

View File

@ -0,0 +1,57 @@
//! INT2 pad control register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// INT2 pad control register (r/w).
/// Each bit in this register enables a signal to be carried through INT2. The pads output will supply the OR combination of the selected signals.
#[derive(Default)]
pub struct Int2Ctrl {
/// Pedometer step recognition interrupt on delta time(1) enable on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub pedometer_step_recognition_delta_time: RegisterBits<1, 7>,
/// Step counter overflow interrupt enable on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub step_counter_overflow: RegisterBits<1, 6>,
/// FIFO full flag interrupt enable on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub fifo_full: RegisterBits<1, 5>,
/// FIFO overrun interrupt on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub fifo_overrun: RegisterBits<1, 4>,
/// FIFO threshold interrupt on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub fifo_threshold: RegisterBits<1, 3>,
/// Temperature Data Ready on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub temperature_data_ready: RegisterBits<1, 2>,
/// Gyroscope Data Ready on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub gyroscope_data_ready: RegisterBits<1, 1>,
/// Accelerometer Data Ready on INT2 pad. Default value: 0
/// (0: disabled; 1: enabled)
pub accelerometer_data_ready: RegisterBits<1, 0>,
}
impl Int2Ctrl {
pub fn address(&self) -> u8 {
RegisterAddress::INT2_CTRL.address()
}
pub fn value(&self) -> u8 {
self.pedometer_step_recognition_delta_time.shifted()
| self.step_counter_overflow.shifted()
| self.fifo_full.shifted()
| self.fifo_overrun.shifted()
| self.fifo_threshold.shifted()
| self.temperature_data_ready.shifted()
| self.gyroscope_data_ready.shifted()
| self.accelerometer_data_ready.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

34
src/registers/int_dur2.rs Normal file
View File

@ -0,0 +1,34 @@
//! Tap recognition function setting register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Tap recognition function setting register (r/w).
#[derive(Default)]
pub struct IntDur2 {
/// Duration of maximum time gap for double tap recognition. Default: 0000
/// When double tap recognition is enabled, this register expresses the maximum time between two consecutive detected taps to determine a double tap event. The default value of these bits is 0000b which corresponds to 16*ODR_XL time. If the DUR[3\:0] bits are set to a different value, 1LSB corresponds to 32*ODR_XL time.
pub duration: RegisterBits<4, 4>,
/// Expected quiet time after a tap detection. Default value: 00
/// Quiet time is the time after the first detected tap in which there must not be any overthreshold event. The default value of these bits is 00b which corresponds to 2*ODR_XL time. If the QUIET[1\:0] bits are set to a different value, 1LSB corresponds to 4*ODR_XL time.
pub quiet: RegisterBits<2, 2>,
/// Maximum duration of overthreshold event. Default value: 00
/// Maximum duration is the maximum time of an overthreshold signal detection to be recognized as a tap event. The default value of these bits is 00b which corresponds to 4*ODR_XL time. If the SHOCK[1\:0] bits are set to a different value, 1LSB corresponds to 8*ODR_XL time.
pub shock: RegisterBits<2, 0>,
}
impl IntDur2 {
pub fn address(&self) -> u8 {
RegisterAddress::INT_DUR2.address()
}
pub fn value(&self) -> u8 {
self.duration.shifted() | self.quiet.shifted() | self.shock.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

61
src/registers/md1_cfg.rs Normal file
View File

@ -0,0 +1,61 @@
//! Function routing on INT1 register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Function routing on INT1 register (r/w).
#[derive(Default)]
pub struct Md1Cfg {
/// Routing on INT1 of inactivity mode. Default: 0
/// (0: routing on INT1 of inactivity disabled; 1: routing on INT1 of inactivity enabled)
pub inactivity_event: RegisterBits<1, 7>,
/// Single-tap recognition routing on INT1. Default: 0
/// (0: routing of single-tap event on INT1 disabled;
/// 1: routing of single-tap event on INT1 enabled)
pub single_tap_event: RegisterBits<1, 6>,
/// Routing of wakeup event on INT1. Default value: 0
/// (0: routing of wakeup event on INT1 disabled;
/// 1: routing of wakeup event on INT1 enabled)
pub wake_up_event: RegisterBits<1, 5>,
/// Routing of free-fall event on INT1. Default value: 0
/// (0: routing of free-fall event on INT1 disabled;
/// 1: routing of free-fall event on INT1 enabled)
pub free_fall_event: RegisterBits<1, 4>,
/// Routing of tap event on INT1. Default value: 0
/// (0: routing of double-tap event on INT1 disabled;
/// 1: routing of double-tap event on INT1 enabled)
pub double_tap_event: RegisterBits<1, 3>,
/// Routing of 6D event on INT1. Default value: 0
/// (0: routing of 6D event on INT1 disabled; 1: routing of 6D event on INT1 enabled)
pub six_degrees_event: RegisterBits<1, 2>,
/// Routing of tilt event on INT1. Default value: 0
/// (0: routing of tilt event on INT1 disabled; 1: routing of tilt event on INT1 enabled)
pub tilt_event: RegisterBits<1, 1>,
/// Routing of end counter event of timer on INT1. Default value: 0
/// (0: routing of end counter event of timer on INT1 disabled;
/// 1: routing of end counter event of timer event on INT1 enabled)
pub timer_end_counter_event: RegisterBits<1, 0>,
}
impl Md1Cfg {
pub fn address(&self) -> u8 {
RegisterAddress::MD1_CFG.address()
}
pub fn value(&self) -> u8 {
self.inactivity_event.shifted()
| self.single_tap_event.shifted()
| self.wake_up_event.shifted()
| self.free_fall_event.shifted()
| self.double_tap_event.shifted()
| self.six_degrees_event.shifted()
| self.tilt_event.shifted()
| self.timer_end_counter_event.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

61
src/registers/md2_cfg.rs Normal file
View File

@ -0,0 +1,61 @@
//! Function routing on INT2 register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Function routing on INT2 register (r/w).
#[derive(Default)]
pub struct Md2Cfg {
/// Routing on INT2 of inactivity mode. Default: 0
/// (0: routing on INT2 of inactivity disabled; 1: routing on INT2 of inactivity enabled)
pub inactivity_event: RegisterBits<1, 7>,
/// Single-tap recognition routing on INT2. Default: 0
/// (0: routing of single-tap event on INT2 disabled;
/// 1: routing of single-tap event on INT2 enabled)
pub single_tap_event: RegisterBits<1, 6>,
/// Routing of wakeup event on INT2. Default value: 0
/// (0: routing of wakeup event on INT2 disabled;
/// 1: routing of wake-up event on INT2 enabled)
pub wake_up_event: RegisterBits<1, 5>,
/// Routing of free-fall event on INT2. Default value: 0
/// (0: routing of free-fall event on INT2 disabled;
/// 1: routing of free-fall event on INT2 enabled)
pub free_fall_event: RegisterBits<1, 4>,
/// Routing of tap event on INT2. Default value: 0
/// (0: routing of double-tap event on INT2 disabled;
/// 1: routing of double-tap event on INT2 enabled)
pub double_tap_event: RegisterBits<1, 3>,
/// Routing of 6D event on INT2. Default value: 0
/// (0: routing of 6D event on INT2 disabled; 1: routing of 6D event on INT2 enabled)
pub six_degrees_event: RegisterBits<1, 2>,
/// Routing of tilt event on INT2. Default value: 0
/// (0: routing of tilt event on INT2 disabled; 1: routing of tilt event on INT2 enabled)
pub tilt_event: RegisterBits<1, 1>,
/// Routing of soft-iron/hard-iron algorithm end event on INT2. Default value: 0
/// (0: routing of soft-iron/hard-iron algorithm end event on INT2 disabled;
/// 1: routing of soft-iron/hard-iron algorithm end event on INT2 enabled)
pub soft_hard_iron_algorithm_end_event: RegisterBits<1, 0>,
}
impl Md2Cfg {
pub fn address(&self) -> u8 {
RegisterAddress::MD2_CFG.address()
}
pub fn value(&self) -> u8 {
self.inactivity_event.shifted()
| self.single_tap_event.shifted()
| self.wake_up_event.shifted()
| self.free_fall_event.shifted()
| self.double_tap_event.shifted()
| self.six_degrees_event.shifted()
| self.tilt_event.shifted()
| self.soft_hard_iron_algorithm_end_event.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

39
src/registers/mod.rs Normal file
View File

@ -0,0 +1,39 @@
#![allow(unused_imports)]
pub mod addresses;
pub mod ctrl1_xl;
pub mod ctrl2_g;
pub mod ctrl3_c;
pub mod ctrl4_c;
pub mod drdy_pulse_cfg_g;
pub mod free_fall;
pub mod int1_ctrl;
pub mod int2_ctrl;
pub mod int_dur2;
pub mod md1_cfg;
pub mod md2_cfg;
pub mod tap_cfg;
pub mod tap_src;
pub mod tap_ths_6d;
pub mod wake_up_dur;
pub mod wake_up_src;
pub mod wake_up_ths;
pub use addresses::*;
pub use ctrl1_xl::*;
pub use ctrl2_g::*;
pub use ctrl3_c::*;
pub use ctrl4_c::*;
pub use drdy_pulse_cfg_g::*;
pub use free_fall::*;
pub use int1_ctrl::*;
pub use int2_ctrl::*;
pub use int_dur2::*;
pub use md1_cfg::*;
pub use md2_cfg::*;
pub use tap_cfg::*;
pub use tap_src::*;
pub use tap_ths_6d::*;
pub use wake_up_dur::*;
pub use wake_up_src::*;
pub use wake_up_ths::*;

85
src/registers/tap_cfg.rs Normal file
View File

@ -0,0 +1,85 @@
//! Enables interrupt and inactivity functions, configuration of filtering and tap recognition functions (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Enables interrupt and inactivity functions, configuration of filtering and tap recognition functions (r/w).
#[derive(Default)]
pub struct TapCfg {
/// Enable basic interrupts (6D/4D, free-fall, wake-up, tap, inactivity). Default 0.
/// (0: interrupt disabled; 1: interrupt enabled)
pub enable_basic_interrupts: RegisterBits<1, 7>,
/// Enable inactivity function. Default value: 00
/// (00: disabled
/// 01: sets accelerometer ODR to 12.5 Hz (low-power mode), gyro does not change;
/// 10: sets accelerometer ODR to 12.5 Hz (low-power mode), gyro to sleep mode;
/// 11: sets accelerometer ODR to 12.5 Hz (low-power mode), gyro to power-down mode)
pub enable_inactivity_function: InactivityGyroMode,
/// HPF or SLOPE filter selection on wake-up and Activity/Inactivity functions. Refer to Figure 8. Default value: 0
/// (0: SLOPE filter applied; 1: HPF applied)
pub slope_fds: FilterSelected,
/// Enable X direction in tap recognition. Default value: 0
/// (0: X direction disabled; 1: X direction enabled)
pub enable_x_direction_tap_recognition: RegisterBits<1, 3>,
/// Enable Y direction in tap recognition. Default value: 0
/// (0: Y direction disabled; 1: Y direction enabled)
pub enable_y_direction_tap_recognition: RegisterBits<1, 2>,
/// Enable Z direction in tap recognition. Default value: 0
/// (0: Z direction disabled; 1: Z direction enabled)
pub enable_z_direction_tap_recognition: RegisterBits<1, 1>,
/// Latched Interrupt. Default value: 0
/// (0: interrupt request not latched; 1: interrupt request latched)
pub latched_interrupt: RegisterBits<1, 0>,
}
impl TapCfg {
pub fn address(&self) -> u8 {
RegisterAddress::TAP_CFG.address()
}
pub fn value(&self) -> u8 {
self.enable_basic_interrupts.shifted()
| self.enable_inactivity_function.shifted()
| self.slope_fds.shifted()
| self.enable_x_direction_tap_recognition.shifted()
| self.enable_y_direction_tap_recognition.shifted()
| self.enable_z_direction_tap_recognition.shifted()
| self.latched_interrupt.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}
#[repr(u8)]
#[derive(Default, Clone, Copy)]
pub enum InactivityGyroMode {
#[default]
Disabled = 0b00,
AccelLowPowerGyroUnchanged = 0b01,
AccelLowPowerGyroSleepMode = 0b10,
AccelLowPowerGyroPowerDown = 0b11,
}
impl RegisterValue for InactivityGyroMode {
fn shifted(&self) -> u8 {
(*self as u8) << 5
}
}
#[repr(u8)]
#[derive(Default, Clone, Copy)]
pub enum FilterSelected {
#[default]
Slope = 0b0,
HighPassFilter = 0b1,
}
impl RegisterValue for FilterSelected {
fn shifted(&self) -> u8 {
(*self as u8) << 4
}
}

75
src/registers/tap_src.rs Normal file
View File

@ -0,0 +1,75 @@
//! Tap source register (r).
use heapless::Vec;
use crate::{IrqSource, RegisterAddress, RegisterBits};
/// Tap source register (r).
#[derive(Default)]
pub struct TapSrc {
/// Tap event detection status. Default: 0
/// (0: tap event not detected; 1: tap event detected)
pub tap_event: RegisterBits<1, 6>,
/// Single-tap event status. Default value: 0
/// (0: single tap event not detected; 1: single tap event detected)
pub single_tap_event: RegisterBits<1, 5>,
/// Double-tap event detection status. Default value: 0
/// (0: double-tap event not detected; 1: double-tap event detected.)
pub double_tap_event: RegisterBits<1, 4>,
/// Sign of acceleration detected by tap event. Default: 0
/// (0: positive sign of acceleration detected by tap event;
/// 1: negative sign of acceleration detected by tap event)
pub tap_sign_acceleration: RegisterBits<1, 3>,
/// Tap event detection status on X-axis. Default value: 0
/// (0: tap event on X-axis not detected; 1: tap event on X-axis detected)
pub tap_x_axis: RegisterBits<1, 2>,
/// Tap event detection status on Y-axis. Default value: 0
/// (0: tap event on Y-axis not detected; 1: tap event on Y-axis detected)
pub tap_y_axis: RegisterBits<1, 1>,
/// Tap event detection status on Z-axis. Default value: 0
/// (0: tap event on Z-axis not detected; 1: tap event on Z-axis detected)
pub tap_z_axis: RegisterBits<1, 0>,
}
impl TapSrc {
pub fn address(&self) -> u8 {
RegisterAddress::TAP_SRC.address()
}
pub fn get_irq_sources(&self) -> Vec<IrqSource, 6> {
let mut v: Vec<IrqSource, 6> = Default::default();
if self.tap_event.value() != 0 {
v.push(IrqSource::Tap).unwrap();
}
if self.single_tap_event.value() != 0 {
v.push(IrqSource::SingleTap).unwrap();
}
if self.double_tap_event.value() != 0 {
v.push(IrqSource::DoubleTap).unwrap();
}
if self.tap_x_axis.value() != 0 {
v.push(IrqSource::TapOnX).unwrap();
}
if self.tap_y_axis.value() != 0 {
v.push(IrqSource::TapOnY).unwrap();
}
if self.tap_z_axis.value() != 0 {
v.push(IrqSource::TapOnZ).unwrap();
}
v
}
}
impl From<u8> for TapSrc {
fn from(value: u8) -> Self {
let mut s = Self::default();
s.tap_event.set_from_reg(value);
s.single_tap_event.set_from_reg(value);
s.double_tap_event.set_from_reg(value);
s.tap_sign_acceleration.set_from_reg(value);
s.tap_x_axis.set_from_reg(value);
s.tap_y_axis.set_from_reg(value);
s.tap_z_axis.set_from_reg(value);
s
}
}

View File

@ -0,0 +1,36 @@
//! Portrait/landscape position and tap function threshold register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Portrait/landscape position and tap function threshold register (r/w).
#[derive(Default)]
pub struct TapThs6d {
/// 4D orientation detection enable. Z-axis position detection is disabled. Default value: 0
/// (0: enabled; 1: disabled)
pub four_degrees_detection_enable: RegisterBits<1, 7>,
/// Threshold for 4D/6D function. Default value: 00
/// For details, refer to Table 187.
pub six_degrees_threshold: RegisterBits<2, 5>,
/// Threshold for tap recognition. Default value: 00000
/// 1 LSb corresponds to FS_XL/2^5
pub tap_threshold: RegisterBits<5, 0>,
}
impl TapThs6d {
pub fn address(&self) -> u8 {
RegisterAddress::TAP_THS_6D.address()
}
pub fn value(&self) -> u8 {
self.four_degrees_detection_enable.shifted()
| self.six_degrees_threshold.shifted()
| self.tap_threshold.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

View File

@ -0,0 +1,41 @@
//! Free-fall, wakeup, timestamp and sleep mode functions duration setting register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Free-fall, wakeup, timestamp and sleep mode functions duration setting register (r/w).
#[derive(Default)]
pub struct WakeUpDur {
/// Free fall duration event. Default: 0
/// For the complete configuration of the free-fall duration, refer to FF_DUR[4\:0] in FREE_FALL (5Dh) configuration.
/// 1 LSB = 1 ODR_time
pub free_fall_duration_event: RegisterBits<1, 7>,
/// Wake up duration event. Default: 00
/// 1LSB = 1 ODR_time
pub wake_up_duration_event: RegisterBits<2, 5>,
/// Timestamp register resolution setting. Default value: 0
/// (0: 1LSB = 6.4 ms; 1: 1LSB = 25 μs)
pub timestamp_resolution: RegisterBits<1, 4>,
/// Duration to go in sleep mode. Default value: 0000 (this corresponds to 16 ODR)
/// 1 LSB = 512 ODR
pub sleep_duration_event: RegisterBits<4, 0>,
}
impl WakeUpDur {
pub fn address(&self) -> u8 {
RegisterAddress::WAKE_UP_DUR.address()
}
pub fn value(&self) -> u8 {
self.free_fall_duration_event.shifted()
| self.wake_up_duration_event.shifted()
| self.timestamp_resolution.shifted()
| self.sleep_duration_event.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

View File

@ -0,0 +1,70 @@
//! Wake up interrupt source register (r).
use heapless::Vec;
use crate::{IrqSource, RegisterAddress, RegisterBits};
/// Wake up interrupt source register (r).
#[derive(Default)]
pub struct WakeUpSrc {
/// Free-fall event detection status. Default: 0
/// (0: free-fall event not detected; 1: free-fall event detected)
pub free_fall_event: RegisterBits<1, 5>,
/// Sleep event status. Default value: 0
/// (0: sleep event not detected; 1: sleep event detected)
pub sleep_event: RegisterBits<1, 4>,
/// Wakeup event detection status. Default value: 0
/// (0: wakeup event not detected; 1: wakeup event detected.)
pub wake_up_event: RegisterBits<1, 3>,
/// Wakeup event detection status on X-axis. Default value: 0
/// (0: wakeup event on X-axis not detected; 1: wakeup event on X-axis detected)
pub wake_up_event_x: RegisterBits<1, 2>,
/// Wakeup event detection status on Y-axis. Default value: 0
/// (0: wakeup event on Y-axis not detected; 1: wakeup event on Y-axis detected)
pub wake_up_event_y: RegisterBits<1, 1>,
/// Wakeup event detection status on Z-axis. Default value: 0
/// (0: wakeup event on Z-axis not detected; 1: wakeup event on Z-axis detected)
pub wake_up_event_z: RegisterBits<1, 0>,
}
impl WakeUpSrc {
pub fn address(&self) -> u8 {
RegisterAddress::WAKE_UP_SRC.address()
}
pub fn get_irq_sources(&self) -> Vec<IrqSource, 6> {
let mut v = Vec::new();
if self.free_fall_event.value() != 0 {
v.push(IrqSource::FreeFall).unwrap();
}
if self.sleep_event.value() != 0 {
v.push(IrqSource::Sleep).unwrap();
}
if self.wake_up_event.value() != 0 {
v.push(IrqSource::WakeUp).unwrap();
}
if self.wake_up_event_x.value() != 0 {
v.push(IrqSource::WakeUpOnX).unwrap();
}
if self.wake_up_event_y.value() != 0 {
v.push(IrqSource::WakeUpOnY).unwrap();
}
if self.wake_up_event_z.value() != 0 {
v.push(IrqSource::WakeUpOnZ).unwrap();
}
v
}
}
impl From<u8> for WakeUpSrc {
fn from(value: u8) -> Self {
let mut s = Self::default();
s.free_fall_event.set_from_reg(value);
s.sleep_event.set_from_reg(value);
s.wake_up_event.set_from_reg(value);
s.wake_up_event_x.set_from_reg(value);
s.wake_up_event_y.set_from_reg(value);
s.wake_up_event_z.set_from_reg(value);
s
}
}

View File

@ -0,0 +1,32 @@
//! Single and double-tap function threshold register (r/w).
use crate::{RegisterAddress, RegisterBits, RegisterConfig, RegisterValue};
/// Single and double-tap function threshold register (r/w).
#[derive(Default)]
pub struct WakeUpThs {
/// Single/double-tap event enable. Default: 0
/// (0: only single-tap event enabled;
/// 1: both single and double-tap events enabled)
pub single_double_tap_enabled: RegisterBits<1, 7>,
/// Threshold for wakeup. Default value: 000000
/// 1 LSb corresponds to FS_XL/2^6
pub wake_up_threshold: RegisterBits<6, 0>,
}
impl WakeUpThs {
pub fn address(&self) -> u8 {
RegisterAddress::WAKE_UP_THS.address()
}
pub fn value(&self) -> u8 {
self.single_double_tap_enabled.shifted() | self.wake_up_threshold.shifted()
}
pub fn config(&self) -> RegisterConfig {
RegisterConfig {
address: self.address(),
value: self.value(),
}
}
}

37
src/settings/accel.rs Normal file
View File

@ -0,0 +1,37 @@
use crate::registers::Ctrl1Xl;
use crate::{AccelSampleRate, AccelScale, RegisterConfig};
/// Accelerometer settings
#[derive(Default)]
pub struct AccelSettings {
pub sample_rate: AccelSampleRate,
pub scale: AccelScale,
}
impl AccelSettings {
pub fn new() -> Self {
Self::default()
.with_sample_rate(AccelSampleRate::_416Hz)
.with_scale(AccelScale::_2G)
}
pub fn with_sample_rate(mut self, sample_rate: AccelSampleRate) -> Self {
self.sample_rate = sample_rate;
self
}
pub fn with_scale(mut self, scale: AccelScale) -> Self {
self.scale = scale;
self
}
/// Returns accelerometer-related register config to be written
pub fn config(&self) -> RegisterConfig {
Ctrl1Xl {
sample_rate: self.sample_rate,
scale: self.scale,
..Default::default()
}
.config()
}
}

36
src/settings/gyro.rs Normal file
View File

@ -0,0 +1,36 @@
use crate::registers::Ctrl2G;
use crate::{GyroSampleRate, GyroScale, RegisterConfig};
/// Gyroscope settings
#[derive(Default)]
pub struct GyroSettings {
pub scale: GyroScale,
pub sample_rate: GyroSampleRate,
}
impl GyroSettings {
pub fn new() -> Self {
Self::default()
.with_sample_rate(GyroSampleRate::_416Hz)
.with_scale(GyroScale::_250DPS)
}
pub fn with_sample_rate(mut self, sample_rate: GyroSampleRate) -> Self {
self.sample_rate = sample_rate;
self
}
pub fn with_scale(mut self, scale: GyroScale) -> Self {
self.scale = scale;
self
}
/// Returns gyroscope-related register config to be written
pub fn config(&self) -> RegisterConfig {
Ctrl2G {
sample_rate: self.sample_rate,
scale: self.scale,
}
.config()
}
}

314
src/settings/irq.rs Normal file
View File

@ -0,0 +1,314 @@
use crate::{
data::XYZ,
registers::{
FreeFall, FreeFallThreshold, InactivityGyroMode, Int1Ctrl, Int2Ctrl, IntDur2, Md1Cfg,
Md2Cfg, RegisterConfig, TapCfg, TapThs6d, WakeUpDur, WakeUpThs,
},
};
/// Interrupt pin/pad routing selection
#[derive(Default, Clone, Copy)]
pub enum InterruptRoute {
#[default]
None,
Int1,
Int2,
Both,
}
#[derive(Default, Clone, Copy)]
pub enum TapRecognitionMode {
#[default]
None,
Single,
Double,
Both,
}
#[derive(Default, Clone, Copy)]
pub struct FreeFallIrqSettings {
pub interrupt_route: InterruptRoute,
pub threshold: FreeFallThreshold,
pub duration_samples: u8,
}
#[derive(Default)]
pub struct WakeUpIrqSettings {
pub interrupt_route: InterruptRoute,
pub threshold: u8,
}
#[derive(Default)]
pub struct OrientationDetectionIrqSettings {
pub interrupt_route: InterruptRoute,
// TODO
}
#[derive(Default)]
pub struct TapIrqSettings {
pub interrupt_route: InterruptRoute,
pub recognition_mode: TapRecognitionMode,
pub direction_enable: XYZ<bool>,
pub threshold: u8,
pub shock_samples: u8,
pub quiet_samples: u8,
pub duration_samples: u8,
}
#[derive(Default)]
pub struct InactivityIrqSettings {
pub interrupt_route: InterruptRoute,
pub inactivity_gyro_mode: InactivityGyroMode,
pub threshold: u8,
pub sleep_duration: u8,
}
/// Interrupt settings
#[derive(Default)]
pub struct IrqSettings {
pub free_fall: FreeFallIrqSettings,
pub wake_up: WakeUpIrqSettings,
pub orientation_detection: OrientationDetectionIrqSettings,
pub tap: TapIrqSettings,
pub inactivity: InactivityIrqSettings,
registers: IrqRegisters,
}
#[derive(Default)]
struct IrqRegisters {
int1_ctrl: Int1Ctrl,
int2_ctrl: Int2Ctrl,
md1_cfg: Md1Cfg,
md2_cfg: Md2Cfg,
tap_cfg: TapCfg,
tap_ths_6d: TapThs6d,
free_fall: FreeFall,
wake_up_dur: WakeUpDur,
wake_up_ths: WakeUpThs,
int_dur2: IntDur2,
}
impl IrqSettings {
/// Enables Free Fall interrupt
pub fn enable_free_fall_irq(
&mut self,
threshold: FreeFallThreshold,
duration_samples: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.free_fall.threshold = threshold;
self.free_fall.duration_samples = duration_samples;
self.free_fall.interrupt_route = interrupt_route;
self.update_registers();
}
/// Enables Wake Up interrupt
pub fn enable_wake_up_irq(
&mut self,
threshold: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.wake_up.threshold = threshold;
self.wake_up.interrupt_route = interrupt_route;
self.update_registers();
}
// TODO provide helper function calculating desired tap time to register values
/// Enables Single/Double Tap interrupt
pub fn enable_tap_irq(
&mut self,
recognition_mode: TapRecognitionMode,
direction_enable: XYZ<bool>,
// threshold: u8,
// shock_samples: u8,
// quiet_samples: u8,
// duration_samples: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.tap.recognition_mode = recognition_mode;
self.tap.direction_enable = direction_enable;
// self.tap.threshold = threshold;
// self.tap.shock_samples = shock_samples;
// self.tap.quiet_samples = quiet_samples;
// self.tap.duration_samples = duration_samples;
self.tap.interrupt_route = interrupt_route;
self.update_registers();
}
/// Enables Activity/Inactivity interrupt
pub fn enable_inactivity_irq(
&mut self,
inactivity_gyro_mode: InactivityGyroMode,
threshold: u8,
duration_samples: u8,
interrupt_route: InterruptRoute,
latched_irq: bool,
) {
self.enable_irqs(latched_irq);
self.inactivity.inactivity_gyro_mode = inactivity_gyro_mode;
self.inactivity.threshold = threshold;
self.inactivity.sleep_duration = duration_samples;
self.inactivity.interrupt_route = interrupt_route;
self.update_registers();
}
/// Enables basic interrupts
pub fn enable_irqs(&mut self, latched_irq: bool) {
self.registers.tap_cfg.enable_basic_interrupts = 1.into();
self.registers.tap_cfg.latched_interrupt = latched_irq.into();
self.update_registers();
}
/// Disables basic interrupts
pub fn disable_irqs(&mut self) {
self.registers.tap_cfg.enable_basic_interrupts = 0.into();
self.update_registers();
}
/// Returns interrupt-related registers configs to be written
pub fn configs(&self) -> [RegisterConfig; 10] {
[
self.registers.int1_ctrl.config(),
self.registers.int2_ctrl.config(),
self.registers.int_dur2.config(),
self.registers.md1_cfg.config(),
self.registers.md2_cfg.config(),
self.registers.tap_cfg.config(),
self.registers.tap_ths_6d.config(),
self.registers.free_fall.config(),
self.registers.wake_up_dur.config(),
self.registers.wake_up_ths.config(),
]
}
fn update_registers(&mut self) {
self.update_free_fall_registers();
self.update_wake_up_registers();
self.update_tap_registers();
self.update_inactivity_registers();
}
fn update_free_fall_registers(&mut self) {
(
self.registers.md1_cfg.free_fall_event,
self.registers.md2_cfg.free_fall_event,
) = match self.free_fall.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
self.registers.free_fall.threshold = self.free_fall.threshold;
self.registers.wake_up_dur.free_fall_duration_event =
(((self.free_fall.threshold as u8) >> 5) & 0b1).into();
self.registers.free_fall.duration_event = self.free_fall.duration_samples.into();
}
fn update_wake_up_registers(&mut self) {
(
self.registers.md1_cfg.wake_up_event,
self.registers.md2_cfg.wake_up_event,
) = match self.wake_up.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
self.registers.wake_up_ths.wake_up_threshold = self.wake_up.threshold.into();
}
fn update_tap_registers(&mut self) {
match self.tap.recognition_mode {
TapRecognitionMode::None | TapRecognitionMode::Single => {
self.registers.wake_up_ths.single_double_tap_enabled = 0.into()
}
TapRecognitionMode::Double | TapRecognitionMode::Both => {
self.registers.wake_up_ths.single_double_tap_enabled = 1.into()
}
}
match self.tap.recognition_mode {
TapRecognitionMode::None => {
self.registers.tap_cfg.enable_basic_interrupts = false.into()
}
TapRecognitionMode::Single => {
self.registers.tap_cfg.enable_basic_interrupts = true.into();
self.update_single_tap_registers()
}
TapRecognitionMode::Double => {
self.registers.tap_cfg.enable_basic_interrupts = true.into();
self.update_double_tap_registers()
}
TapRecognitionMode::Both => {
self.registers.tap_cfg.enable_basic_interrupts = true.into();
self.update_single_tap_registers();
self.update_double_tap_registers();
}
};
self.registers.tap_cfg.enable_basic_interrupts = 1.into();
self.registers.tap_cfg.enable_x_direction_tap_recognition =
self.tap.direction_enable.x.into();
self.registers.tap_cfg.enable_y_direction_tap_recognition =
self.tap.direction_enable.y.into();
self.registers.tap_cfg.enable_z_direction_tap_recognition =
self.tap.direction_enable.z.into();
self.registers.tap_ths_6d.tap_threshold = self.tap.threshold.into();
self.registers.int_dur2.duration = self.tap.duration_samples.into();
self.registers.int_dur2.quiet = self.tap.quiet_samples.into();
self.registers.int_dur2.shock = self.tap.shock_samples.into();
}
fn update_single_tap_registers(&mut self) {
(
self.registers.md1_cfg.single_tap_event,
self.registers.md2_cfg.single_tap_event,
) = match self.tap.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
}
fn update_double_tap_registers(&mut self) {
(
self.registers.md1_cfg.double_tap_event,
self.registers.md2_cfg.double_tap_event,
) = match self.tap.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
}
fn update_inactivity_registers(&mut self) {
(
self.registers.md1_cfg.inactivity_event,
self.registers.md2_cfg.inactivity_event,
) = match self.inactivity.interrupt_route {
InterruptRoute::None => (0.into(), 0.into()),
InterruptRoute::Int1 => (1.into(), 0.into()),
InterruptRoute::Int2 => (0.into(), 1.into()),
InterruptRoute::Both => (1.into(), 1.into()),
};
self.registers.wake_up_ths.wake_up_threshold = self.inactivity.threshold.into();
self.registers.wake_up_dur.sleep_duration_event = self.inactivity.sleep_duration.into();
self.registers.tap_cfg.enable_inactivity_function = self.inactivity.inactivity_gyro_mode;
}
}

44
src/settings/mod.rs Normal file
View File

@ -0,0 +1,44 @@
pub mod accel;
pub mod gyro;
pub mod irq;
pub use accel::*;
pub use gyro::*;
pub use irq::*;
/// Device settings
#[derive(Default)]
pub struct LsmSettings {
pub accel: AccelSettings,
pub gyro: GyroSettings,
pub irq: IrqSettings,
pub low_performance_mode: bool,
}
impl LsmSettings {
pub fn basic() -> Self {
Self::default()
.with_accel(AccelSettings::new())
.with_gyro(GyroSettings::new())
}
pub fn with_accel(mut self, accel_settings: AccelSettings) -> Self {
self.accel = accel_settings;
self
}
pub fn with_gyro(mut self, gyro_settings: GyroSettings) -> Self {
self.gyro = gyro_settings;
self
}
pub fn with_irq(mut self, irq_settings: IrqSettings) -> Self {
self.irq = irq_settings;
self
}
pub fn with_low_performance_mode(mut self) -> Self {
self.low_performance_mode = true;
self
}
}