Hello forum !
I just got my hands on a LSM303DLH (catalog page here). Since then, I’ve browsed several documents, the one on the I2C protocol and this particular part.
Also, read the case where an Arduino simply got frozen in the I2C commands, which later resulted in voltage level difference problems, that got solved later.
Background:
I have adapted the example code provided for the Orangutan to be used in a single ATmega8 chip. I changed the code so that the TWI interface produced a 100kHz clock (Standard I2C mode). The whole circuit is supplied with 5V from a regulated switching supply.
My testbed:
With a greatly stripped-down version of the code -for testing purposes- It appeared that the sensor was actually ACK-ing my AVR because it completed the commands used to write and read bytes from the I2C bus. I did this by turning on a LED before the command and turning it off afterwards.
The test:
Finally, I changed the code so that the value of one of the bytes read was sent to a port (portD) to view it with a LED-bar. Then, I’ve tested by outputting each of the bytes (high and low parts of each of the 3 axis) for both the accelerometer and the magnetometer.
The issue:
Every byte I read from the accelerometer is 0h31, and every byte I read from the magnetometer reads 0h3D. And these values are FIXED. I’ve tried moving the module, tilting it in order to alter the readings. Nothing happened.
As a curious fact… that 0h31 is the reading address for the Accelerometer and 0h3D, for the magnetometer.
Now, as far as I understand, the configuration commands provided in the example code put the sensors in “free running” so they auto-update their registers with new measurements, right? So, if I sample them periodically I’d expect to see changing values (and different LEDs lit-on) by changing the sensor position.
I hope this error is just a misunderstanding of the I2C protocol or how it works, or even how the sensors are designed to work. This rather than having a malfunctioning part.
The code:
(The code is essentialy the same as the Orangutan’s example, I’ve just changed the main() function and added the delay_ms() function for the time delays. I’m pasting the changed part of the code.
// ### OMMITTED COMMENTS ##//
// HEADERS AND DEFINES
#define F_CPU 4000000 // 4mhz, for delay_ms()
#include <avr/io.h>
#include <util/delay.h>
// #include <pololu/orangutan.h> // Not using Orangutan, just an ATmega8
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include "vector.h"
// ### OMMITTED CODE ##//
void delay_ms(unsigned int time_ms)
{
while (time_ms--)
_delay_ms(1);
}
int main()
{
// DATA OUTPUT TO LED BAR
DDRD = 255;
PORTD = 0;
DDRC = 1; // PC0 as blinking LED
// IT IS NOT NECCESARY TO ENABLE THIS, THE CIRCUIT HAS EXTERNAL 4.7K PULLUPS
// PORTC = (1 << PORTC4) | (1 << PORTC5); // enable pull-ups on SDA and SCL, respectively
TWSR = 0; // clear bit-rate prescale bits
// FOR ATMEGA8
TWBR = 12; // produces an SCL frequency of 100 kHz with a 4 MHz CPU clock speed
//enable accelerometer
i2c_start();
i2c_write_byte(0x30); // write acc
i2c_write_byte(0x20); // CTRL_REG1_A
i2c_write_byte(0x27); // normal power mode, 50 Hz data rate, all axes enabled
i2c_stop();
//enable magnetometer
i2c_start();
i2c_write_byte(0x3C); // write mag
i2c_write_byte(0x02); // MR_REG_M
i2c_write_byte(0x00); // continuous conversion mode
i2c_stop();
// Data variables (high and low) for each axis
unsigned char axl,axh,ayl,ayh,azl,azh,ret = 0;
unsigned char mxl,mxh,myl,myh,mzl,mzh = 0;
// DEBUG CODE TEST BEGIN
while(1){
// read accelerometer values
i2c_start();
i2c_write_byte(0x30); // write acc
i2c_write_byte(0xa8); // OUT_X_L_A, MSB set to enable auto-increment
i2c_start(); // repeated start
i2c_write_byte(0x31); // read acc
axl = i2c_read_byte();
axh = i2c_read_byte();
ayl = i2c_read_byte();
ayh = i2c_read_byte();
azl = i2c_read_byte();
azh = i2c_read_last_byte();
i2c_stop();
// read magnetometer values
i2c_start();
i2c_write_byte(0x3C); // write mag
i2c_write_byte(0x03); // OUTXH_M
i2c_start(); // repeated start
i2c_write_byte(0x3D); // read mag
mxh = i2c_read_byte();
mxl = i2c_read_byte();
myh = i2c_read_byte();
myl = i2c_read_byte();
mzh = i2c_read_byte();
mzl = i2c_read_last_byte();
i2c_stop();
PORTD = axl; // Output the read value for the accelerometer X axis low byte
// Blink led to know that things are running
for(int r=0;r<5;r++) delay_ms(100); // Wait 1/2 sec
PORTC = 1;
for(int r=0;r<5;r++) delay_ms(100); // Wait 1/2 sec
PORTC = 0;
}
}
(I’ve also attached the whole *.c file to this message If you find it neccesary)
I hope you can give me some advice on how to solve this, I expected to have issues with all the whole I2C voltage thing, but it appears that the voltage shifting circuitry already on the board do all the work.
Best regards, David.
acelerometro.c (7.19 KB)