LIS302DL 3Axis Accelerometer I2C

Did you notice that the x value wasn't stable. Hovering around 2-5 and sometimes overflowing (it feels) to 255 ?

Sorry for bringing back an old thread.

@bGatti - Thanks for the code! It was very helpful.

@boubele - Did you ever figure out why the values don't seem to settle? I notice that all three values seem to hover between 0-2. I'm also seeing a constant status value of FFh which I think means X, Y and Z are overflowing. If I enable the high pass filter, it seems a little better but not much.

So, how exactly would you wire the accelerometer to the Arduino?

Connecting the LIS302DL to the arduino is fairly simple with the i2c protocol. You need to connect SDA (labelled MOSI) to pin analog 4 and SCL to analog 5.

Those with the seeeduino board will find some convenient breakout pads that once you solder angled pin headers on makes the connection very easy.

For those seeing 0xFF on x, y, and z values, this is because the result is sent back as 8bit 2s complement number. Simply cast them to char to see them as signed numbers, or just declare them as chars to begin with. To make these numbers more useful, we need map the value (-128 to +127) to -2 to +2, and this is done by first normalising the value by dividing it by 128, then multiplying by 2. These 2 operations combines into divide by 64 (2/128 = 1/64). This gives us acceleration in gs.

This isn't all that useful because we want to only work with ints, so our answer is going to be 0,1,2 which isn't much granulity. So lets work in accelerations, which is m/s/s. To do this we simply multiply by 9.8, so we are really doing 9.8/64 ~0.15 which is to say, multiply the value by 0.15. Bbut 0.15 is a float! Let us invert it, 1/0.15 = 6.666, truncating this gives us 6. So if we divide the value by 6 we get a truncated measure of acceleration in m/s/s.

Note that truncating 6.6666 as 6, rather than rounding, is a somewhat arbitrary decision, partly influenced by the fact 6 gives me nicer numbers with my LIS302DL, so YMMV. Experiment with various values until you get a 9 or 10 when an axis is straight "down".

Here is my Sketch, it is designed to work with a 2x16 character LCD, but should be trivial to convert to using Serial.

#include <LiquidCrystal.h>
#include <Wire.h>
// based on Sketch by bGatti from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213072318
// for use with http://www.nkcelectronics.com/triple-axis-accelerometer-breakout--lis30302.html
// tested with a seeeduino board, i2c connection established using the breakout pads with angled
// pin headers soldered in.
// Copyright Shu Ning Bian 2008, released under GPLv2
int _slave_id = 0x1D;
int backlight_pin = 3;

LiquidCrystal lcd(5,6,7,8,9,10,11);

uint8_t read_register(uint8_t sub)
{
   i2c_send(_slave_id, &sub, 1);
   return i2c_read(_slave_id);
}
     
void write_register(uint8_t sub, uint8_t data)
{
  uint8_t bytes[] = {sub, data};
  i2c_send(_slave_id, bytes, 2);
}

uint8_t i2c_read(uint8_t id)
{
  Wire.requestFrom(_slave_id, 1);
  while(!Wire.available())
  {
    delay(10);
  }
  
  return Wire.receive();
  
}

void i2c_send(uint8_t id, uint8_t * data, uint8_t len)
{
  Wire.beginTransmission(id);
  for(int i = 0; i < len; ++i)
  {
    Wire.send(data[i]);
  }
  Wire.endTransmission();
}

void dot_print(int val)
{
  /* prints a number in the form of i.f where i is from val/10 and f
     from val%10
  */
  int i = val/10;
  int f = val%10;
  
  if ( val < 0 )
  {
    f*=-1;
  }
 
  if ( i>=0 )
  {
    // print a + to counter the - which is added by print when val is negative
    lcd.print("+");
  }

  lcd.print(i, DEC);
  lcd.print(".");
  lcd.print(f,DEC);
  if (i<10)
  {
    lcd.print(" ");
  }
}

void pretty_print(char x, char y, char z)
{
  /* The divisor of x,y, and z are chosen to give the "correct" value at 1g. They are worked out
     by trial and error, but a rough starting point can be calculated as follows:
     
     1. divided by 128 to normalise the range
     2. multiply by 2 since the range is +/- 2, 
       * combined so this gives divided by 64, giving acceleration in gs
     3. multiply by 9.8 to give acceleration in ms/s/s, 
       * combined this gives multiply by 9.8/64 
     4. to make things into nicer integer maths, invert 9.8/64 to give 6.5
     5. now we can truncate and use divisor of 6, an integer, or sacrifice some cycles and use
        a floating value around 6 which gives the "correct" value of 9.8m/s/s for an axis when that
        axis is "pointing" towards the centre of the earth.
     Note I have multiplied everything by 10 implicitly to keep us in int domain
  */
  int xx = x * 100 / 55;
  int yy = y * 100 / 55;
  int zz = z * 100 / 63;

  lcd.clear();  
  lcd.print("X:");dot_print(xx);lcd.print(" ");
  lcd.print("Y:");dot_print(yy);lcd.print(" ");
  lcd.setCursor(0, 1);
  lcd.print("Z:");dot_print(zz);lcd.print(" (m/s/s)");
}

#define CTRL_REG2 0x21
#define CTRL_REG1 0x20

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
  lcd.print("Setting up...");
  write_register(CTRL_REG2, B01000000);
  /* 0 - SPI mode selection
     1 - reboot memory contents
     0 - none
     0 - filtered data selection, 0 = bypassed
     0 - high pass filter enable for freefall/wakeup #2, 0 = bypassed
     0 - high pass filter enable for freefall/wakeup #1, 0 = bypassed
     0 - high pass coefficient 2
     0 - high pass coefficient 1
     the last 2 bits configure the high pass filter cutoff frequency
  */
  
  write_register(CTRL_REG1, B01000111);
  /* 0 - data rate selection, 1=100Hz
     1 - power down control, 1 = active mode
     0 - full scale selection, 0 = +/- 2g, 1 = +/- 8g
     0 - self test P enable, 0 = normal mode
     0 - self test M enabled, 0 = normal mode
     1 - z axis enable, 1 = enabled
     1 - y axis enable, 1 = enabled
     1 - x axis enable, 1 = enabled
  */
  
  pinMode(backlight_pin, OUTPUT);
  analogWrite(backlight_pin, 128);
}

void loop()
{

  #define OUT_X 0x29
  #define OUT_Y 0x2B
  #define OUT_Z 0x2D
  #define STATUS_REG 0x27

  //----------Status Register-----------------------
  byte  status = read_register(STATUS_REG);

  #define ZYXDA  0x08
  if ( status & ZYXDA == 0)
  {
    // ZYXDA is 1 when new set of data is available, so since its 0, lets skip
    return;
  }
  
  //----------X Values-----------------------
  char x_val = read_register(OUT_X);


  //----------Y Values-----------------------
  char y_val = read_register(OUT_Y);

 //----------Z Values-----------------------
  char z_val = read_register(OUT_Z);

  //Serial.print("status "); Serial.println(status, BIN);
  
  pretty_print(x_val, y_val, z_val);
  delay(200);
}

Im still pretty new at this and Im confused on the physical connection part of it. I know:

SCL to 5 (5.6K pull-up)
MIS1 to 4 (5.6K pull-up)
MIS0 to Vcc
Vcc = 5vdc

but how do you use a resistor as a "pull-up" resistor? does that mean I connect a 5.6k resistor to the VCC and then to the data lines??? And why is MIS0 the only one marked as connect to VCC.

A visual diagram would be awesome!
Thanks in advance...

I figured out what I was doing wrong. Now that its up and running the instructions originally given make complete sense... but if anyone else runs in to trouble like I did, PM me and I'll help you out.

Thanks for the nice i2c example - good for getting started.

I have a few experiences with the LIS302DL that I think should be shared.

Voltage: Don't overdo it.
At first, I just send 5V from the arduino board to Vcc on the chip, as suggested in this article.
But I experienced the accelerometer randomly going dead.
Then I made a voltage devider with two 2k7 and gave it 2.5 v, and now it runs flawlessly.

Pull up - not needed?
I didn't bother to put pullup-resistors on the 4 and 5. It seems to be no problem to skip them.

Remeber - 4 and 5 is ANALOG pins
That i2c is on analog pin 4 and 5 is probably obvious, but it took me some time and frustration before I realized my error. Don't connect to 4 and 5 digital.. :slight_smile:

My few cents on this. Might post some code when the project moves on..

Best regards
Christian Liljedahl

@Christian Liljedahl
Re: voltage: I had the opposite experience with this, strangely enough. I could not get it to work at all with a voltage divider using 2x1k5 resistors.

I ended up taking away the lower resistor, and that has been running happily, though I still don't like it :-/

Re: pull ups: I think thats for SPI, not i2c.

pull ups: I think thats for SPI, not i2c.

Nope, it's I2C. The ATmega has them built in, and Wire.h enables them by default.

-j

@kg4wsv
Ah, I see. Thank you :slight_smile:

HI, trying this code all I get is : 1, 255, 3 even when I move the accelerometer....

What's wrong ?

E

I'm using a Lis302Dl accelerometer, with I2C but my values are not constant, for example is i'm triyng to read the Who_Am_I register i'm getting values 00 and 3B.The strange thing is that i figure it out, it was reading 3B an good values from x y and z, but next day i' we tried to make another test and with the same code it wasn't reading good values.
What am i doing wrong?
Here is my microC code.

       char sir[3]={0,0,0};
       char *who="Who Am I = ";

void HexToString(char val)
 {
  char rest;
  int i=0,j=1;
  for(i=0;i<2;i++)
  {
      rest=val%16;
      val=val/16;
         if(rest<0xa) rest+=0x30;
         else rest+=0x37;
      sir[j]=rest;
      j--;
  }

 }

void main(){
  char  x=0,y=0,z=0,xyz=0,identificator,reg1=0;

    //initializare I2C
    TRISC=1;
    PORTC=1;

    LCD_Config(&PORTB, 2,1,3,7,6,5,4);         // initialize I2C communication
    
    LCD_Cmd(LCD_CURSOR_OFF);
    
    LCD_Out(1,1,"X = ");
    LCD_Out(1,8,"Y = ");
    LCD_Out(1,15,"Z = ");
    LCD_Out(2,1,"CTRL Reg1 init= ");
    LCD_Out(3,1,"CTRL Reg1 setat= ");
    LCD_Out(4,1,who);
    
    I2C_Init(400000);
    while(!I2C_Is_Idle());

    //reading from CTRL Reg 1 init

    I2C_Start();
    I2C_Wr(0x38);
    while(!I2C_Is_Idle());
    I2C_Wr(0x20);
    while(!I2C_Is_Idle());
    I2C_Repeated_Start();
    I2C_Wr(0x39);
    while(!I2C_Is_Idle());
    reg1=I2C_Rd(0);
    I2C_Stop();
    
    //LCD+ CTRL Reg1

    HexToString(reg1);
    LCD_Out(2,16,sir);
    Delay_ms(100);
    
    //seting CTRL Reg 1
    
    I2C_Start();
    I2C_Wr(0x38);
    while(!I2C_Is_Idle());
    I2C_Wr(0x20);
    while(!I2C_Is_Idle());
    I2C_Wr(0xC7);
    while(!I2C_Is_Idle());
    I2C_Stop();
    Delay_ms(100);


    //reading the new CTR Reg 1

    I2C_Start();
    I2C_Wr(0x38);
    while(!I2C_Is_Idle());
    I2C_Wr(0x20);
    while(!I2C_Is_Idle());
    I2C_Repeated_Start();
    I2C_Wr(0x39);
    while(!I2C_Is_Idle());
    reg1=I2C_Rd(0);
    I2C_Stop();

    //LCD + the new CTRL Reg1

    HexToString(reg1);
    LCD_Out(3,17,sir);
    Delay_ms(100);



    //reading Who Am I

    I2C_Start();
    I2C_Wr(0x38);
    while(!I2C_Is_Idle());
    I2C_Wr(0x0f);
    while(!I2C_Is_Idle());
    I2C_Repeated_Start();
    I2C_Wr(0x39);
    while(!I2C_Is_Idle());
    identificator=I2C_Rd(0);
    I2C_Stop();
    
    //LCD + who_am_I

    HexToString(identificator);
    LCD_Out(4,12,sir);
    Delay_ms(100);


    while(1)
    {
           Usart_Init(9600);
    Usart_Write(sir);
    //reading X
    I2C_Start();
    I2C_Wr(0x38);
    while(!I2C_Is_Idle());
    I2C_Wr(0x29);
    while(!I2C_Is_Idle());
    I2C_Repeated_Start();
    I2C_Wr(0x39);
    while(!I2C_Is_Idle());
    x=I2C_Rd(0);
     x=255-x;
    I2C_Stop();
    
    //LCD+ x
    HexToString(x);
    LCD_Out(1,5,sir);
   // Usart_Init(9600);
    //Usart_Write(x);
//    Delay_ms(10);


    //reading y
    I2C_Start();
    I2C_Wr(0x38);
    while(!I2C_Is_Idle());
    I2C_Wr(0x2B);
    while(!I2C_Is_Idle());
    I2C_Repeated_Start();
    I2C_Wr(0x39);
    while(!I2C_Is_Idle());
    y=I2C_Rd(0);
    //y=255-y;
    I2C_Stop();

    HexToString(y);  //LCD+ y
    LCD_Out(1,12,sir);

//    Delay_ms(10);

    I2C_Start();              //reading z

    I2C_Wr(0x38);
    while(!I2C_Is_Idle());

    I2C_Wr(0x2D);
    while(!I2C_Is_Idle());

    I2C_Repeated_Start();
    I2C_Wr(0x39);
    while(!I2C_Is_Idle());

    z=I2C_Rd(0);
     //z=255-z;
    I2C_Stop();

    HexToString(z);  //LCD + z
    LCD_Out(1,19,sir);

    Delay_ms(100);

    }
}

Thank you

Anyone have a picture of how to hook up the lis302dl to my arduino mega, or where every pin goes.

So far I can only see that 4 pins are being used, 2 for power and the other to for communication. What do I do with the other pins?

What do I do with the other pins?

Page 9/42

I got the LCD working, and it keeps reading out "setting up..." and never changes.

I put VCC to 3v
GND to GND
SCL to Analog 4
MOSI to Analog 5
MISO to 5v
CS to 5v

I think that the MOSI and SCL are never read or something... everyone says the code works though.

I didn't use any pull-up resistors. How do you attach the pull up resistors? Just put them is series to the inputs/ to ground?

Help! Thanks!

Hi. I was wondering if anyone has gotten the LIS302DL to work with flash (I'm currently using SerProxy and as3Glue to communicate with the Arduino). I've gotten the accelerometer to work under the Arduino environment, but am unsure of how to get it to communicate with flash.

Thanks.

It didn't work on my arduino and accelerometer. I bought the sparkfun LIS302DL with breakout.

Connect wires as below:
VCC to 3v
GND to gnd
SCLK to anolog 5
MOSI to anolog 4
CS to 3v

The result in serial monitor shown status register was 0 and xyz was 65:15:0. When I rotated it to certain angle it would became 0:0:0

But I am sure this is not the correct result. Does anyone have the same issue using this code?

Hi guys, sorry for the thread necromany on this topic, however I'm encountering the exact same problem as the poster above me.

Status register is reading as 0x00, implying that there is no new data available and the three output registers for the x:y:z axes read 65:15:0

I'm assuming there is a fault condition somewhere, that the data is reading implies this fault is outwith the communication protocol itself.

any help would be greatly appreciated

edited to add: infact, no matter what register I try to read, the serial monitor always displays 65:15:0....

Infact, I further tested this device by changing the device adress to something random, the idea being that if were the incorrect address, it would at least be easy to spot, since logically the devices shouldn't communicate. What I got? still 65:15:0

update: well, there was one fault in my code, in so much as I'd put the line regarding readGood outside of the last if loop for the z axis read, when put in the proper place I am reading as getting no data.

Got access to an oscilloscope and found my SCL line reading a constant high. This is obviously something of a bummer to me.

Any general hints on why this might be?