Version 5 (modified by joe.muller.uk@…, 16 months ago)

--

LIS302 Digital Accelerometer

I've already had a play with the analog accelerometers, which were fine, but as they are analog I am naturally allergic to them.

Instead, my preference is the LIS302 3-axis accelerometer from STMicroelectronic. It is dynamically switchable from +/-2g t0 +/-8g by software, which is nice. It also has both SPI and I2C interfaces. SPI == Good, I2C == Bad, so I'll start with SPI.

This part also has free fall detection, and a gesture interface, so it will work out if you have "double clicked". One step at a time though.

I am using the breakout board from Sparkfun, LIS302DL Breakout - The novelty of hand soldering crazy packages is wearing off.

source:/LIS302/doc/LIS302_bob.jpg

Cut to the chase... library please!

If you have visited this page to get the class to use in your own code :

It just an experiment, but it works. All feedback welcome!

Hooking it up

There are no pin numbers on the breakout board, but the signal names instead - you can enumerate them how you wish :-) There are also two interrupt pins that are not part of the convenient SIL header, which are for Freefall detection interrupts. We'll not be using them just yet.

LIS302 Signal Name mbed pin
Vcc Vout
Gnd Gnd
SCL 7
MOSI 5
MISO 6
CS 8

source:/LIS302/doc/DSCF0699.JPG

  • Click for a close up

Hello World

The first and best resource for getting this going will be the datasheet for the LIS302 part :

#include "mbed.h"

SPI _spi (5,6,7);
DigitalOut _cs (8);
Serial pc (USBTX,USBRX);


int main() {

  int val=0;
  
  // Taken from datasheet
  // 8 bit data
  // High steady state clock
  // Second edge capture
  _spi.format(8,1,1);
  
  // 1MHz clock rate
  _spi.frequency(1000000);

  // Select the device, active low chip select
  _cs = 0;
  
  // Send the command to read the WHOAMI register
  _spi.write(0x8F);   // Send the "Read  WHOAMI Register
  
  // send a dummy byte to receive the contents of the WHOAMI register
  val = _spi.write(0x00);
  
  pc.printf("WHOAMI register contains 0x%X\n",val);

  // Deselect the device
  _cs = 1;

  }

Phut! WHOAMI reads back 0x0, instead of the expected 0x3B. Read the datasheet again...

Oh, you have to write to CTRL1_REG and set bit 6 to power the device up.

So the code now looks like :

#include "mbed.h"

SPI _spi (5,6,7);
DigitalOut _cs (8);
Serial pc (USBTX,USBRX);


int main() {

  int val=0;
  
  // Taken from datasheet
  // 8 bit data
  // High steady state clock
  // Second edge capture
  _spi.format(8,1,1);
  
  // 1MHz clock rate
  _spi.frequency(1000000);

  // Select the device, active low chip select
  _cs = 0;
    
  // Enable the device, and all three channels
  _spi.write(0x47);
  
  // end this transfer
  _cs = 1;
  
  wait (0.01);
  
  // start new transfer
  _cs = 0;

  // Send the command to read the WHOAMI register
  _spi.write(0x8F);   // Send the "Read  WHOAMI Register
  
  // send a dummy byte to receive the contents of the WHOAMI register
  val = _spi.write(0x00);
  
  pc.printf("WHOAMI register contains 0x%X\n",val);

  // Deselect the device
  _cs = 1;

  }

Bingo! WHOAMI now reads 0x3B, as it should.

Reading some acceleration numbers

Now I want to start reading OUTX, OUTY and OUTZ - the outputs of the accelerometer.

The output is a 8 bit signed number, so there is 7 bits of resoltion and the accelerometer is +/-2g, so I need to divide the signed number by 64.0. I'll put in a while loop so I can continuously read and make sure it looks sensible.

#include "mbed.h"

SPI _spi (5,6,7);
DigitalOut _cs (8);
Serial pc (USBTX,USBRX);


int main() {

  int val=0;
  
  // Taken from datasheet
  // 8 bit data
  // High steady state clock
  // Second edge capture
  _spi.format(8,1,1);
  
  // 1MHz clock rate
  _spi.frequency(1000000);

  // Select the device, active low chip select
  _cs = 0;
    
  // Enable the device, and all three channels
  _spi.write(0x47);
  
  // end this transfer
  _cs = 1;
  
  wait (0.01);
  
  // start new transfer
  _cs = 0;

  // Send the command to read the WHOAMI register
  _spi.write(0x8F);   // Send the "Read  WHOAMI Register
  
  // send a dummy byte to receive the contents of the WHOAMI register
  val = _spi.write(0x00);
  
  pc.printf("WHOAMI register contains 0x%X\n",val);

  // Deselect the device
  _cs = 1;
  
  // now read out the from the acceleration registers
  while (1) {
       
      _cs = 0;
      _spi.write(0xA9);   // Read X out reg
      signed char xraw =  _spi.write(0x0);
      _cs = 1;

      _cs = 0;
      _spi.write(0xAB);   // Read Y out reg
      signed char yraw =  _spi.write(0x0);
      _cs = 1;

      _cs = 0;
      _spi.write(0xAD);   // Read Z out reg
      signed char zraw = _spi.write(0x0);
      _cs = 1;

	  float xaxis = xraw/16.0;
	  float yaxis = yraw/16.0;
	  float zaxis = zraw/16.0;

      pc.printf("A X=%f, Y=%f, Z=%f\n",xaxis,yaxis,zaxis);
      wait(0.5);
  
      }
  }

Okay, so that is working. The numbers are not quite what I;d been hoping for :

X=0.875000, Y=0.000000, Z=-0.187500
X=-0.875000, Y=-0.187500, Z=-0.250000
X=0.125000, Y=0.937500, Z=-0.062500
X=0.000000, Y=-0.937500, Z=0.062500
X=0.000000, Y=0.062500, Z=0.812500
X=0.000000, Y=-0.125000, Z=-0.937500

Looking at the datasheet it does say that calibration at the factory can be affected when the part is soldered. It also says that the typical full scale is 2.3g, with 2.0g being minimum.

Bearing this in mind, i'll change the 64.0 fudeg factor to 128/2.3 = 55.6, and in 8g mode, it is actuall 9.3g

Give that a go...

X=1.007194, Y=-0.215827, Z=0.287770
X=-1.079137, Y=-0.215827, Z=-0.143885
X=0.000000, Y=1.007194, Z=-0.287770
X=0.143885, Y=-1.007194, Z=-0.143885
X=0.071942, Y=0.071942, Z=0.935252
X=0.071942, Y=0.071942, Z=-1.151079

Closer.

Time to wrap it up into a class.

Building the class

The API I'd want for this class is

  • LIS302(int mosi, int miso, int clk, int ncs);
  • float x(void);
  • float y(void);
  • float z(void);
  • int whoami(void);
  • int status(void);
  • void range(int g); (0=2g, 1=8g)

At the top of this page is a link to the subversion where this is kept. Go have a look at the code if you're interested.

Here is a HelloWorld using the class :

#include "mbed.h"
#include "LIS302.h"

LIS302 acc (5,6,7,8);
Serial pc (USBTX,USBRX);

int main() {
    while (1){
        pc.printf("%.3f %.3f %.3f\n",acc.x(),acc.y(),acc.z());
        wait(0.1);
    }
}