MEMS sensor drivers and tilt-compensated compass using the STEVAL-MKI124V1 header board: LPS331 pressure sensor, LSM303DLHC magnetometer/accelerometer and L3GD20 gyroscope.

Dependencies:   mbed

I used a header board for an STM MEMS evaluation kit in order to take a look at some common MEMS sensors:

  • LPS301: Pressure and temperature sensor
  • LG3D20: Gyroscope
  • LSM303DLHC: Accelerometer and magnetometer

The header was an STEVAL-MKI124V1 which is designed to work with an STM motherboard evaluation system. I took a shortcut and used it with an LPC1768 MBED over I2C

Hook-up was trivial:


The schematic is here:

The orientation of the sensors on the board is like this:


The code sets up each of the sensors and then provides a continuous output of temperature, pressure and orientation. Rather than optimize for performance or efficiency, the code here is intended to show clearly how to access the sensors.

An interesting twist was to use the linear accelerometer to find the vector of the earth's gravitational field (i.e. down) and to use that to make a tilt-adjusted compass. Algorithm came from ST Apps note AN3192.

The sensors do need some calibration. Here is a scatter plot of the raw output of X and Y values from the magnetometer:


The chart should be a perfect circle around the origin (allowing for distortion on Excel charting).

  • Blue points are the raw data
  • Red is offset-corrected
  • Green is offset and soft-iron corrected

As you can see, there is an offset error but also and X:Y ratio term. The latter is a soft iron error and is well described in a great article here:

--- a/main.cpp	Tue Mar 18 05:22:01 2014 +0000
+++ b/main.cpp	Tue Mar 18 16:48:10 2014 +0000
@@ -6,6 +6,10 @@
 // Developed on an LPC1768
 // By Liam Goudge. March 2014
+#define LSM303_on
+#define L3GD20_on
+#define LPS301_on
 #include "mbed.h"
 #include "MKI124V1.h"
 #include "math.h"
@@ -56,6 +60,7 @@
     pc.printf("\nSTM MEMS eval board sensor init \n");
+#ifdef LSM303_on
     // LSM303DLHC Magnetic sensor
     pc.printf("LSM303DLHC ping (should reply 0x48): %x \n",readByte(LSM303_m,mIRA_REG_M));
     writeByte(LSM303_m,mCRA_REG_M,0x94);     //switch on temperature sensor and set Output Data Rate to 30Hz
@@ -65,17 +70,22 @@
     // LSM303DLHC Accelerometer
     writeByte(LSM303_a,aCTRL_REG1_A ,0x37); // Set 25Hz ODR, everything else on
     writeByte(LSM303_a,aCTRL_REG4_A ,0x08); // Set full scale to +/- 2g sensitivity and high rez mode
+#ifdef LPS331
     // LPS331 Pressure sensor
     pc.printf("LPS331 ping (should reply 0xBB): %x \n",readByte(LPS331addr,pWHO_AM_I));
     writeByte(LPS331addr,pCTRL_REG1,0x90);  // Switch on pressure sensor and select 1Hz ODR. If you select one-shot then sensor powers itself down after every reading...
     writeByte(LPS331addr,pRES_CONF,0x70);   // Temp and pressure noise reduction. Sets # of internal measurements that are averaged to 1 reading. Default is 0x7A (temp rez=128, press=512)
+#ifdef L3GD20
     // L3GD20 gyro
     printf("Ping L3GD20 (should reply 0xD4): %x \n",readByte(L3GD20_ADDR,gWHO_AM_I));
     writeByte(L3GD20_ADDR,gCTRL_REG1,0x0F); // Set ODR to 95Hz, BW to 12.5Hz, enable axes and turn on device
     writeByte(L3GD20_ADDR,gCTRL_REG4,0x10); // Full scale selected at 500dps (degrees per second)
     printf("L3GD20 gyro Temp: %x degrees C \n",readByte(L3GD20_ADDR,gOUT_TEMP));
     pc.printf("--------------------------------------\n \n");
     wait(1); // Wait for settings to stabilize
@@ -200,14 +210,22 @@
 int main()
     SensorState_t   state;
+#ifdef LPS331_on
+#ifdef LSM303_on
+#ifdef L3GD20