GithubHelp home page GithubHelp logo

eldruin / lsm303agr-rs Goto Github PK

View Code? Open in Web Editor NEW
18.0 3.0 14.0 134 KB

Platform agnostic Rust driver for the LSM303AGR ultra-compact high-performance eCompass module: ultra-low-power 3D accelerometer and 3D magnetometer

License: Apache License 2.0

Rust 99.79% Logos 0.21%
accelerometer magnetometer rust driver embedded-hal-driver i2c spi ecompass embedded

lsm303agr-rs's Introduction

Rust LSM303AGR Ultra-low-power 3D Accelerometer and 3D Magnetometer Driver

crates.io Docs Minimum Supported Rust Version Build Status Coverage Status

This is a platform agnostic Rust driver for the LSM303AGR ultra-compact high-performance eCompass module: ultra-low-power 3D accelerometer and 3D magnetometer using the embedded-hal traits. This driver also supports the [embedded-hal-async] traits if the async feature is enabled.

This driver allows you to:

  • Connect through I2C or SPI. See: new_with_i2c().
  • Initialize the device. See: init().
  • Accelerometer:
    • Read measured acceleration. See: acceleration().
    • Get accelerometer status. See: accel_status().
    • Set accelerometer mode and output data rate. See: set_accel_mode_and_odr().
    • Set accelerometer scale. See: set_accel_scale().
    • Get accelerometer ID. See: accelerometer_id().
    • Get temperature sensor status. See: temperature_status().
    • Read measured temperature. See: temperature().
    • Configure FIFO. See: acc_set_fifo_mode().
    • Enable/disable interrupts. See: acc_enable_interrupt().
  • Magnetometer:
    • Get the magnetometer status. See: mag_status().
    • Change into continuous/one-shot mode. See: into_mag_continuous().
    • Read measured magnetic field. See: magnetic_field().
    • Set magnetometer mode and output data rate. See: set_mag_mode_and_odr().
    • Get magnetometer ID. See: magnetometer_id().
    • Enable/disable magnetometer built in offset cancellation. See: enable_mag_offset_cancellation().
    • Enable/disable magnetometer low-pass filter. See: mag_enable_low_pass_filter().

The LSM303AGR is an ultra-low-power high- performance system-in-package featuring a 3D digital linear acceleration sensor and a 3D digital magnetic sensor. The LSM303AGR has linear acceleration full scales of ±2g/±4g/±8g/±16g and a magnetic field dynamic range of ±50 gauss.

The LSM303AGR includes an I2C serial bus interface that supports standard, fast mode, fast mode plus, and high-speed (100 kHz, 400 kHz, 1 MHz, and 3.4 MHz) and an SPI serial standard interface.

The system can be configured to generate an interrupt signal for free-fall, motion detection and magnetic field detection.

The magnetic and accelerometer blocks can be enabled or put into power-down mode separately.

Documents: Datasheet - Application note

Usage

To use this driver, import this crate and an embedded_hal implementation, then instantiate the device.

Please find additional examples using hardware in this repository: driver-examples

use linux_embedded_hal::{Delay, I2cdev};
use lsm303agr::{AccelMode, AccelOutputDataRate, Lsm303agr};

fn main() {
    let dev = I2cdev::new("/dev/i2c-1").unwrap();
    let mut sensor = Lsm303agr::new_with_i2c(dev);
    sensor.init().unwrap();
    sensor
        .set_accel_mode_and_odr(&mut Delay, AccelMode::Normal, AccelOutputDataRate::Hz50)
        .unwrap();
    loop {
        if sensor.accel_status().unwrap().xyz_new_data() {
            let data = sensor.acceleration().unwrap();
            println!(
                "Acceleration: x {} y {} z {}",
                data.x_mg(),
                data.y_mg(),
                data.z_mg()
            );
        }
    }
}

For an example of using the async support of this driver on a micro:bit V2, have a look at microbit-v2 example.

Support

For questions, issues, feature requests, and other changes, please file an issue in the github project.

License

Licensed under either of

at your option.

Contributing

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

lsm303agr-rs's People

Contributors

chrysn avatar clebi avatar dam4rus avatar devonmorris avatar dusterthefirst avatar eldruin avatar hargonix avatar hdoordt avatar qwandor avatar reitermarkus avatar robyoung avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

lsm303agr-rs's Issues

Implement a calibration algorithm

Hi! I'm quite new to the embedded scene and, following the embedded wg's book, recently became interested in the micro:bit. The book references a wonderful BSP for it, however, it lacks many of the APIs that the official C++ lib offers. I noticed this crate is often used to alleviate that, however, I don't notice a calibration function currently implemented.

My proposal would be to implement the algorithm currently in use in the micro:bit API which, in turn, is implementing the manufacturer's algorithm. I am far from decent enough at Rust or familiar enough with embedded programming yet to do so myself, unfortunately.

Support for other LSM303x devices

I am the maintainer for the stm32f3-discovery board support crate, which is a replacement for the old f3 bsc.

It has recently come to my attention that the STMF3Discovery board has newer revisions with this IMU on board instead of the LSM303DLHC. The accelerometers on the AGR and DLHC are compatible, only the magnometers and temperature sensors differ. In fact, the old, unmaintained, lsm303dlhc driver works just fine for the accelerometer.

This driver's API is also already almost compatible with the old lsm303dlhc driver.

I understand that the LSM303DLHC is obsolete and out of production, but there are still a number of them floating around in the wild and I would like to support both variants of the board if I can.

I can, obviously, plaster over the differences in APIs and use a feature gate to switch between the two drivers, but I was curious if you'd be open to adding support for the older device here, considering they share so much common implementation code. I'm happy to put in some work here, but didn't want to do so if there wasn't a chance of it being merged.

Sensors report 0 everywhere since version 0.3

Something changed between 0.2.2 and 0.3 that makes the sensor on a microbit-v2 report all-zeros on every measurement.

(As I had 0.2.2 last time I updated and used this to develop my embedded-hal 1.0 implementation, this made me doubt my sanity -- but indeed already 0.3 has the trouble, which is embedded-hal 0.2 based.)

I have yet to bisect between 0.3 and 0.2.2 (maybe with some more linearity than regular bisection to avoid editing back and forth through API changes), and will keep this updated.

Support async

Hi @eldruin thanks for another great driver crate!

I'm looking to use this driver in an async context. Would you be in favour of adding driver implementations based on embedded-hal-async traits? If so, what would you suggest be the best way to go about it?

Implement the manufacturer self-tests

It would be nice to have the manufacturer self tests from section 4.1.5 and 4.2.4 of the LSM303AGR datasheet available as methods in this crate. I have a micro:bit v2 with a broken (probably just massively hard-iron miscalibrated) magnetometer, and it took quite a thing to notice it and figure it out. Would prefer to just call a self-test and note failure…

I'll work on this when I get time, but it may be a while. Hopefully someone will beat me to it.

Confusing readings with different accelerometer modes

I am using this library on micro:bit (tested on a V1.5 and V2) and getting some confusing readings when experimenting with different AccelMode values.

When I change the AccelMode I get different values for the readings. My understanding of the resolution_factor used here is that it accounts for the different number of bits used in each operating mode (described in 4.2.1 of the datasheet).

It looks as though the HighResolution data is correct (Z is approximately equal to 1000mg). This is what I would expect from the datasheet. However, it looks as though the Normal and LowPower data is also being returned the same and then getting sent off by the reslution_factor.

Example code

The full example, working on the V1.5 or V2 micro:bit, can be found here. Run it with

cargo run --release --manifest-path ./examples/magnetometer/Cargo.toml --features v1 --target thumbv6m-none-eabi

The main logic of the example is also copied below for convenience.

let mut sensor = Lsm303agr::new_with_i2c(i2c);
match sensor.accelerometer_id() {
    Ok(0x33u8) => {},
    _ => defmt::panic!("accelerometer not found"),
}
timer.delay_ms(100_u32);
defmt::info!("before init");
sensor.init().unwrap();
defmt::info!("before set accel odr");
sensor.set_accel_odr(AccelOutputDataRate::Hz50).unwrap();
sensor.set_accel_mode(AccelMode::Normal).unwrap();
timer.delay_ms(1000_u32);
get_data(&mut sensor);
sensor.set_accel_mode(AccelMode::LowPower).unwrap();
timer.delay_ms(1000_u32);
get_data(&mut sensor);
sensor.set_accel_mode(AccelMode::HighResolution).unwrap();
timer.delay_ms(1000_u32);
get_data(&mut sensor);
fn get_data(sensor: &mut Lsm303agr<I2cInterface<twim::Twim<TWIM1>>, MagOneShot>) {
    let mut counter = 0;
    loop {
        if sensor.accel_status().unwrap().xyz_new_data {
            let data = sensor.accel_data().unwrap();
            defmt::info!("Acceleration: x {} y {} z {}", data.x, data.y, data.z);
            counter += 1;
        }
        if counter > 2 {
            return;
        }
    }
}

And the output I get (with the data being written to the registers)

 INFO  before init
 INFO  register: 0x23 data: 0b10000000
 INFO  before set accel odr
 INFO  register: 0x20 data: 0b1000111
 INFO  register: 0x20 data: 0b1000111
 INFO  register: 0x23 data: 0b10000000
 INFO  Acceleration: x -35 y -60 z -247
 INFO  Acceleration: x -36 y -60 z -247
 INFO  Acceleration: x -36 y -59 z -253
 INFO  register: 0x23 data: 0b10000000
 INFO  register: 0x20 data: 0b1001111
 INFO  Acceleration: x -8 y -15 z -62
 INFO  Acceleration: x -9 y -16 z -63
 INFO  Acceleration: x -9 y -15 z -62
 INFO  register: 0x20 data: 0b1000111
 INFO  register: 0x23 data: 0b10001000
 INFO  Acceleration: x -141 y -240 z -994
 INFO  Acceleration: x -142 y -242 z -995
 INFO  Acceleration: x -141 y -238 z -997

Proper way to read from fifo?

I'm poking around, and trying to understand how the fifo is set up. EDIT: Skip the rest of this comment, I have resolved most of my confusion in the second comment in the thread.

From the datasheet it seems you have to set fifo mode to bypass to clear the fifo after you read it, which seems to be sorta working, but I am not sure if this is how the reading is intended, I seem to always get "dead" data for the first sensor.acceleration() read. Is there a better way to read a chunk from the buffer? Is there a way to see how much is in the buffer? In my bogus test code below, I am intentionally reading too far, and just get duplicated data for the last item(s).

sensor.set_accel_mode_and_odr(
            &mut delay,
            lsm303agr::AccelMode::LowPower,
            lsm303agr::AccelOutputDataRate::Hz10,
        )
        .unwrap();

    let _ = sensor.acc_set_fifo_mode(lsm303agr::FifoMode::Fifo, 31);

    loop {
        for _ in 0..12 {
            let data = sensor.acceleration().unwrap();
            rprintln!(
                "x {} y {} z {}",
                data.x_mg(),
                data.y_mg(),
                data.z_mg()
            );
        }
        rprintln!(" ");
        let _ = sensor.acc_set_fifo_mode(lsm303agr::FifoMode::Bypass, 0);
        let _ = sensor.acc_set_fifo_mode(lsm303agr::FifoMode::Fifo, 31);

        delay.delay_ms(1000_u32);

     }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.