Skip to content

Commit

Permalink
Adds configuration for motion and tap detection features, and some re…
Browse files Browse the repository at this point in the history
…factoring (#5)

* Just backing up some work.
Added a soft reset in the init method so the chip returns to a known state and the config file can be loaded again for sure.
Waits for the internal status to be ok after completing loading the config file to ensure that it was successful, with a timeout.
Sets up the accelerometer into a known configuration at the end of init so it is usable right away, considering adding some type states instead.
Currently full of some test methods written to get the any motion and tap detection features working.

* Updates the `embedded-hal` dependency from ^0.2 to 1.0.0-alpha.10.

* Adds the public `features` module and `EditFeatures` struct for efficient editing of feature configurations instead of reading and writing the entire register contents from the chip every time.
Implements setting the feature configurations for the motion and tap detection features, other features are still pending.
Adds additional methods to the driver for configuring the interrupt lines, and tweaks the methods for mapping them to features.

* Refactors the driver to add type states to ensure that bad things aren't done such as:
* Doing things before initializing
* Editing features when in a low power mode, as this requires long delays between burst write bytes
Renames and reorganizes some of the methods.
Adds additional info the README in terms of what is done and what still needs done.

* Adds documentation for the remaining items that can be documented (i.e. everything but bit masks).
Adds the `set_fifo_self_wakeup` method.

* Removes the `derive-new` dependency per the pull request discussion: #5

---------

Co-authored-by: Dan Whitman <dwhitman44@mgail.com>
  • Loading branch information
kyp44 and Dan Whitman committed Oct 27, 2023
1 parent 560335f commit 62296bc
Show file tree
Hide file tree
Showing 4 changed files with 701 additions and 326 deletions.
21 changes: 10 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
[package]
name = "bma423"
version = "0.0.1"
edition = "2021"
authors = ["Pierre-Yves Aillet <pyaillet@gmail.com>"]
categories = ["embedded", "hardware-support"]
description = "Rust driver for Bma423 accelerometer"
repository = "https://github.com/pyaillet/bma423-rs"
edition = "2021"
license = "MIT OR Apache-2.0"
name = "bma423"
readme = "README.md"

repository = "https://github.com/pyaillet/bma423-rs"
version = "0.0.1"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
embedded-hal = "^0.2"
num_enum = { version = "^0.5", default-features = false }
accelerometer = { version = "^0.12", optional = true }
bitmask-enum = { version = "^1.1" }
accelerometer = {version = "^0.12", optional = true}
bitmask-enum = {version = "^1.1"}
embedded-hal = "1.0.0-alpha.10"
num_enum = {version = "^0.5", default-features = false}

[features]
default = [ "accel" ]
accel = [ "accelerometer" ]
accel = ["accelerometer"]
default = ["accel"]
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,17 @@ This is an experimental Rust driver for the BMA423 accelerometer.

What's working:
- Getting x, y, z axis acceleration values
- The motion detection feature
- The tap detection feature
- Configuring the interrupt pins
- Mapping features to the interrupt pins (as outputs)

What's missing:
- Identifying activities and reporting them with interrupts
- The step counter and step detection features
- Activity classification feature
- Wrist wakeup feature
- Auxiliary interface configuration
- FIFO configuration

## Examples

Expand Down
174 changes: 174 additions & 0 deletions src/features.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
//! Items for configuring the features of the chip.
//!
//! The main item is [`EditFeatures`].

use core::ops::RangeInclusive;

use bitmask_enum::bitmask;

use crate::{Error, FullPower, Reg};

pub(crate) const FEATURE_SIZE: usize = 70;

#[repr(u8)]
#[derive(Copy, Clone, Debug)]
enum FeatureOffset {
AnyMotion = 0x00,
NoMotion = 0x04,
//StepCounterParam = 0x08,
//StepCounter = 0x3A,
SingleTap = 0x3C,
DoubleTap = 0x3E,
//WristWear = 0x40,
//ConfigId = 0x42,
//AxesRemap = 0x44,
}

/// Which motion feature
#[derive(Copy, Clone, Debug)]
pub enum MotionFeature {
/// Any motion detection feature
AnyMotion,
/// No motion detection feature
NoMotion,
}

// Motion feature valid value ranges
const MOTION_THRESHOLD_RANGE: RangeInclusive<u16> = 0..=0x7FF;
const MOTION_DURATION_RANGE: RangeInclusive<u16> = 0..=0x1FFF;

/// Motion feature axes.
///
/// Can be combined like a bitmask.
#[bitmask(u8)]
#[derive(Copy, Clone, Debug)]
pub enum MotionAxes {
AxisX = Self(0b0010_0000),
AxisY = Self(0b0100_0000),
AxisZ = Self(0b1000_0000),
}

// Tap sensitivity valid value ranges
const TAP_SENSITIVITY_RANGE: RangeInclusive<u8> = 0..=7;

/// Which tap feature
#[derive(Copy, Clone, Debug)]
pub enum TapFeature {
/// Single tap detection feature
SingleTap,
/// Double tap detection feature
DoubleTap,
}

/// Allows editing feature configurations in an efficient way.
///
/// This can be obtained from the driver by calling
/// [`edit_features`](crate::Bma423::edit_features).
/// Once the desired features are configured, one must
/// call [`write`](EditFeatures::write) to write the
/// configurations back to the chip so that they take
/// effect.
pub struct EditFeatures<'a, I2C> {
pub(crate) register: [u8; FEATURE_SIZE + 1],
pub(crate) driver: &'a mut crate::Bma423<I2C, FullPower>,
}
impl<I2C: embedded_hal::i2c::I2c> EditFeatures<'_, I2C> {
/// Allows editing the features register without the offset.
fn edit_register(&mut self, f: impl FnOnce(&mut [u8])) {
f(&mut self.register[1..FEATURE_SIZE + 1]);
}

/// Sets the motion detection feature configuration.
///
/// # Arguments
///
/// - `which` Specifies which motion feature to configure.
/// - `threshold` Slope threshold for motion detection.
/// The least significant bit is 0.48828125 mg, and the valid
/// range is 0 to 0x7FF (1 g).
/// The default value is 0xAA (83 mg).
/// - `duration` The number of consecutive data points for which
/// the threshold condition must be respected.
/// In terms of time, the least significant bit is 20 ms, and the
/// valid range is 0 to 0x1FFF (163 s).
/// The default value is 5 (100 ms).
/// - `enabled_axes` Axes for which to enable the motion detection.
pub fn set_motion_config(
&mut self,
which: MotionFeature,
threshold: u16,
duration: u16,
enabled_axes: MotionAxes,
) -> Result<(), Error<I2C::Error>> {
// Validate arguments
if !MOTION_THRESHOLD_RANGE.contains(&threshold)
|| !MOTION_DURATION_RANGE.contains(&duration)
{
return Err(Error::BadArgument);
}

self.edit_register(|reg| {
let offset = match which {
MotionFeature::AnyMotion => FeatureOffset::AnyMotion,
MotionFeature::NoMotion => FeatureOffset::NoMotion,
} as usize;

// Set the threshold
let threshold = threshold.to_le_bytes();
reg[offset + 0] = threshold[0];

Check warning on line 118 in src/features.rs

View workflow job for this annotation

GitHub Actions / clippy

this operation has no effect

warning: this operation has no effect --> src/features.rs:118:17 | 118 | reg[offset + 0] = threshold[0]; | ^^^^^^^^^^ help: consider reducing it to: `offset` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#identity_op = note: `#[warn(clippy::identity_op)]` on by default
reg[offset + 1] = threshold[1];

// Set the duration
let duration = duration.to_le_bytes();
reg[offset + 2] = duration[0];
reg[offset + 3] = duration[1];

// Set enabled axes
reg[offset + 3] = u8::from(enabled_axes) & 0xE0;
});

Ok(())
}

/// Sets the tap detection feature configuration.
///
/// The features can be enabled using [`edit_feature`](crate::Bma423::edit_features).
///
/// # Arguments
///
/// - `which` Specifies which tap feature to configure.
/// - `sensitivity` A sensitivity level from 0 (most sensitive) to
/// 7 (least sensitive).
/// The default value is 3.
/// - `enable` Whether to enable or disable tap detection.
pub fn set_tap_config(
&mut self,
which: TapFeature,
sensitivity: u8,
enable: bool,
) -> Result<(), Error<I2C::Error>> {
if !TAP_SENSITIVITY_RANGE.contains(&sensitivity) {
return Err(Error::BadArgument);
}

self.edit_register(|reg| {
let offset = match which {
TapFeature::SingleTap => FeatureOffset::SingleTap,
TapFeature::DoubleTap => FeatureOffset::DoubleTap,
} as usize;

reg[offset] = sensitivity << 1;
if enable {
reg[offset] |= 1;
}
});

Ok(())
}

/// Writes the edited features back to the chip so that they take effect.
pub fn write(mut self) -> Result<(), Error<I2C::Error>> {
self.register[0] = Reg::FeatureConfig.into();
self.driver.write(&self.register)
}
}
Loading

0 comments on commit 62296bc

Please sign in to comment.