Skip to content

Ozonised/LSM6DSL-Platform-Independent-Library

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LSM6DSL library for STM32, PICs, AVR

This is a platform independent I2C library for LSM6DSL 6 axis imu. The LSM6DSL is a 3D digital accelerometer and 3D digital gyroscope system-in-package with a digital I2C/SPI serial interface standard output, performing at 0.65 mA in combo High-Performance mode. The device has a dynamic user-selectable full-scale acceleration range of ±2/±4/±8/±16 g and an angular rate range of ±125/±250/±500/±1000/±2000 dps.

Supported Features:

  • Checking for device presence.
  • Setting endianess for output registers.
  • Setting output data rate and full scale range for accelerometer and gyroscope.
  • Enabling accelerometer and gyroscope high performance mode.
  • Reading accelerometer, gyroscope and temperature data.
  • Performing gyroscope and accelerometer self test.
  • Configuring accelerometer's digital high pass and low pass filters.
  • Configuring interrupts for INT1 and INT2 pins.
  • Setting block updata mode.

Note:

Refer to lsm6dsl.h or lsm6dsl.hpp for all the implemented features.


Do I use it with my favourite microcontroller?

To use it with your favourite microcontroller, you simply need to define the 3 functions declared in lsm6dsl_port.h (for C) or create read, write and delay functions based on the function pointer syntax in lsm6dsl.hpp (for C++).

The functions for C are:

  1. LSM6DSL_INTF_RET_TYPE LSM6DSL_PortI2CReadReg(void *hinterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len) : function to read the device registers.
  2. LSM6DSL_INTF_RET_TYPE LSM6DSL_PortI2CWriteReg(void *hinterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len) : function to write to device registers.
  3. void LSM6DSL_PortDelayMs(void *hinterface, uint32_t ms) : function to delay in milliseconds.

The function syntax for C++ are:

  1. LSM6DSL_INTF_RET_TYPE FunctionToRead(void *hInterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len) : function to read the device registers.
  2. LSM6DSL_INTF_RET_TYPE FunctionToWrite (void *hInterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len) : function to write to device registers.
  3. void delay(uint32_t ms) : function to delay in milliseconds.

Don't worry, I will show you an example.

Porting to Arduino Framework:

To use the library with the arduino framwork, inlude the .hpp and .cpp files from LSM6DSL_CPP into your project. Now, create read, write and delay functions as shown below:

Note:

I am using I2C interface.

LSM6DSL_INTF_RET_TYPE LSM6DSL_I2C_Read(void *hInterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len) {
  TwoWire *i2c = static_cast<TwoWire*>(hInterface);
  uint8_t i = 0;
  i2c->beginTransmission(chipAddr);
  i2c->write(RegAddr);
  if (i2c->endTransmission() != 0) return LSM6DSL_INTF_RET_TYPE_FAILURE;

  i2c->requestFrom(chipAddr, len);
  while (i < len) {
    if (i2c->available()) {
      buf[i++] = i2c->read();
    }
  }
  return LSM6DSL_INTF_RET_TYPE_SUCCESS;
}

LSM6DSL_INTF_RET_TYPE LSM6DSL_I2C_Write(void *hInterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len) {
  TwoWire *i2c = static_cast<TwoWire*>(hInterface);
  uint8_t i = 0;
  i2c->beginTransmission(chipAddr);
  i2c->write(RegAddr);
  while (i < len) {
    i2c->write(buf[i++]);
  }
  if (i2c->endTransmission() != 0) return LSM6DSL_INTF_RET_TYPE_FAILURE;
  return LSM6DSL_INTF_RET_TYPE_SUCCESS;
}

Porting to STM32 using ST HAL framework:

To use use the library with ST HAL's framework, include the files from LSM6DSL_C into your project Now in the main file, create the definitions for the functions in lsm6dsl_port.h as shown below:

LSM6DSL_INTF_RET_TYPE LSM6DSL_PortI2CReadReg(void *hinterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len)
{
	I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef*) hinterface;
	return HAL_I2C_Mem_Read(hi2c, chipAddr << 1, RegAddr, I2C_MEMADD_SIZE_8BIT, buf, len, 50);
}

LSM6DSL_INTF_RET_TYPE LSM6DSL_PortI2CWriteReg(void *hinterface, uint8_t chipAddr, uint8_t RegAddr, uint8_t *buf, uint16_t len)
{
	I2C_HandleTypeDef *hi2c = (I2C_HandleTypeDef*) hinterface;
	return HAL_I2C_Mem_Write(hi2c, chipAddr << 1, RegAddr, I2C_MEMADD_SIZE_8BIT, buf, len, 50);
}

void LSM6DSL_PortDelayMs(void *hinterface, uint32_t ms)
{
	(void) hinterface;
	HAL_Delay(ms);
}

Examples:

Not all the features of this library is discussed in the example, but enough to get you started.

1. Read accelerometer and gyroscope data

C

#include "lsm6dsl.h"

#define LSM6DSL_ADDR 0x6A
LSM6DSL imu; // create LSM6DSL object
LSM6DSL_AccelRawData accelRaw; 		// object to hold accelerometer's raw data
LSM6DSL_GyroRawData gyroRaw;	 	// object to hold gyroscope's raw data
	.
	.
	.
wait(20); 						// delay for 20 ms as the imu performs a 15ms boot up procedure
LSM6DSL_Init(&imu, (void *) &i2cHandle, LSM6DSL_ADDR);	// initialise the struct
LSM6DSL_setAccelFSRange(&imu, LSM6DSL_XL_FS_4G);	// set the accelerometer full scale range
LSM6DSL_setAccelODR(&imu, LSM6DSL_XL_ODR_416Hz);	// set the accelerometer output data rate
LSM6DSL_setGyroFSRange(&imu, LSM6DSL_G_FS_500DPS);	// set the gyroscope full scale range
LSM6DSL_setGyroODR(&imu, LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
	.
	.
	.
if (LSM6DSL_isAccelDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	LSM6DSL_readAccelData(&imu, &accelRaw);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
}

if (LSM6DSL_isGyroDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	LSM6DSL_readGyroData(&imu, &gyroRaw);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
}

CPP

#include "lsm6dsl.hpp"

LSM6DSL imu(static_cast<void*>(&hI2Chandle), LSM6DSL_I2C_Read, LSM6DSL_I2C_Write, delay);
LSM6DSL_AccelRawData xl;					// object to hold accelerometer's raw data
LSM6DSL_GyroRawData gy;						// object to hold gyroscope's raw data
	.
	.
	.
imu.setI2CAddress(0);
delay(20);									// delay for 20 ms as the imu performs a 15ms boot up procedure
imu.setAccelFSRange(LSM6DSL_XL_FS_4G);		// set the accelerometer full scale range
imu.setAccelODR(LSM6DSL_XL_ODR_416Hz);		// set the accelerometer output data rate
imu.setGyroFSRange(LSM6DSL_G_FS_1000DPS);	// set the gyroscope full scale range
imu.setGyroODR(LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
	.
	.
	.
if (imu.isAccelDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readAccelData(&xl);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
}

if (imu.isGyroDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readGyroData(&gy);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
}

Note:

To convert the gyroscope and accelerometer raw values into degrees per second (dps) and meters per second squared (m/s^2), use the following two functions:

  1. float convertGyroRawDataToDPS(int16_t axisN, LSM6DSL_G_FS_Range r); : convert raw gyroscope value into dps
  2. float convertAccelRawDataTomS2(int16_t axisN, LSM6DSL_XL_FS_Range r); : convert raw accelerometer value in m/s^2
float accelX, accelY, accelZ, gyroX, gyroY, gyroZ;

accelX = convertAccelRawDataTomS2(xl.x, LSM6DSL_XL_FS_4G);
accelY = convertAccelRawDataTomS2(xl.y, LSM6DSL_XL_FS_4G);
accelZ = convertAccelRawDataTomS2(xl.z, LSM6DSL_XL_FS_4G);

gyroX = convertGyroRawDataToDPS(gy.x, LSM6DSL_G_FS_1000DPS);
gyroY = convertGyroRawDataToDPS(gy.y, LSM6DSL_G_FS_1000DPS);
gyroZ = convertGyroRawDataToDPS(gy.z, LSM6DSL_G_FS_1000DPS);

2. Read temperature data

To activate the temperature, either the accelerometer, gyroscope, or both must be enabled. Refer to section 9 of the application note AN5040 for output data rate (max 52Hz).

C

#include "lsm6dsl.h"

#define LSM6DSL_ADDR 0x6A
LSM6DSL imu; // create LSM6DSL object
LSM6DSL_TempData t;	// object to hold temperature data
	.
	.
	.
wait(20); 						// delay for 20 ms as the imu performs a 15ms boot up procedure
LSM6DSL_Init(&imu, (void *) &i2cHandle, LSM6DSL_ADDR);	// initialise the struct
LSM6DSL_setAccelFSRange(&imu, LSM6DSL_XL_FS_4G);	// set the accelerometer full scale range
LSM6DSL_setAccelODR(&imu, LSM6DSL_XL_ODR_416Hz);	// set the accelerometer output data rate
	.
	.
	.
if (LSM6DSL_isTempDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	LSM6DSL_readTemperature(&imu, &t);
	printf("Raw data: %d, Celsius: %f\n", t.regData, t.celsius);
}

CPP

#include "lsm6dsl.hpp"
	.
	.
	.
LSM6DSL imu(static_cast<void*>(&hI2Chandle), LSM6DSL_I2C_Read, LSM6DSL_I2C_Write, delay);
LSM6DSL_TempData t;	// object to hold temperature data
	.
	.
	.
imu.setI2CAddress(0);
delay(20);									// delay for 20 ms as the imu performs a 15ms boot up procedure
imu.setAccelFSRange(LSM6DSL_XL_FS_4G);		// set the accelerometer full scale range
imu.setAccelODR(LSM6DSL_XL_ODR_416Hz);		// set the accelerometer output data rate
	.
	.
	.
if (imu.isTempDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readTemperature(&t);
	printf("Raw data: %d, Celsius: %f\n", t.regData, t.celsius);
}

3. Perform self test

The device must be kept steady during the self test procedure.

C

#include "lsm6dsl.h"

#define LSM6DSL_ADDR 0x6A
LSM6DSL imu; // create LSM6DSL object
LSM6DSL_AccelData accelRaw; // object to hold accelerometer's raw data
LSM6DSL_GyroData gyroRaw;	 // object to hold gyroscope's raw data
	.
	.
	.
wait(20); 						// delay for 20 ms as the imu performs a 15ms boot up procedure
LSM6DSL_Init(&imu, (void *) &i2cHandle, LSM6DSL_ADDR);	// initialise the struct

uint8_t xlStState, gyStState;
xlStState = LSM6DSL_selfTestAccel(&imu);
gyStState = LSM6DSL_selfTestGyro(&imu);
	.
	.
LSM6DSL_setAccelFSRange(&imu, LSM6DSL_XL_FS_4G);	// set the accelerometer full scale range
LSM6DSL_setAccelODR(&imu, LSM6DSL_XL_ODR_416Hz);	// set the accelerometer output data rate
LSM6DSL_setGyroFSRange(&imu, LSM6DSL_G_FS_500DPS);	// set the gyroscope full scale range
LSM6DSL_setGyroODR(&imu, LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
	.
	.
	.
if (xlStState == LSM6DSL_INTF_RET_TYPE_SUCCESS && LSM6DSL_isAccelDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	LSM6DSL_readAccelData(&imu, &accelRaw);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
}

if (gyStState == LSM6DSL_INTF_RET_TYPE_SUCCESS && LSM6DSL_isGyroDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	LSM6DSL_readGyroData(&imu, &gyro);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
}

CPP

#include "lsm6dsl.hpp"
	.
	.
	.
LSM6DSL imu(static_cast<void*>(&hI2Chandle), LSM6DSL_I2C_Read, LSM6DSL_I2C_Write, delay);
LSM6DSL_AccelRawData xl;					// object to hold accelerometer's raw data
LSM6DSL_GyroRawData gy;						// object to hold gyroscope's raw data
	.
	.
	.
imu.setI2CAddress(0);
delay(20);									// delay for 20 ms as the imu performs a 15ms boot up procedure
uint8_t xlStState, gyStState;
xlStState = imu.selfTestAccel();
gyStState = imu.selfTestGyro();
	.
	.
	.
imu.setAccelFSRange(LSM6DSL_XL_FS_4G);		// set the accelerometer full scale range
imu.setAccelODR(LSM6DSL_XL_ODR_416Hz);		// set the accelerometer output data rate
imu.setGyroFSRange(LSM6DSL_G_FS_1000DPS);	// set the gyroscope full scale range
imu.setGyroODR(LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
	.
	.
	.
if (xlStState == LSM6DSL_INTF_RET_TYPE_SUCCESS && imu.isAccelDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readAccelData(&xl);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
}

if (gyStState == LSM6DSL_INTF_RET_TYPE_SUCCESS && imu.isGyroDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readGyroData(&gy);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
}

4. Reading data with Interrupt

Generate interrupt on INT1 pin when accelerometer or gyroscope data is ready.

C

#include "lsm6dsl.h"

#define LSM6DSL_ADDR 0x6A
LSM6DSL imu; // create LSM6DSL object
LSM6DSL_AccelRawData accelRaw; 		// object to hold accelerometer's raw data
LSM6DSL_GyroRawData gyroRaw;	 	// object to hold gyroscope's raw data
	.
volatile bool imuDataReady = false;
	.
	.
	.
wait(20); 						// delay for 20 ms as the imu performs a 15ms boot up procedure
LSM6DSL_Init(&imu, (void *) &i2cHandle, LSM6DSL_ADDR);	// initialise the struct
LSM6DSL_setAccelFSRange(&imu, LSM6DSL_XL_FS_4G);	// set the accelerometer full scale range
LSM6DSL_setGyroFSRange(&imu, LSM6DSL_G_FS_500DPS);	// set the gyroscope full scale range
LSM6DSL_INT1SourceConfig(&imu, LSM6DSL_INT1_DRDY_XL | LSM6DSL_INT1_DRDY_G); // accelerometer and gyroscope data ready interrupt on INT1 pin
LSM6DSL_setAccelODR(&imu, LSM6DSL_XL_ODR_416Hz);	// set the accelerometer output data rate
LSM6DSL_setGyroODR(&imu, LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
	.
	.
	.
if (LSM6DSL_isAccelDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS && LSM6DSL_isGyroDataAvailabe(&imu) == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imuDataReady = false;
	LSM6DSL_readAccelData(&imu, &accelRaw);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
	LSM6DSL_readGyroData(&imu, &gyroRaw);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
}
	.
	.
	.
void imuInterruptHandler(void)
{
	imuDataReady = true;
}

Note:

LSM6DSL has 2 interrupts pin INT1 and INT2, whose interrupt souce can be configured through LSM6DSL_INTF_RET_TYPE LSM6DSL_INT1SourceConfig(LSM6DSL *dev, enum LSM6DSL_INT1_Sources s) and LSM6DSL_INTF_RET_TYPE LSM6DSL_INT2SourceConfig(LSM6DSL *dev, enum LSM6DSL_INT2_Sources s) respectively. By default, some interrupt sources are exclusive to INT2 pin. These sources can be mappeded to INT1 pin through LSM6DSL_INTF_RET_TYPE LSM6DSL_setAllIRQonINT1(LSM6DSL *dev, uint8_t en).

CPP

#include "lsm6dsl.hpp"

LSM6DSL imu(static_cast<void*>(&hI2Chandle), LSM6DSL_I2C_Read, LSM6DSL_I2C_Write, delay);
LSM6DSL_AccelRawData xl;					// object to hold accelerometer's raw data
LSM6DSL_GyroRawData gy;						// object to hold gyroscope's raw data
	.
volatile bool imuDataReady = false;
	.
	.
	.
imu.setI2CAddress(0);
delay(20);									// delay for 20 ms as the imu performs a 15ms boot up procedure
imu.setAccelFSRange(LSM6DSL_XL_FS_4G);		// set the accelerometer full scale range
imu.setGyroFSRange(LSM6DSL_G_FS_1000DPS);	// set the gyroscope full scale range
imu.INT1SourceConfig(static_cast<LSM6DSL_INT1_Sources>(LSM6DSL_INT1_DRDY_XL | LSM6DSL_INT1_DRDY_G)); // accelerometer and gyroscope data ready interrupt on INT1 pin
imu.setGyroODR(LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
imu.setAccelODR(LSM6DSL_XL_ODR_416Hz);		// set the accelerometer output data rate
	.
	.
	.
if (imuDataReady == true && imu.isAccelDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS && imu.isGyroDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readAccelData(&xl);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
	imu.readGyroData(&gy);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
	imuDataReady = false;
}
	.
	.
	.
void imuInterruptHandler(void)
{
	imuDataReady = true;
}

Note:

LSM6DSL has 2 interrupts pin INT1 and INT2, whose interrupt souce can be configured through LSM6DSL_INTF_RET_TYPE INT1SourceConfig(LSM6DSL_INT1_Sources s) and LSM6DSL_INTF_RET_TYPE INT2SourceConfig(LSM6DSL_INT2_Sources s) respectively. By default, some interrupt sources are exclusive to INT2 pin. These sources can be mappeded to INT1 pin through LSM6DSL_INTF_RET_TYPE setAllIRQonINT1(uint8_t en).

5. Using builtin low and high pass digital filters

The LSM6DSL imu offers builtin in digital high pass and low pass filter for the accelerometer and high pass filter for the gyroscope. In this example, we will be utilising the accelerometer's low pass filter to reduce noise due to vibrations, and gyroscope's high pass filter to reduce gyro drift to an extent.

CPP

#include "lsm6dsl.hpp"

LSM6DSL imu(static_cast<void*>(&hI2Chandle), LSM6DSL_I2C_Read, LSM6DSL_I2C_Write, delay);
LSM6DSL_AccelRawData xl;					// object to hold accelerometer's raw data
LSM6DSL_GyroRawData gy;						// object to hold gyroscope's raw data
	.
volatile bool imuDataReady = false;
	.
	.
	.
imu.setI2CAddress(0);
delay(20);									// delay for 20 ms as the imu performs a 15ms boot up procedure
imu.setAccelFSRange(LSM6DSL_XL_FS_4G);		// set the accelerometer full scale range
imu.setGyroFSRange(LSM6DSL_G_FS_1000DPS);	// set the gyroscope full scale range
imu.configGyroHPF(LSM6DSL_G_HPF_BW_0_260Hz); // gyroscope high pass fitler cut off set to 0.26HZ
imu.configAccelDigitalLPF(LSM6DSL_XL_LPF_BW_ODR_9, 1); // accelerometer low pass filter bandwidth set to: aODR / 9 (here accelerometer ODR = 416) -> 416Hz/9 = 46Hz (approx).
imu.INT1SourceConfig(static_cast<LSM6DSL_INT1_Sources>(LSM6DSL_INT1_DRDY_XL | LSM6DSL_INT1_DRDY_G)); // accelerometer and gyroscope data ready interrupt on INT1 pin
imu.setGyroODR(LSM6DSL_G_ODR_416Hz);		// set the gyroscope output data rate
imu.setAccelODR(LSM6DSL_XL_ODR_416Hz);		// set the accelerometer output data rate
	.
	.
	.
if (imuDataReady == true && imu.isAccelDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS && imu.isGyroDataAvailabe() == LSM6DSL_INTF_RET_TYPE_SUCCESS)
{
	imu.readAccelData(&xl);
	printf("%d,%d,%d\n", accelRaw.x, accelRaw.y, accelRaw.z);
	imu.readGyroData(&gy);
	printf("%d,%d,%d\n", gyroRaw.x, gyroRaw.y, gyroRaw.z);
	imuDataReady = false;
}
	.
	.
	.
void imuInterruptHandler(void)
{
	imuDataReady = true;
}

About

A platform independent C & C++ I2C library for LSM6DSL 6 axis imu

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors