| 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.
Cut to the chase... library please!
If you have visited this page to get the class to use in your own code :
- Library: http://mbed.co.uk/projects/cookbook/svn/LIS302/trunk (right-click compiler project, select "Import Library...", and use this url)
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 |
- 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);
}
}

