#magnetometer #gyroscope #accelerometer #embedded-hal-driver #temperature-sensor

no-std lsm9ds1

A platform agnostic driver to interface with LSM9DS1 3D accelerometer, 3D gyroscope, 3D magnetometer sensor module

1 unstable release

0.1.0 Mar 17, 2020

#1009 in Embedded development

MIT license

58KB
1K SLoC

lsm9ds1

A platform agnostic driver to interface with LSM9DS1 3D accelerometer, 3D gyroscope, 3D magnetometer sensor module.

This library is work in progress. Not all features are implemented yet. Contributions are welcome.

Features

  • SPI communication with Accelerometer/Gyroscope
  • SPI communication with Magnetometer
  • SPI communication with Temperature Sensor
  • I2C communication with Accelerometer/Gyroscope
  • I2C communication with Magnetometer
  • I2C communication with Temperature Sensor
  • Custom sensor settings
  • Sensor reading (Accel, Gyro, Mag, Temperature)
  • Raw Sensor reading (Accel, Gyro, Mag) See read_sensor_raw().
  • Calibration
  • Interrupt
  • FIFO Mode

Usage

Overview

  1. Configure sensor settings with LSM9DS1Init.
  2. Initialize a communication interface: either SpiInterface or I2cInterface.
  3. Initialize LSM9DS1 driver with the interface of your choice.
  4. Start the sensors.
  5. Get the sensors' readings.

Sensor Settings

This driver uses LSM9DS1Init struct to set sensor configuration.

pub struct LSM9DS1Init {
    pub accel: AccelSettings,
    pub gyro: GyroSettings,
    pub mag: MagSettings,
}

You can find each sensor's default settings in accel.rs, gyro.rs and mag.rs.

Accelerometer default settings

impl Default for AccelSettings {
    fn default() -> Self {
        AccelSettings {
            enable_x: true,
            enable_y: true,
            enable_z: true,
            sample_rate: ODR::_119Hz,
            scale: Scale::_2G,
            bandwidth_selection: BandwidthSelection::ByODR,
            bandwidth: Bandwidth::_408Hz,
            high_res_bandwidth: HighRes::Disabled,
        }
    }
}

Gyroscope default settings

impl Default for GyroSettings {
    fn default() -> Self {
        GyroSettings {
            enable_x: true,
            enable_y: true,
            enable_z: true,
            flip_x: false,
            flip_y: false,
            flip_z: false,
            scale: Scale::_245DPS,
            sample_rate: ODR::_952Hz,
            bandwidth: Bandwidth::LPF_0,
            int_selection: GyroIntSelection::SEL_0,
            out_selection: GyroOutSelection::SEL_0,
            low_power_mode: LowPowerMode::Disabled,
            hpf_mode: HpFilter::Disabled,
            hpf_cutoff: HpFilterCutoff::HPCF_1,
            latch_interrupt: LatchInterrupt::Disabled,
        }
    }
}

Magnetometer default settings

impl Default for MagSettings {
    fn default() -> Self {
        MagSettings {
            temp_compensation: TempComp::Disabled,
            x_y_performance: OpModeXY::Low,
            sample_rate: ODR::_10Hz,
            scale: Scale::_4G,
            i2c_mode: I2cMode::Enabled,
            system_op: SysOpMode::Continuous,
            low_power: LowPowerMode::Disabled,
            spi_mode: SpiMode::RW,
            z_performance: OpModeZ::Low,
        }
    }
}

How to configure settings

If you want to use the default settings, initialize LSM9DS1Init this way.

LSM9DS1Init {
    ..Default::default()
}

If you want a custom configuration, modify the fields that are different from the default values.

LSM9DS1Init {
    accel: accel::AccelSettings {
        scale: accel::Scale::_16G, // custom setting
        ..Default::default() // the rest of the fields are the default values.
    },
    ..Default::default() // gyro and mag use the default settings.
}

Communication Interface

LSM9DS1 supports SPI and I2C communication. Create an instance of SpiInterface or I2cInterface and pass it to LSM9DS1Init's with_interface() method to create an instance of LSM9DS1 driver.

// Create SPI interface
let spi_interface = SpiInterface::init(spi, ag_cs, m_cs);
// Init LSM9DS1 driver with settings and SPI interface
let mut lsm9ds1 = LSM9DS1Init {
    ..Default::default()
}
.with_interface(spi_interface);

Reading Sensors

Turn on sensors.

lsm9ds1.begin_accel().unwrap();
lsm9ds1.begin_gyro().unwrap();
lsm9ds1.begin_mag().unwrap();

Get readings

let temp = lsm9ds1.read_temp().unwrap(); // temperature reading in celsius
let (x, y, z) = lsm9ds1.read_accel().unwrap();
let (x, y, z) = lsm9ds1.read_gyro().unwrap();
let (x, y, z) = lsm9ds1.read_mag().unwrap();

Example

This code shows how to read sensor values with SPI interface. (Error handling is omitted for brevity.)

//! Target board: STM32F3DISCOVERY
#![no_std]
#![no_main]

extern crate panic_semihosting;
pub use cortex_m::{asm::bkpt, iprint, iprintln, peripheral::ITM};
use cortex_m_rt::entry;
use embedded_hal::spi::MODE_0;
use stm32f3xx_hal as hal;

use hal::prelude::*;
use hal::spi::Spi;
use hal::stm32;

use lsm9ds1::interface::SpiInterface;
use lsm9ds1::{accel, gyro, mag, LSM9DS1Init};

#[entry]
fn main() -> ! {
    let cp = cortex_m::Peripherals::take().unwrap();
    let mut itm = cp.ITM;
    let dp = stm32::Peripherals::take().unwrap();
    let mut flash = dp.FLASH.constrain();
    let mut rcc = dp.RCC.constrain();

    // Accelerometer/Gyroscope Chip Select
    let mut gpiob = dp.GPIOB.split(&mut rcc.ahb);
    let mut ag_cs = gpiob
        .pb5
        .into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper);
    ag_cs.set_high().unwrap();

    // Magnetometer Chip Select
    let mut m_cs = gpiob
        .pb4
        .into_push_pull_output(&mut gpiob.moder, &mut gpiob.otyper);
    m_cs.set_high().unwrap();

    // SPI
    let mut gpioa = dp.GPIOA.split(&mut rcc.ahb);
    let clocks = rcc.cfgr.freeze(&mut flash.acr);
    // Configure pins for SPI
    let sck = gpioa.pa5.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
    let miso = gpioa.pa6.into_af5(&mut gpioa.moder, &mut gpioa.afrl);
    let mosi = gpioa.pa7.into_af5(&mut gpioa.moder, &mut gpioa.afrl);

    let spi = Spi::spi1(
        dp.SPI1,
        (sck, miso, mosi),
        MODE_0,
        1.mhz(),
        clocks,
        &mut rcc.apb2,
    );

    // Create SPI interface
    let spi_interface = SpiInterface::init(spi, ag_cs, m_cs);
    // Init LSM9DS1 with default settings and attach SPI interface
    let mut lsm9ds1 = LSM9DS1Init {
        ..Default::default()
    }
    .with_interface(spi_interface);
	
    // start sensors
    lsm9ds1.begin_accel().unwrap();
    lsm9ds1.begin_gyro().unwrap();
    lsm9ds1.begin_mag().unwrap();

    loop {
        // read sensors
        let temp = lsm9ds1.read_temp().unwrap();
        iprintln!(&mut itm.stim[0], "temp: {}", temp);

        let (x, y, z) = lsm9ds1.read_accel().unwrap();
        iprintln!(&mut itm.stim[0], "xl: {}, {}, {}", x, y, z);

        let (x, y, z) = lsm9ds1.read_gyro().unwrap();
        iprintln!(&mut itm.stim[0], "gy: {}, {}, {}", x, y, z);

        let (x, y, z) = lsm9ds1.read_mag().unwrap();
        iprintln!(&mut itm.stim[0], "mg: {}, {}, {}", x, y, z);

        cortex_m::asm::delay(8_000_000);
    }
}

Dependencies

~71KB