initial commit
This commit is contained in:
commit
b368f6200c
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[registries.crates-io]
|
||||||
|
protocol = "sparse"
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.pdf filter=lfs diff=lfs merge=lfs -text
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/target
|
||||||
|
/Cargo.lock
|
||||||
|
.vscode/
|
34
.gitlab-ci.yml
Normal file
34
.gitlab-ci.yml
Normal 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
19
Cargo.toml
Normal 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
6
ci/build
Executable 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
6
ci/cargo-sort
Executable 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
6
ci/check
Executable 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
6
ci/clippy
Executable 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
6
ci/doc
Executable 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
6
ci/format
Executable 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
9
ci/jobs/build
Executable 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
15
ci/jobs/check
Executable 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
7
ci/jobs/doc
Executable 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
7
ci/jobs/test
Executable 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
9
ci/pipeline
Executable 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
6
ci/test
Executable 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
6
ci/udeps
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -xEeuo pipefail
|
||||||
|
|
||||||
|
cd "$(git rev-parse --show-toplevel)"
|
||||||
|
|
||||||
|
cargo +nightly udeps "$@"
|
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:0e2089de13ab537736e174c76eaee17fc6ac164c69324862716859688db9e963
|
||||||
|
size 135994
|
3
docs/LSM6DS3TR-C-application-note-AN5130.pdf
Normal file
3
docs/LSM6DS3TR-C-application-note-AN5130.pdf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:15b90b0ccca09f1cd6f561ecc67c7620714f452ad3f2c07e0f1cbce7e1ebb1c6
|
||||||
|
size 1577264
|
3
docs/LSM6DS3TR-C-datasheet-DS11937.pdf
Normal file
3
docs/LSM6DS3TR-C-datasheet-DS11937.pdf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:251737db70e3b6cdc217a5681dd4634a05faffd5288aff6a576078a6464a1b2b
|
||||||
|
size 1839683
|
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:541e1501d15cc3a1be1e45f4e98a91d4005c9e94b471407ed3b9775fe4023c5d
|
||||||
|
size 220256
|
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:0837f80f41f215a1ee9556bdb0c3637f0c36e23e422320832dfa223b3bd87ea0
|
||||||
|
size 202544
|
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:21ad5fa9ea2ae4076585c569bd8ffc502221fe9b700b2a7a04767b412535ff48
|
||||||
|
size 631742
|
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f6eb4483119f6fadc3088f7318078743a58c6bca5738383ea98f37c3d0066e19
|
||||||
|
size 197066
|
21
license
Normal file
21
license
Normal 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
5
readme.md
Normal 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
8
src/consts.rs
Normal 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
28
src/data.rs
Normal 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
34
src/interface/i2c.rs
Normal 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
13
src/interface/mod.rs
Normal 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
34
src/interface/spi.rs
Normal 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
220
src/lib.rs
Normal 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
540
src/registers/addresses.rs
Normal 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
103
src/registers/ctrl1_xl.rs
Normal 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
98
src/registers/ctrl2_g.rs
Normal 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
73
src/registers/ctrl3_c.rs
Normal 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
56
src/registers/ctrl4_c.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
src/registers/drdy_pulse_cfg_g.rs
Normal file
34
src/registers/drdy_pulse_cfg_g.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/registers/free_fall.rs
Normal file
52
src/registers/free_fall.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
57
src/registers/int1_ctrl.rs
Normal file
57
src/registers/int1_ctrl.rs
Normal 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 pad’s 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
src/registers/int2_ctrl.rs
Normal file
57
src/registers/int2_ctrl.rs
Normal 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 pad’s 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
34
src/registers/int_dur2.rs
Normal 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
61
src/registers/md1_cfg.rs
Normal 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
61
src/registers/md2_cfg.rs
Normal 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
39
src/registers/mod.rs
Normal 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
85
src/registers/tap_cfg.rs
Normal 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
75
src/registers/tap_src.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
36
src/registers/tap_ths_6d.rs
Normal file
36
src/registers/tap_ths_6d.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
src/registers/wake_up_dur.rs
Normal file
41
src/registers/wake_up_dur.rs
Normal 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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
src/registers/wake_up_src.rs
Normal file
70
src/registers/wake_up_src.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
32
src/registers/wake_up_ths.rs
Normal file
32
src/registers/wake_up_ths.rs
Normal 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
37
src/settings/accel.rs
Normal 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
36
src/settings/gyro.rs
Normal 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
314
src/settings/irq.rs
Normal 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
44
src/settings/mod.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user