Skip to content

Instantly share code, notes, and snippets.

@jimblom
Created April 3, 2015 17:36
Show Gist options
  • Save jimblom/08b333892ee383d6e443 to your computer and use it in GitHub Desktop.
Save jimblom/08b333892ee383d6e443 to your computer and use it in GitHub Desktop.
LSM9DS1 Simple - Spark Core
/*****************************************************************
LSM9DS1_Simple.ino
SFE_LSM9DS1 Library Simple Example Code
Jim Lindblom @ SparkFun Electronics
Original Creation Date: February 27, 2015
https://github.com/sparkfun/LSM9DS1_Breakout
The LSM9DS1 is a versatile 9DOF sensor. It has a built-in
accelerometer, gyroscope, and magnetometer. Very cool! Plus it
functions over either SPI or I2C.
This Arduino sketch is a demo of the simple side of the
SFE_LSM9DS1 library. It'll demo the following:
* How to create a LSM9DS1 object, using a constructor (global
variables section).
* How to use the begin() function of the LSM9DS1 class.
* How to read the gyroscope, accelerometer, and magnetometer
using the readGryo(), readAccel(), readMag() functions and the
gx, gy, gz, ax, ay, az, mx, my, and mz variables.
* How to calculate actual acceleration, rotation speed, magnetic
field strength using the calcAccel(), calcGyro() and calcMag()
functions.
* How to use the data from the LSM9DS1 to calculate orientation
and heading.
Hardware setup: This library supports communicating with the
LSM9DS1 over either I2C or SPI. If you're using I2C, these are
the only connections that need to be made:
LSM9DS1 --------- Arduino
SCL ---------- SCL (A5 on older 'Duinos')
SDA ---------- SDA (A4 on older 'Duinos')
VDD ------------- 3.3V
GND ------------- GND
(CSG, CSXM, SDOG, and SDOXM should all be pulled high jumpers on
the breakout board will do this for you.)
If you're using SPI, here is an example hardware setup:
LSM9DS1 --------- Arduino
CSG -------------- 9
CSXM ------------- 10
SDOG ------------- 12
SDOXM ------------ 12 (tied to SDOG)
SCL -------------- 13
SDA -------------- 11
VDD -------------- 3.3V
GND -------------- GND
The LSM9DS1 has a maximum voltage of 3.6V. Make sure you power it
off the 3.3V rail! And either use level shifters between SCL
and SDA or just use a 3.3V Arduino Pro.
Development environment specifics:
IDE: Arduino 1.6.0
Hardware Platform: Arduino Uno
LSM9DS1 Breakout Version: 1.0
This code is beerware. If you see me (or any other SparkFun
employee) at the local, and you've found our code helpful, please
buy us a round!
Distributed as-is; no warranty is given.
*****************************************************************/
#include "SFE_LSM9DS1.h"
#include "math.h"
///////////////////////
// Example I2C Setup //
///////////////////////
// Comment out this section if you're using SPI
// SDO_XM and SDO_G are both grounded, so our addresses are:
#define LSM9DS1_M 0x1E // Would be 0x1C if SDO_XM is LOW
#define LSM9DS1_AG 0x6B // Would be 0x6A if SDO_G is LOW
// Create an instance of the LSM9DS1 library called `dof` the
// parameters for this constructor are:
// [SPI or I2C Mode declaration],[gyro I2C address],[xm I2C add.]
LSM9DS1 dof(MODE_I2C, LSM9DS1_AG, LSM9DS1_M);
///////////////////////
// Example SPI Setup //
///////////////////////
/* // Uncomment this section if you're using SPI
#define LSM9DS1_CSG 9 // CSG connected to Arduino pin 9
#define LSM9DS1_CSXM 10 // CSXM connected to Arduino pin 10
LSM9DS1 dof(MODE_SPI, LSM9DS1_CSG, LSM9DS1_CSXM);
*/
// Do you want to print calculated values or raw ADC ticks read
// from the sensor? Comment out ONE of the two #defines below
// to pick:
#define PRINT_CALCULATED
//#define PRINT_RAW
#define PRINT_SPEED 500 // 500 ms between prints
void setup()
{
Serial.begin(115200); // Start serial at 115200 bps
// Use the begin() function to initialize the LSM9DS1 library.
// You can either call it with no parameters (the easy way):
uint16_t status = dof.begin();
// Or call it with declarations for sensor scales and data rates:
//uint16_t status = dof.begin(dof.G_SCALE_2000DPS,
// dof.A_SCALE_6G, dof.M_SCALE_2GS);
// begin() returns a 16-bit value which includes both the gyro
// and accelerometers WHO_AM_I response. You can check this to
// make sure communication was successful.
Serial.print("LSM9DS1 WHO_AM_I's returned: 0x");
Serial.println(status, HEX);
Serial.println("Should be 0x683D");
Serial.println();
}
void loop()
{
printGyro(); // Print "G: gx, gy, gz"
printAccel(); // Print "A: ax, ay, az"
printMag(); // Print "M: mx, my, mz"
// Print the heading and orientation for fun!
printHeading((float) dof.mx, (float) dof.my);
printOrientation(dof.calcAccel(dof.ax), dof.calcAccel(dof.ay),
dof.calcAccel(dof.az));
Serial.println();
delay(PRINT_SPEED);
}
void printGyro()
{
// To read from the gyroscope, you must first call the
// readGyro() function. When this exits, it'll update the
// gx, gy, and gz variables with the most current data.
dof.readGyro();
// Now we can use the gx, gy, and gz variables as we please.
// Either print them as raw ADC values, or calculated in DPS.
Serial.print("G: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcGyro helper function to convert a raw ADC value to
// DPS. Give the function the value that you want to convert.
Serial.print(dof.calcGyro(dof.gx), 2);
Serial.print(", ");
Serial.print(dof.calcGyro(dof.gy), 2);
Serial.print(", ");
Serial.println(dof.calcGyro(dof.gz), 2);
#elif defined PRINT_RAW
Serial.print(dof.gx);
Serial.print(", ");
Serial.print(dof.gy);
Serial.print(", ");
Serial.println(dof.gz);
#endif
}
void printAccel()
{
// To read from the accelerometer, you must first call the
// readAccel() function. When this exits, it'll update the
// ax, ay, and az variables with the most current data.
dof.readAccel();
// Now we can use the ax, ay, and az variables as we please.
// Either print them as raw ADC values, or calculated in g's.
Serial.print("A: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcAccel helper function to convert a raw ADC value to
// g's. Give the function the value that you want to convert.
Serial.print(dof.calcAccel(dof.ax), 2);
Serial.print(", ");
Serial.print(dof.calcAccel(dof.ay), 2);
Serial.print(", ");
Serial.println(dof.calcAccel(dof.az), 2);
#elif defined PRINT_RAW
Serial.print(dof.ax);
Serial.print(", ");
Serial.print(dof.ay);
Serial.print(", ");
Serial.println(dof.az);
#endif
}
void printMag()
{
// To read from the magnetometer, you must first call the
// readMag() function. When this exits, it'll update the
// mx, my, and mz variables with the most current data.
dof.readMag();
// Now we can use the mx, my, and mz variables as we please.
// Either print them as raw ADC values, or calculated in Gauss.
Serial.print("M: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcMag helper function to convert a raw ADC value to
// Gauss. Give the function the value that you want to convert.
Serial.print(dof.calcMag(dof.mx), 2);
Serial.print(", ");
Serial.print(dof.calcMag(dof.my), 2);
Serial.print(", ");
Serial.println(dof.calcMag(dof.mz), 2);
#elif defined PRINT_RAW
Serial.print(dof.mx);
Serial.print(", ");
Serial.print(dof.my);
Serial.print(", ");
Serial.println(dof.mz);
#endif
}
// Here's a fun function to calculate your heading, using Earth's
// magnetic field.
// It only works if the sensor is flat (z-axis normal to Earth).
// Additionally, you may need to add or subtract a declination
// angle to get the heading normalized to your location.
// See: http://www.ngdc.noaa.gov/geomag/declination.shtml
void printHeading(float hx, float hy)
{
float heading;
if (hy > 0)
{
heading = 90 - (atan(hx / hy) * (180 / M_PI));
}
else if (hy < 0)
{
heading = - (atan(hx / hy) * (180 / M_PI));
}
else // hy = 0
{
if (hx < 0) heading = 180;
else heading = 0;
}
Serial.print("Heading: ");
Serial.println(heading, 2);
}
// Another fun function that does calculations based on the
// acclerometer data. This function will print your LSM9DS1's
// orientation -- it's roll and pitch angles.
void printOrientation(float x, float y, float z)
{
float pitch, roll;
pitch = atan2(x, sqrt(y * y) + (z * z));
roll = atan2(y, sqrt(x * x) + (z * z));
pitch *= 180.0 / M_PI;
roll *= 180.0 / M_PI;
Serial.print("Pitch, Roll: ");
Serial.print(pitch, 2);
Serial.print(", ");
Serial.println(roll, 2);
}
/******************************************************************************
SFE_LSM9DS1.cpp
SFE_LSM9DS1 Library Source File
Jim Lindblom @ SparkFun Electronics
Original Creation Date: February 27, 2015
https://github.com/sparkfun/LSM9DS1_Breakout
This file implements all functions of the LSM9DS1 class. Functions here range
from higher level stuff, like reading/writing LSM9DS1 registers to low-level,
hardware reads and writes. Both SPI and I2C handler functions can be found
towards the bottom of this file.
Development environment specifics:
IDE: Arduino 1.6
Hardware Platform: Arduino Uno
LSM9DS1 Breakout Version: 1.0
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#include "SFE_LSM9DS1.h"
#include "application.h"
LSM9DS1::LSM9DS1()
{
}
LSM9DS1::LSM9DS1(interface_mode interface, uint8_t xgAddr, uint8_t mAddr)
{
// interfaceMode will keep track of whether we're using SPI or I2C:
interfaceMode = interface;
// mAddress and xgAddress will store the 7-bit I2C address, if using I2C.
// If we're using SPI, these variables store the chip-select pins.
mAddress = mAddr;
xgAddress = xgAddr;
}
void LSM9DS1::init(interface_mode interface, uint8_t xgAddr, uint8_t mAddr)
{
// interfaceMode will keep track of whether we're using SPI or I2C:
interfaceMode = interface;
// mAddress and xgAddress will store the 7-bit I2C address, if using I2C.
// If we're using SPI, these variables store the chip-select pins.
mAddress = mAddr;
xgAddress = xgAddr;
}
uint16_t LSM9DS1::begin(gyro_scale gScl, accel_scale aScl, mag_scale mScl,
gyro_odr gODR, accel_odr aODR, mag_odr mODR)
{
// Store the given scales in class variables. These scale variables
// are used throughout to calculate the actual g's, DPS,and Gs's.
gScale = gScl;
aScale = aScl;
mScale = mScl;
// Once we have the scale values, we can calculate the resolution
// of each sensor. That's what these functions are for. One for each sensor
calcgRes(); // Calculate DPS / ADC tick, stored in gRes variable
calcmRes(); // Calculate Gs / ADC tick, stored in mRes variable
calcaRes(); // Calculate g / ADC tick, stored in aRes variable
// Now, initialize our hardware interface.
if (interfaceMode == MODE_I2C) // If we're using I2C
initI2C(); // Initialize I2C
else if (interfaceMode == MODE_SPI) // else, if we're using SPI
initSPI(); // Initialize SPI
// To verify communication, we can read from the WHO_AM_I register of
// each device. Store those in a variable so we can return them.
uint8_t mTest = mReadByte(WHO_AM_I_M); // Read the gyro WHO_AM_I
uint8_t xlTest = xgReadByte(WHO_AM_I_XG); // Read the accel/mag WHO_AM_I
// Gyro initialization stuff:
initGyro(); // This will "turn on" the gyro. Setting up interrupts, etc.
setGyroODR(gODR); // Set the gyro output data rate and bandwidth.
setGyroScale(gScale); // Set the gyro range
// Accelerometer initialization stuff:
initAccel(); // "Turn on" all axes of the accel. Set up interrupts, etc.
setAccelODR(aODR); // Set the accel data rate.
setAccelScale(aScale); // Set the accel range.
// Magnetometer initialization stuff:
initMag(); // "Turn on" all axes of the mag. Set up interrupts, etc.
setMagODR(mODR); // Set the magnetometer output data rate.
setMagScale(mScale); // Set the magnetometer's range.
// Once everything is initialized, return the WHO_AM_I registers we read:
return (xlTest << 8) | mTest;
}
void LSM9DS1::initGyro()
{
// CTRL_REG1_G (Default value: 0x00)
// [ODR_G2][ODR_G1][ODR_G0][FS_G1][FS_G0][0][BW_G1][BW_G0]
// ODR_G[2:0] - Output data rate selection
// FS_G[1:0] - Gyroscope full-scale selection
// BW_G[1:0] - Gyroscope bandwidth selection
xgWriteByte(CTRL_REG1_G, 0xC0); // 952 Hz OD, 33 Hz cutoff
// CTRL_REG2_G (Default value: 0x00)
// [0][0][0][0][INT_SEL1][INT_SEL0][OUT_SEL1][OUT_SEL0]
// INT_SEL[1:0] - INT selection configuration
// OUT_SEL[1:0] - Out selection configuration
xgWriteByte(CTRL_REG2_G, 0x00);
// CTRL_REG3_G (Default value: 0x00)
// [LP_mode][HP_EN][0][0][HPCF3_G][HPCF2_G][HPCF1_G][HPCF0_G]
// LP_mode - Low-power mode enable (0: disabled, 1: enabled)
// HP_EN - HPF enable (0:disabled, 1: enabled)
// HPCF_G[3:0] - HPF cutoff frequency
xgWriteByte(CTRL_REG3_G, 0x00);
// CTRL_REG4 (Default value: 0x38)
// [0][0][Zen_G][Yen_G][Xen_G][0][LIR_XL1][4D_XL1]
// Zen_G - Z-axis output enable (0:disable, 1:enable)
// Yen_G - Y-axis output enable (0:disable, 1:enable)
// Xen_G - X-axis output enable (0:disable, 1:enable)
// LIR_XL1 - Latched interrupt (0:not latched, 1:latched)
// 4D_XL1 - 4D option on interrupt (0:6D used, 1:4D used)
xgWriteByte(CTRL_REG4, 0x38);
}
void LSM9DS1::initAccel()
{
// CTRL_REG5_XL (0x1F) (Default value: 0x38)
// [DEC_1][DEC_0][Zen_XL][Yen_XL][Zen_XL][0][0][0]
// DEC[0:1] - Decimation of accel data on OUT REG and FIFO.
// 00: None, 01: 2 samples, 10: 4 samples 11: 8 samples
// Zen_XL - Z-axis output enabled
// Yen_XL - Y-axis output enabled
// Xen_XL - X-axis output enabled
xgWriteByte(CTRL_REG5_XL, 0x38);
// CTRL_REG6_XL (0x20) (Default value: 0x00)
// [ODR_XL2][ODR_XL1][ODR_XL0][FS1_XL][FS0_XL][BW_SCAL_ODR][BW_XL1][BW_XL0]
// ODR_XL[2:0] - Output data rate & power mode selection
// FS_XL[1:0] - Full-scale selection
// BW_SCAL_ODR - Bandwidth selection
// BW_XL[1:0] - Anti-aliasing filter bandwidth selection
xgWriteByte(CTRL_REG6_XL, 0x00);
// CTRL_REG7_XL (0x21) (Default value: 0x00)
// [HR][DCF1][DCF0][0][0][FDS][0][HPIS1]
// HR - High resolution mode (0: disable, 1: enable)
// DCF[1:0] - Digital filter cutoff frequency
// FDS - Filtered data selection
// HPIS1 - HPF enabled for interrupt function
xgWriteByte(CTRL_REG7_XL, 0x00);
}
void LSM9DS1::initMag()
{
// CTRL_REG1_M (Default value: 0x10)
// [TEMP_COMP][OM1][OM0][DO2][DO1][DO0][0][ST]
// TEMP_COMP - Temperature compensation
// OM[1:0] - X & Y axes op mode selection
// 00:low-power, 01:medium performance
// 10: high performance, 11:ultra-high performance
// DO[2:0] - Output data rate selection
// ST - Self-test enable
mWriteByte(CTRL_REG1_M, 0x1C); // 80 Hz ODR
// CTRL_REG2_M (Default value 0x00)
// [0][FS1][FS0][0][REBOOT][SOFT_RST][0][0]
// FS[1:0] - Full-scale configuration
// REBOOT - Reboot memory content (0:normal, 1:reboot)
// SOFT_RST - Reset config and user registers (0:default, 1:reset)
mWriteByte(CTRL_REG2_M, 0x00); // +/-4Gauss
// CTRL_REG3_M (Default value: 0x03)
// [I2C_DISABLE][0][LP][0][0][SIM][MD1][MD0]
// I2C_DISABLE - Disable I2C interace (0:enable, 1:disable)
// LP - Low-power mode cofiguration (1:enable)
// SIM - SPI mode selection (0:write-only, 1:read/write enable)
// MD[1:0] - Operating mode
// 00:continuous conversion, 01:single-conversion,
// 10,11: Power-down
mWriteByte(CTRL_REG3_M, 0x00); // Continuous conversion mode
// CTRL_REG4_M (Default value: 0x00)
// [0][0][0][0][OMZ1][OMZ0][BLE][0]
// OMZ[1:0] - Z-axis operative mode selection
// 00:low-power mode, 01:medium performance
// 10:high performance, 10:ultra-high performance
// BLE - Big/little endian data
mWriteByte(CTRL_REG4_M, 0x00);
// CTRL_REG5_M (Default value: 0x00)
// [0][BDU][0][0][0][0][0][0]
// BDU - Block data update for magnetic data
// 0:continuous, 1:not updated until MSB/LSB are read
mWriteByte(CTRL_REG5_M, 0x00);
}
// This is a function that uses the FIFO to accumulate sample of accelerometer and gyro data, average
// them, scales them to gs and deg/s, respectively, and then passes the biases to the main sketch
// for subtraction from all subsequent data. There are no gyro and accelerometer bias registers to store
// the data as there are in the ADXL345, a precursor to the LSM9DS1, or the MPU-9150, so we have to
// subtract the biases ourselves. This results in a more accurate measurement in general and can
// remove errors due to imprecise or varying initial placement. Calibration of sensor data in this manner
// is good practice.
/*
void LSM9DS1::calLSM9DS1(float * gbias, float * abias)
{
uint8_t data[6] = {0, 0, 0, 0, 0, 0};
int16_t gyro_bias[3] = {0, 0, 0}, accel_bias[3] = {0, 0, 0};
int samples, ii;
// First get gyro bias
byte c = gReadByte(CTRL_REG5_G);
gWriteByte(CTRL_REG5_G, c | 0x40); // Enable gyro FIFO
delay(20); // Wait for change to take effect
gWriteByte(FIFO_CTRL_REG_G, 0x20 | 0x1F); // Enable gyro FIFO stream mode and set watermark at 32 samples
delay(1000); // delay 1000 milliseconds to collect FIFO samples
samples = (gReadByte(FIFO_SRC_REG_G) & 0x1F); // Read number of stored samples
for(ii = 0; ii < samples ; ii++)
{ // Read the gyro data stored in the FIFO
gReadBytes(OUT_X_L_G, &data[0], 6);
gyro_bias[0] += (((int16_t)data[1] << 8) | data[0]);
gyro_bias[1] += (((int16_t)data[3] << 8) | data[2]);
gyro_bias[2] += (((int16_t)data[5] << 8) | data[4]);
}
gyro_bias[0] /= samples; // average the data
gyro_bias[1] /= samples;
gyro_bias[2] /= samples;
gbias[0] = (float)gyro_bias[0]*gRes; // Properly scale the data to get deg/s
gbias[1] = (float)gyro_bias[1]*gRes;
gbias[2] = (float)gyro_bias[2]*gRes;
c = gReadByte(CTRL_REG5_G);
gWriteByte(CTRL_REG5_G, c & ~0x40); // Disable gyro FIFO
delay(20);
gWriteByte(FIFO_CTRL_REG_G, 0x00); // Enable gyro bypass mode
// Now get the accelerometer biases
c = xmReadByte(CTRL_REG0_XM);
xmWriteByte(CTRL_REG0_XM, c | 0x40); // Enable accelerometer FIFO
delay(20); // Wait for change to take effect
xmWriteByte(FIFO_CTRL_REG, 0x20 | 0x1F); // Enable accelerometer FIFO stream mode and set watermark at 32 samples
delay(1000); // delay 1000 milliseconds to collect FIFO samples
samples = (xmReadByte(FIFO_SRC_REG) & 0x1F); // Read number of stored accelerometer samples
for(ii = 0; ii < samples ; ii++)
{ // Read the accelerometer data stored in the FIFO
xmReadBytes(OUT_X_L_A, &data[0], 6);
accel_bias[0] += (((int16_t)data[1] << 8) | data[0]);
accel_bias[1] += (((int16_t)data[3] << 8) | data[2]);
accel_bias[2] += (((int16_t)data[5] << 8) | data[4]) - (int16_t)(1./aRes); // Assumes sensor facing up!
}
accel_bias[0] /= samples; // average the data
accel_bias[1] /= samples;
accel_bias[2] /= samples;
abias[0] = (float)accel_bias[0]*aRes; // Properly scale data to get gs
abias[1] = (float)accel_bias[1]*aRes;
abias[2] = (float)accel_bias[2]*aRes;
c = xmReadByte(CTRL_REG0_XM);
xmWriteByte(CTRL_REG0_XM, c & ~0x40); // Disable accelerometer FIFO
delay(20);
xmWriteByte(FIFO_CTRL_REG, 0x00); // Enable accelerometer bypass mode
}
*/
void LSM9DS1::readAccel()
{
uint8_t temp[6]; // We'll read six bytes from the accelerometer into temp
xgReadBytes(OUT_X_L_XL, temp, 6); // Read 6 bytes, beginning at OUT_X_L_XL
ax = (temp[1] << 8) | temp[0]; // Store x-axis values into ax
ay = (temp[3] << 8) | temp[2]; // Store y-axis values into ay
az = (temp[5] << 8) | temp[4]; // Store z-axis values into az
}
void LSM9DS1::readMag()
{
uint8_t temp[6]; // We'll read six bytes from the mag into temp
mReadBytes(OUT_X_L_M, temp, 6); // Read 6 bytes, beginning at OUT_X_L_M
mx = (temp[1] << 8) | temp[0]; // Store x-axis values into mx
my = (temp[3] << 8) | temp[2]; // Store y-axis values into my
mz = (temp[5] << 8) | temp[4]; // Store z-axis values into mz
}
void LSM9DS1::readTemp()
{
uint8_t temp[2]; // We'll read two bytes from the temperature sensor into temp
xgReadBytes(OUT_TEMP_L, temp, 2); // Read 2 bytes, beginning at OUT_TEMP_L
temperature = (((int16_t) temp[1] << 12) | temp[0] << 4 ) >> 4; // Temperature is a 12-bit signed integer
}
void LSM9DS1::readGyro()
{
uint8_t temp[6]; // We'll read six bytes from the gyro into temp
xgReadBytes(OUT_X_L_G, temp, 6); // Read 6 bytes, beginning at OUT_X_L_G
gx = (temp[1] << 8) | temp[0]; // Store x-axis values into gx
gy = (temp[3] << 8) | temp[2]; // Store y-axis values into gy
gz = (temp[5] << 8) | temp[4]; // Store z-axis values into gz
}
float LSM9DS1::calcGyro(int16_t gyro)
{
// Return the gyro raw reading times our pre-calculated DPS / (ADC tick):
return gRes * gyro;
}
float LSM9DS1::calcAccel(int16_t accel)
{
// Return the accel raw reading times our pre-calculated g's / (ADC tick):
return aRes * accel;
}
float LSM9DS1::calcMag(int16_t mag)
{
// Return the mag raw reading times our pre-calculated Gs / (ADC tick):
return mRes * mag;
}
void LSM9DS1::setGyroScale(gyro_scale gScl)
{
// We need to preserve the other bytes in CTRL_REG4_G. So, first read it:
uint8_t temp = xgReadByte(CTRL_REG1_G);
// Then mask out the gyro scale bits:
temp &= 0xFF^(0x3 << 3);
// Then shift in our new scale bits:
temp |= gScl << 3;
// And write the new register value back into CTRL_REG4_G:
xgWriteByte(CTRL_REG1_G, temp);
// We've updated the sensor, but we also need to update our class variables
// First update gScale:
gScale = gScl;
// Then calculate a new gRes, which relies on gScale being set correctly:
calcgRes();
}
void LSM9DS1::setAccelScale(accel_scale aScl)
{
// We need to preserve the other bytes in CTRL_REG2_XM. So, first read it:
uint8_t temp = xgReadByte(CTRL_REG6_XL);
// Then mask out the accel scale bits:
temp &= 0xC7; //0xFF^(0x2 << 3);
// Then shift in our new scale bits:
temp |= (aScl << 3);
// And write the new register value back into CTRL_REG2_XM:
xgWriteByte(CTRL_REG6_XL, temp);
// We've updated the sensor, but we also need to update our class variables
// First update aScale:
aScale = aScl;
// Then calculate a new aRes, which relies on aScale being set correctly:
calcaRes();
}
void LSM9DS1::setMagScale(mag_scale mScl)
{
// We need to preserve the other bytes in CTRL_REG6_XM. So, first read it:
uint8_t temp = mReadByte(CTRL_REG2_M);
// Then mask out the mag scale bits:
temp &= 0xFF^(0x3 << 5);
// Then shift in our new scale bits:
temp |= mScl << 5;
// And write the new register value back into CTRL_REG6_XM:
mWriteByte(CTRL_REG2_M, temp);
// We've updated the sensor, but we also need to update our class variables
// First update mScale:
mScale = mScl;
// Then calculate a new mRes, which relies on mScale being set correctly:
calcmRes();
}
void LSM9DS1::setGyroODR(gyro_odr gRate)
{
// We need to preserve the other bytes in CTRL_REG1_G. So, first read it:
uint8_t temp = xgReadByte(CTRL_REG1_G);
// Then mask out the gyro ODR bits:
temp &= 0xFF^(0x7 << 5);
// Then shift in our new ODR bits:
temp |= (gRate << 5);
// And write the new register value back into CTRL_REG1_G:
xgWriteByte(CTRL_REG1_G, temp);
}
void LSM9DS1::setAccelODR(accel_odr aRate)
{
// We need to preserve the other bytes in CTRL_REG1_XM. So, first read it:
uint8_t temp = xgReadByte(CTRL_REG6_XL);
// Then mask out the accel ODR bits:
temp &= 0x1F;
// Then shift in our new ODR bits:
temp |= (aRate << 5);
// And write the new register value back into CTRL_REG1_XM:
xgWriteByte(CTRL_REG6_XL, temp);
}
/*
void LSM9DS1::setAccelABW(accel_abw abwRate)
{
// We need to preserve the other bytes in CTRL_REG2_XM. So, first read it:
uint8_t temp = xmReadByte(CTRL_REG2_XM);
// Then mask out the accel ABW bits:
temp &= 0xFF^(0x3 << 7);
// Then shift in our new ODR bits:
temp |= (abwRate << 7);
// And write the new register value back into CTRL_REG2_XM:
xmWriteByte(CTRL_REG2_XM, temp);
}
*/
void LSM9DS1::setMagODR(mag_odr mRate)
{
// We need to preserve the other bytes in CTRL_REG5_XM. So, first read it:
uint8_t temp = mReadByte(CTRL_REG1_M);
// Then mask out the mag ODR bits:
temp &= 0xFF^(0x7 << 2);
// Then shift in our new ODR bits:
temp |= (mRate << 2);
// And write the new register value back into CTRL_REG5_XM:
mWriteByte(CTRL_REG1_M, temp);
}
void LSM9DS1::configAccelIntTHS(interrupt_select intSelect, uint8_t ths_x_xl,
uint8_t ths_y_xl, uint8_t ths_z_xl)
{
/*
uint8_t temp;
if (intSelect == INT1)
{
temp = xgReadByte(INT1_CTRL);
temp |= (1<<6);
xgWriteByte(INT1_CTRL
}*/
}
void LSM9DS1::configAccelIntDRDY(interrupt_select intSelect, bool enable)
{
uint8_t temp;
uint8_t intRegister = intSelect;
temp = xgReadByte(intRegister);
if (enable)
temp |= (1<<0);
else
temp &= ~(1<<0);
xgWriteByte(intRegister, temp);
}
void LSM9DS1::configGyroIntDRDY(interrupt_select intSelect, bool enable)
{
uint8_t temp;
uint8_t intRegister = intSelect;
temp = xgReadByte(intRegister);
if (enable)
temp |= (1<<1);
else
temp &= ~(1<<1);
xgWriteByte(intRegister, temp);
}
void LSM9DS1::configAGInterrupt(h_lactive activeLow, pp_od pushPull)
{
uint8_t temp;
temp = xgReadByte(CTRL_REG8);
if (activeLow)
temp |= (1<<5);
else
temp &= ~(1<<5);
if (pushPull)
temp &= ~(1<<4);
else
temp |= (1<<4);
xgWriteByte(CTRL_REG8, temp);
}
void LSM9DS1::configMInterrupt(h_lactive activeLow)
{
uint8_t temp;
temp = mReadByte(INT_CFG_M);
if (activeLow)
temp &= ~(1<<2);
else
temp |= (1<<2);
mWriteByte(INT_CFG_M, temp);
}
void LSM9DS1::configMagIntTHS(int threshold, bool xien, bool yien, bool zien)
{
uint8_t msb, lsb, temp;
msb = (uint8_t)((threshold & 0x7F00) >> 8);
lsb = (uint8_t)(threshold & 0x00FF);
mWriteByte(INT_THS_L_M, lsb);
mWriteByte(INT_THS_H_M, msb);
temp = mReadByte(INT_CFG_M);
if (xien)
temp |= (1<<7);
else
temp &= ~(1<<7);
if (yien)
temp |= (1<<6);
else
temp &= ~(1<<6);
if (zien)
temp |= (1<<5);
else
temp &= ~(1<<5);
temp |= 1; // Set IEN
mWriteByte(INT_CFG_M, temp);
}
uint8_t LSM9DS1::getMagIntSrc()
{
return mReadByte(INT_SRC_M);
}
/*
void LSM9DS1::configGyroInt(uint8_t int1Cfg, uint16_t int1ThsX, uint16_t int1ThsY, uint16_t int1ThsZ, uint8_t duration)
{
gWriteByte(INT1_CFG_G, int1Cfg);
gWriteByte(INT1_THS_XH_G, (int1ThsX & 0xFF00) >> 8);
gWriteByte(INT1_THS_XL_G, (int1ThsX & 0xFF));
gWriteByte(INT1_THS_YH_G, (int1ThsY & 0xFF00) >> 8);
gWriteByte(INT1_THS_YL_G, (int1ThsY & 0xFF));
gWriteByte(INT1_THS_ZH_G, (int1ThsZ & 0xFF00) >> 8);
gWriteByte(INT1_THS_ZL_G, (int1ThsZ & 0xFF));
if (duration)
gWriteByte(INT1_DURATION_G, 0x80 | duration);
else
gWriteByte(INT1_DURATION_G, 0x00);
}
*/
void LSM9DS1::calcgRes()
{
// Possible gyro scales (and their register bit settings) are:
// 245 DPS (00), 500 DPS (01), 2000 DPS (10). Here's a bit of an algorithm
// to calculate DPS/(ADC tick) based on that 2-bit value:
uint8_t scale;
switch (gScale)
{
case G_SCALE_245DPS:
scale = 245;
break;
case G_SCALE_500DPS:
scale = 500;
break;
case G_SCALE_2000DPS:
scale = 2000;
break;
}
gRes = (float)(scale) / 32768.0;
}
void LSM9DS1::calcaRes()
{
uint8_t scale;
switch (aScale)
{
case A_SCALE_2G:
scale = 2;
break;
case A_SCALE_4G:
scale = 4;
break;
case A_SCALE_8G:
scale = 8;
break;
case A_SCALE_16G:
scale = 16;
break;
}
aRes = (float)(scale) / 32768.0;
}
void LSM9DS1::calcmRes()
{
// Possible magnetometer scales (and their register bit settings) are:
// 4 Gs (00), 8 Gs (01), 12 Gs (10) 16 Gs (11). Here's a bit of an algorithm
// to calculate Gs/(ADC tick) based on that 2-bit value:
mRes = (float)(4 * (mScale + 1)) / 32768.0;
}
void LSM9DS1::xgWriteByte(uint8_t subAddress, uint8_t data)
{
// Whether we're using I2C or SPI, write a byte using the
// gyro-specific I2C address or SPI CS pin.
if (interfaceMode == MODE_I2C)
I2CwriteByte(xgAddress, subAddress, data);
else if (interfaceMode == MODE_SPI)
SPIwriteByte(xgAddress, subAddress, data);
}
void LSM9DS1::mWriteByte(uint8_t subAddress, uint8_t data)
{
// Whether we're using I2C or SPI, write a byte using the
// accelerometer-specific I2C address or SPI CS pin.
if (interfaceMode == MODE_I2C)
return I2CwriteByte(mAddress, subAddress, data);
else if (interfaceMode == MODE_SPI)
return SPIwriteByte(mAddress, subAddress, data);
}
uint8_t LSM9DS1::xgReadByte(uint8_t subAddress)
{
// Whether we're using I2C or SPI, read a byte using the
// gyro-specific I2C address or SPI CS pin.
if (interfaceMode == MODE_I2C)
return I2CreadByte(xgAddress, subAddress);
else if (interfaceMode == MODE_SPI)
return SPIreadByte(xgAddress, subAddress);
}
void LSM9DS1::xgReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count)
{
// Whether we're using I2C or SPI, read multiple bytes using the
// gyro-specific I2C address or SPI CS pin.
if (interfaceMode == MODE_I2C)
I2CreadBytes(xgAddress, subAddress, dest, count);
else if (interfaceMode == MODE_SPI)
SPIreadBytes(xgAddress, subAddress, dest, count);
}
uint8_t LSM9DS1::mReadByte(uint8_t subAddress)
{
// Whether we're using I2C or SPI, read a byte using the
// accelerometer-specific I2C address or SPI CS pin.
if (interfaceMode == MODE_I2C)
return I2CreadByte(mAddress, subAddress);
else if (interfaceMode == MODE_SPI)
return SPIreadByte(mAddress, subAddress);
}
void LSM9DS1::mReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count)
{
// Whether we're using I2C or SPI, read multiple bytes using the
// accelerometer-specific I2C address or SPI CS pin.
if (interfaceMode == MODE_I2C)
I2CreadBytes(mAddress, subAddress, dest, count);
else if (interfaceMode == MODE_SPI)
SPIreadBytes(mAddress, subAddress, dest, count);
}
void LSM9DS1::initSPI()
{
pinMode(xgAddress, OUTPUT);
digitalWrite(xgAddress, HIGH);
pinMode(mAddress, OUTPUT);
digitalWrite(mAddress, HIGH);
SPI.begin();
// Maximum SPI frequency is 10MHz, could divide by 2 here:
SPI.setClockDivider(SPI_CLOCK_DIV4);
// Data is read and written MSb first.
SPI.setBitOrder(MSBFIRST);
// Data is captured on rising edge of clock (CPHA = 0)
// Base value of the clock is HIGH (CPOL = 1)
SPI.setDataMode(SPI_MODE1);
}
void LSM9DS1::SPIwriteByte(uint8_t csPin, uint8_t subAddress, uint8_t data)
{
digitalWrite(csPin, LOW); // Initiate communication
// If write, bit 0 (MSB) should be 0
// If single write, bit 1 should be 0
SPI.transfer(subAddress & 0x3F); // Send Address
SPI.transfer(data); // Send data
digitalWrite(csPin, HIGH); // Close communication
}
uint8_t LSM9DS1::SPIreadByte(uint8_t csPin, uint8_t subAddress)
{
uint8_t temp;
// Use the multiple read function to read 1 byte.
// Value is returned to `temp`.
SPIreadBytes(csPin, subAddress, &temp, 1);
return temp;
}
void LSM9DS1::SPIreadBytes(uint8_t csPin, uint8_t subAddress,
uint8_t * dest, uint8_t count)
{
digitalWrite(csPin, LOW); // Initiate communication
// To indicate a read, set bit 0 (msb) to 1
// If we're reading multiple bytes, set bit 1 to 1
// The remaining six bytes are the address to be read
if (count > 1)
SPI.transfer(0xC0 | (subAddress & 0x3F));
else
SPI.transfer(0x80 | (subAddress & 0x3F));
for (int i=0; i<count; i++)
{
dest[i] = SPI.transfer(0x00); // Read into destination array
}
digitalWrite(csPin, HIGH); // Close communication
}
void LSM9DS1::initI2C()
{
Wire.begin(); // Initialize I2C library
}
// Wire.h read and write protocols
void LSM9DS1::I2CwriteByte(uint8_t address, uint8_t subAddress, uint8_t data)
{
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.write(data); // Put data in Tx buffer
Wire.endTransmission(); // Send the Tx buffer
}
uint8_t LSM9DS1::I2CreadByte(uint8_t address, uint8_t subAddress)
{
uint8_t data; // `data` will store the register data
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(address, (uint8_t) 1); // Read one byte from slave register address
data = Wire.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
void LSM9DS1::I2CreadBytes(uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t count)
{
Wire.beginTransmission(address); // Initialize the Tx buffer
// Next send the register to be read. OR with 0x80 to indicate multi-read.
Wire.write(subAddress | 0x80); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
uint8_t i = 0;
Wire.requestFrom(address, count); // Read bytes from slave register address
for (int i=0; i<count;)
{
if (Wire.available())
{
dest[i++] = Wire.read();
}
}
/*while (Wire.available())
{
dest[i++] = Wire.read(); // Put read results in the Rx buffer
}*/
}
/******************************************************************************
SFE_LSM9DS1.h
SFE_LSM9DS1 Library Header File
Jim Lindblom @ SparkFun Electronics
Original Creation Date: February 27, 2015
https://github.com/sparkfun/LSM9DS1_Breakout
This file prototypes the LSM9DS1 class, implemented in SFE_LSM9DS1.cpp. In
addition, it defines every register in the LSM9DS1 (both the Gyro and Accel/
Magnetometer registers).
Development environment specifics:
IDE: Arduino 1.6.0
Hardware Platform: Arduino Uno
LSM9DS1 Breakout Version: 1.0
This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!
Distributed as-is; no warranty is given.
******************************************************************************/
#ifndef __SFE_LSM9DS1_H__
#define __SFE_LSM9DS1_H__
#include "application.h"
/////////////////////////////////////////
// LSM9DS1 Accel/Gyro (XL/G) Registers //
/////////////////////////////////////////
#define ACT_THS 0x04
#define ACT_DUR 0x05
#define INT_GEN_CFG_XL 0x06
#define INT_GEN_THS_X_XL 0x07
#define INT_GEN_THS_Y_XL 0x08
#define INT_GEN_THS_Z_XL 0x09
#define INT_GEN_DUR_XL 0x0A
#define REFERENCE_G 0x0B
#define INT1_CTRL 0x0C
#define INT2_CTRL 0x0D
#define WHO_AM_I_XG 0x0F
#define CTRL_REG1_G 0x10
#define CTRL_REG2_G 0x11
#define CTRL_REG3_G 0x12
#define ORIENT_CFG_G 0x13
#define INT_GEN_SRC_G 0x14
#define OUT_TEMP_L 0x15
#define OUT_TEMP_H 0x16
#define STATUS_REG_0 0x17
#define OUT_X_L_G 0x18
#define OUT_X_H_G 0x19
#define OUT_Y_L_G 0x1A
#define OUT_Y_H_G 0x1B
#define OUT_Z_L_G 0x1C
#define OUT_Z_H_G 0x1D
#define CTRL_REG4 0x1E
#define CTRL_REG5_XL 0x1F
#define CTRL_REG6_XL 0x20
#define CTRL_REG7_XL 0x21
#define CTRL_REG8 0x22
#define CTRL_REG9 0x23
#define CTRL_REG10 0x24
#define INT_GEN_SRC_XL 0x26
#define STATUS_REG_1 0x27
#define OUT_X_L_XL 0x28
#define OUT_X_H_XL 0x29
#define OUT_Y_L_XL 0x2A
#define OUT_Y_H_XL 0x2B
#define OUT_Z_L_XL 0x2C
#define OUT_Z_H_XL 0x2D
#define FIFO_CTRL 0x2E
#define FIFO_SRC 0x2F
#define INT_GEN_CFG_G 0x30
#define INT_GEN_THS_XH_G 0x31
#define INT_GEN_THS_XL_G 0x32
#define INT_GEN_THS_YH_G 0x33
#define INT_GEN_THS_YL_G 0x34
#define INT_GEN_THS_ZH_G 0x35
#define INT_GEN_THS_ZL_G 0x36
#define INT_GEN_DUR_G 0x37
///////////////////////////////
// LSM9DS1 Magneto Registers //
///////////////////////////////
#define OFFSET_X_REG_L_M 0x05
#define OFFSET_X_REG_H_M 0x06
#define OFFSET_Y_REG_L_M 0x07
#define OFFSET_Y_REG_H_M 0x08
#define OFFSET_Z_REG_L_M 0x09
#define OFFSET_Z_REG_H_M 0x0A
#define WHO_AM_I_M 0x0F
#define CTRL_REG1_M 0x20
#define CTRL_REG2_M 0x21
#define CTRL_REG3_M 0x22
#define CTRL_REG4_M 0x23
#define CTRL_REG5_M 0x24
#define STATUS_REG_M 0x27
#define OUT_X_L_M 0x28
#define OUT_X_H_M 0x29
#define OUT_Y_L_M 0x2A
#define OUT_Y_H_M 0x2B
#define OUT_Z_L_M 0x2C
#define OUT_Z_H_M 0x2D
#define INT_CFG_M 0x30
#define INT_SRC_M 0x30
#define INT_THS_L_M 0x32
#define INT_THS_H_M 0x33
// The LSM9DS1 functions over both I2C or SPI. This library supports both.
// But the interface mode used must be sent to the LSM9DS1 constructor. Use
// one of these two as the first parameter of the constructor.
enum interface_mode
{
MODE_SPI,
MODE_I2C,
};
// accel_scale defines all possible FSR's of the accelerometer:
enum accel_scale
{
A_SCALE_2G, // 00: 2g
A_SCALE_16G,// 01: 16g
A_SCALE_4G, // 10: 4g
A_SCALE_8G // 11: 8g
};
// gyro_scale defines the possible full-scale ranges of the gyroscope:
enum gyro_scale
{
G_SCALE_245DPS, // 00: 245 degrees per second
G_SCALE_500DPS, // 01: 500 dps
G_SCALE_2000DPS, // 11: 2000 dps
};
// mag_scale defines all possible FSR's of the magnetometer:
enum mag_scale
{
M_SCALE_4GS, // 00: 4Gs
M_SCALE_8GS, // 01: 8Gs
M_SCALE_12GS, // 10: 12Gs
M_SCALE_16GS, // 11: 16Gs
};
// gyro_odr defines all possible data rate/bandwidth combos of the gyro:
enum gyro_odr
{
//! TODO
G_ODR_PD, // Power down (0)
G_ODR_149, // 14.9 Hz (1)
G_ODR_595, // 59.5 Hz (2)
G_ODR_119, // 119 Hz (3)
G_ODR_238, // 238 Hz (4)
G_ODR_476, // 476 Hz (5)
G_ODR_952 // 952 Hz (6)
};
// accel_oder defines all possible output data rates of the accelerometer:
enum accel_odr
{
XL_POWER_DOWN, // Power-down mode (0x0)
XL_ODR_10, // 10 Hz (0x1)
XL_ODR_50, // 50 Hz (0x02)
XL_ODR_119, // 119 Hz (0x3)
XL_ODR_238, // 238 Hz (0x4)
XL_ODR_476, // 476 Hz (0x5)
XL_ODR_952 // 952 Hz (0x6)
};
// accel_abw defines all possible anti-aliasing filter rates of the accelerometer:
enum accel_abw
{
A_ABW_408, // 408 Hz (0x0)
A_ABW_211, // 211 Hz (0x1)
A_ABW_105, // 105 Hz (0x2)
A_ABW_50, // 50 Hz (0x3)
};
// mag_odr defines all possible output data rates of the magnetometer:
enum mag_odr
{
M_ODR_0625, // 0.625 Hz (0)
M_ODR_125, // 1.25 Hz (1)
M_ODR_250, // 2.5 Hz (2)
M_ODR_5, // 5 Hz (3)
M_ODR_10, // 10 Hz (4)
M_ODR_20, // 20 Hz (5)
M_ODR_40, // 40 Hz (6)
M_ODR_80 // 80 Hz (7)
};
enum interrupt_select
{
XG_INT1 = INT1_CTRL,
XG_INT2 = INT2_CTRL
};
enum h_lactive
{
INT_ACTIVE_HIGH,
INT_ACTIVE_LOW
};
enum pp_od
{
INT_PUSH_PULL,
INT_OPEN_DRAIN
};
class LSM9DS1
{
public:
// We'll store the gyro, accel, and magnetometer readings in a series of
// public class variables. Each sensor gets three variables -- one for each
// axis. Call readGyro(), readAccel(), and readMag() first, before using
// these variables!
// These values are the RAW signed 16-bit readings from the sensors.
int16_t gx, gy, gz; // x, y, and z axis readings of the gyroscope
int16_t ax, ay, az; // x, y, and z axis readings of the accelerometer
int16_t mx, my, mz; // x, y, and z axis readings of the magnetometer
int16_t temperature; // Chip temperature
//! TODO: Description
float abias[3];
float gbias[3];
// LSM9DS1 -- LSM9DS1 class constructor
// The constructor will set up a handful of private variables, and set the
// communication mode as well.
// Input:
// - interface = Either MODE_SPI or MODE_I2C, whichever you're using
// to talk to the IC.
// - xgAddr = If MODE_I2C, this is the I2C address of the accel/gyroscope.
// If MODE_SPI, this is the chip select pin of the gyro (CS_AG)
// - mAddr = If MODE_I2C, this is the I2C address of the magnetometer.
// If MODE_SPI, this is the cs pin of the magnetometer (CS_M)
LSM9DS1(interface_mode interface, uint8_t xgAddr, uint8_t mAddr);
LSM9DS1();
void init(interface_mode interface, uint8_t xgAddr, uint8_t mAddr);
// begin() -- Initialize the gyro, accelerometer, and magnetometer.
// This will set up the scale and output rate of each sensor. It'll also
// "turn on" every sensor and every axis of every sensor.
// Input:
// - gScl = The scale of the gyroscope. This should be a gyro_scale value.
// - aScl = The scale of the accelerometer. Should be a accel_scale value.
// - mScl = The scale of the magnetometer. Should be a mag_scale value.
// - gODR = Output data rate of the gyroscope. gyro_odr value.
// - aODR = Output data rate of the accelerometer. accel_odr value.
// - mODR = Output data rate of the magnetometer. mag_odr value.
// Output: The function will return an unsigned 16-bit value. The most-sig
// bytes of the output are the WHO_AM_I reading of the accel. The
// least significant two bytes are the WHO_AM_I reading of the gyro.
// All parameters have a defaulted value, so you can call just "begin()".
// Default values are FSR's of: 245DPS, 2g, 2Gs; ODRs of 95 Hz for
// gyro, 100 Hz for accelerometer, 100 Hz for magnetometer.
// Use the return value of this function to verify communication.
uint16_t begin(gyro_scale gScl = G_SCALE_245DPS,
accel_scale aScl = A_SCALE_2G, mag_scale mScl = M_SCALE_4GS,
gyro_odr gODR = G_ODR_952, accel_odr aODR = XL_ODR_50,
mag_odr mODR = M_ODR_80);
// readGyro() -- Read the gyroscope output registers.
// This function will read all six gyroscope output registers.
// The readings are stored in the class' gx, gy, and gz variables. Read
// those _after_ calling readGyro().
void readGyro();
// readAccel() -- Read the accelerometer output registers.
// This function will read all six accelerometer output registers.
// The readings are stored in the class' ax, ay, and az variables. Read
// those _after_ calling readAccel().
void readAccel();
// readMag() -- Read the magnetometer output registers.
// This function will read all six magnetometer output registers.
// The readings are stored in the class' mx, my, and mz variables. Read
// those _after_ calling readMag().
void readMag();
// readTemp() -- Read the temperature output register.
// This function will read two temperature output registers.
// The combined readings are stored in the class' temperature variables. Read
// those _after_ calling readTemp().
void readTemp();
// calcGyro() -- Convert from RAW signed 16-bit value to degrees per second
// This function reads in a signed 16-bit value and returns the scaled
// DPS. This function relies on gScale and gRes being correct.
// Input:
// - gyro = A signed 16-bit raw reading from the gyroscope.
float calcGyro(int16_t gyro);
// calcAccel() -- Convert from RAW signed 16-bit value to gravity (g's).
// This function reads in a signed 16-bit value and returns the scaled
// g's. This function relies on aScale and aRes being correct.
// Input:
// - accel = A signed 16-bit raw reading from the accelerometer.
float calcAccel(int16_t accel);
// calcMag() -- Convert from RAW signed 16-bit value to Gauss (Gs)
// This function reads in a signed 16-bit value and returns the scaled
// Gs. This function relies on mScale and mRes being correct.
// Input:
// - mag = A signed 16-bit raw reading from the magnetometer.
float calcMag(int16_t mag);
// setGyroScale() -- Set the full-scale range of the gyroscope.
// This function can be called to set the scale of the gyroscope to
// 245, 500, or 200 degrees per second.
// Input:
// - gScl = The desired gyroscope scale. Must be one of three possible
// values from the gyro_scale enum.
void setGyroScale(gyro_scale gScl);
// setAccelScale() -- Set the full-scale range of the accelerometer.
// This function can be called to set the scale of the accelerometer to
// 2, 4, 6, 8, or 16 g's.
// Input:
// - aScl = The desired accelerometer scale. Must be one of five possible
// values from the accel_scale enum.
void setAccelScale(accel_scale aScl);
// setMagScale() -- Set the full-scale range of the magnetometer.
// This function can be called to set the scale of the magnetometer to
// 2, 4, 8, or 12 Gs.
// Input:
// - mScl = The desired magnetometer scale. Must be one of four possible
// values from the mag_scale enum.
void setMagScale(mag_scale mScl);
// setGyroODR() -- Set the output data rate and bandwidth of the gyroscope
// Input:
// - gRate = The desired output rate and cutoff frequency of the gyro.
// Must be a value from the gyro_odr enum (check above, there're 14).
void setGyroODR(gyro_odr gRate);
// setAccelODR() -- Set the output data rate of the accelerometer
// Input:
// - aRate = The desired output rate of the accel.
// Must be a value from the accel_odr enum (check above, there're 11).
void setAccelODR(accel_odr aRate);
// setAccelABW() -- Set the anti-aliasing filter rate of the accelerometer
// Input:
// - abwRate = The desired anti-aliasing filter rate of the accel.
// Must be a value from the accel_abw enum (check above, there're 4).
void setAccelABW(accel_abw abwRate);
// setMagODR() -- Set the output data rate of the magnetometer
// Input:
// - mRate = The desired output rate of the mag.
// Must be a value from the mag_odr enum (check above, there're 6).
void setMagODR(mag_odr mRate);
// configGyroInt() -- Configure the gyro interrupt output.
// Triggers can be set to either rising above or falling below a specified
// threshold. This function helps setup the interrupt configuration and
// threshold values for all axes.
// Input:
// - int1Cfg = A 8-bit value that is sent directly to the INT1_CFG_G
// register. This sets AND/OR and high/low interrupt gen for each axis
// - int1ThsX = 16-bit interrupt threshold value for x-axis
// - int1ThsY = 16-bit interrupt threshold value for y-axis
// - int1ThsZ = 16-bit interrupt threshold value for z-axis
// - duration = Duration an interrupt holds after triggered. This value
// is copied directly into the INT1_DURATION_G register.
// Before using this function, read about the INT1_CFG_G register and
// the related INT1* registers in the LMS9DS0 datasheet.
void configGyroInt(uint8_t int1Cfg, uint16_t int1ThsX = 0,
uint16_t int1ThsY = 0, uint16_t int1ThsZ = 0,
uint8_t duration = 0);
//! TODO: Description
void calLSM9DS1(float gbias[3], float abias[3]);
void configAccelIntTHS(interrupt_select intSelect = XG_INT1, uint8_t ths_x_xl = 0,
uint8_t ths_y_xl = 0, uint8_t ths_z_xl = 0);
void configAccelIntDRDY(interrupt_select intSelect = XG_INT1, bool enable = true);
void configGyroIntDRDY(interrupt_select intSelect = XG_INT2, bool enable = true);
void configMagIntTHS(int threshold = 0,
bool xien = false, bool yien = false, bool zien = false);
void configAGInterrupt(h_lactive activeLow, pp_od pushPull);
void configMInterrupt(h_lactive activeLow);
uint8_t getMagIntSrc();
protected:
// xmAddress and gAddress store the I2C address or SPI chip select pin
// for each sensor.
uint8_t mAddress, xgAddress;
// interfaceMode keeps track of whether we're using SPI or I2C to talk
interface_mode interfaceMode;
// gScale, aScale, and mScale store the current scale range for each
// sensor. Should be updated whenever that value changes.
gyro_scale gScale;
accel_scale aScale;
mag_scale mScale;
// gRes, aRes, and mRes store the current resolution for each sensor.
// Units of these values would be DPS (or g's or Gs's) per ADC tick.
// This value is calculated as (sensor scale) / (2^15).
float gRes, aRes, mRes;
// initGyro() -- Sets up the gyroscope to begin reading.
// This function steps through all five gyroscope control registers.
// Upon exit, the following parameters will be set:
// - CTRL_REG1_G = 0x0F: Normal operation mode, all axes enabled.
// 95 Hz ODR, 12.5 Hz cutoff frequency.
// - CTRL_REG2_G = 0x00: HPF set to normal mode, cutoff frequency
// set to 7.2 Hz (depends on ODR).
// - CTRL_REG3_G = 0x88: Interrupt enabled on INT_G (set to push-pull and
// active high). Data-ready output enabled on DRDY_G.
// - CTRL_REG4_G = 0x00: Continuous update mode. Data LSB stored in lower
// address. Scale set to 245 DPS. SPI mode set to 4-wire.
// - CTRL_REG5_G = 0x00: FIFO disabled. HPF disabled.
void initGyro();
// initAccel() -- Sets up the accelerometer to begin reading.
// This function steps through all accelerometer related control registers.
// Upon exit these registers will be set as:
// - CTRL_REG0_XM = 0x00: FIFO disabled. HPF bypassed. Normal mode.
// - CTRL_REG1_XM = 0x57: 100 Hz data rate. Continuous update.
// all axes enabled.
// - CTRL_REG2_XM = 0x00: 2g scale. 773 Hz anti-alias filter BW.
// - CTRL_REG3_XM = 0x04: Accel data ready signal on INT1_XM pin.
void initAccel();
// initMag() -- Sets up the magnetometer to begin reading.
// This function steps through all magnetometer-related control registers.
// Upon exit these registers will be set as:
// - CTRL_REG4_XM = 0x04: Mag data ready signal on INT2_XM pin.
// - CTRL_REG5_XM = 0x14: 100 Hz update rate. Low resolution. Interrupt
// requests don't latch. Temperature sensor disabled.
// - CTRL_REG6_XM = 0x00: 2 Gs scale.
// - CTRL_REG7_XM = 0x00: Continuous conversion mode. Normal HPF mode.
// - INT_CTRL_REG_M = 0x09: Interrupt active-high. Enable interrupts.
void initMag();
// gReadByte() -- Reads a byte from a specified gyroscope register.
// Input:
// - subAddress = Register to be read from.
// Output:
// - An 8-bit value read from the requested address.
uint8_t mReadByte(uint8_t subAddress);
// gReadBytes() -- Reads a number of bytes -- beginning at an address
// and incrementing from there -- from the gyroscope.
// Input:
// - subAddress = Register to be read from.
// - * dest = A pointer to an array of uint8_t's. Values read will be
// stored in here on return.
// - count = The number of bytes to be read.
// Output: No value is returned, but the `dest` array will store
// the data read upon exit.
void mReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count);
// gWriteByte() -- Write a byte to a register in the gyroscope.
// Input:
// - subAddress = Register to be written to.
// - data = data to be written to the register.
void mWriteByte(uint8_t subAddress, uint8_t data);
// xmReadByte() -- Read a byte from a register in the accel/mag sensor
// Input:
// - subAddress = Register to be read from.
// Output:
// - An 8-bit value read from the requested register.
uint8_t xgReadByte(uint8_t subAddress);
// xmReadBytes() -- Reads a number of bytes -- beginning at an address
// and incrementing from there -- from the accelerometer/magnetometer.
// Input:
// - subAddress = Register to be read from.
// - * dest = A pointer to an array of uint8_t's. Values read will be
// stored in here on return.
// - count = The number of bytes to be read.
// Output: No value is returned, but the `dest` array will store
// the data read upon exit.
void xgReadBytes(uint8_t subAddress, uint8_t * dest, uint8_t count);
// xmWriteByte() -- Write a byte to a register in the accel/mag sensor.
// Input:
// - subAddress = Register to be written to.
// - data = data to be written to the register.
void xgWriteByte(uint8_t subAddress, uint8_t data);
// calcgRes() -- Calculate the resolution of the gyroscope.
// This function will set the value of the gRes variable. gScale must
// be set prior to calling this function.
void calcgRes();
// calcmRes() -- Calculate the resolution of the magnetometer.
// This function will set the value of the mRes variable. mScale must
// be set prior to calling this function.
void calcmRes();
// calcaRes() -- Calculate the resolution of the accelerometer.
// This function will set the value of the aRes variable. aScale must
// be set prior to calling this function.
void calcaRes();
///////////////////
// SPI Functions //
///////////////////
// initSPI() -- Initialize the SPI hardware.
// This function will setup all SPI pins and related hardware.
void initSPI();
// SPIwriteByte() -- Write a byte out of SPI to a register in the device
// Input:
// - csPin = The chip select pin of the slave device.
// - subAddress = The register to be written to.
// - data = Byte to be written to the register.
void SPIwriteByte(uint8_t csPin, uint8_t subAddress, uint8_t data);
// SPIreadByte() -- Read a single byte from a register over SPI.
// Input:
// - csPin = The chip select pin of the slave device.
// - subAddress = The register to be read from.
// Output:
// - The byte read from the requested address.
uint8_t SPIreadByte(uint8_t csPin, uint8_t subAddress);
// SPIreadBytes() -- Read a series of bytes, starting at a register via SPI
// Input:
// - csPin = The chip select pin of a slave device.
// - subAddress = The register to begin reading.
// - * dest = Pointer to an array where we'll store the readings.
// - count = Number of registers to be read.
// Output: No value is returned by the function, but the registers read are
// all stored in the *dest array given.
void SPIreadBytes(uint8_t csPin, uint8_t subAddress,
uint8_t * dest, uint8_t count);
///////////////////
// I2C Functions //
///////////////////
// initI2C() -- Initialize the I2C hardware.
// This function will setup all I2C pins and related hardware.
void initI2C();
// I2CwriteByte() -- Write a byte out of I2C to a register in the device
// Input:
// - address = The 7-bit I2C address of the slave device.
// - subAddress = The register to be written to.
// - data = Byte to be written to the register.
void I2CwriteByte(uint8_t address, uint8_t subAddress, uint8_t data);
// I2CreadByte() -- Read a single byte from a register over I2C.
// Input:
// - address = The 7-bit I2C address of the slave device.
// - subAddress = The register to be read from.
// Output:
// - The byte read from the requested address.
uint8_t I2CreadByte(uint8_t address, uint8_t subAddress);
// I2CreadBytes() -- Read a series of bytes, starting at a register via SPI
// Input:
// - address = The 7-bit I2C address of the slave device.
// - subAddress = The register to begin reading.
// - * dest = Pointer to an array where we'll store the readings.
// - count = Number of registers to be read.
// Output: No value is returned by the function, but the registers read are
// all stored in the *dest array given.
void I2CreadBytes(uint8_t address, uint8_t subAddress, uint8_t * dest, uint8_t count);
};
#endif // SFE_LSM9DS1_H //
@z1s2u
Copy link

z1s2u commented Feb 15, 2017

Is there application.h code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment