View previous topic :: View next topic |
Author |
Message |
henyhollar
Joined: 09 Aug 2009 Posts: 10 Location: Nigeria
|
adxl345 help |
Posted: Tue Dec 20, 2011 10:26 pm |
|
|
I am working with adxl345 in I2c mode with the code below. But it seems not to be working somebody pls help. I have read the manual over and over again without success
Code: |
#include <18F4520.h>
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3, FORCE_HW, RESTART_WDT)
#fuses HS,NOPROTECT, BROWNOUT, PUT, NOLVP
char DEV_ADD = 0x53; //SDO/ADDRESS Pin is tied low
char FIFO_MODE = 0x38;
char POWER_CTL = 0x2D; //Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32; //X-Axis Data 0
char DATAX1 = 0x33; //X-Axis Data 1
char DATAY0 = 0x34; //Y-Axis Data 0
char DATAY1 = 0x35; //Y-Axis Data 1
char DATAZ0 = 0x36; //Z-Axis Data 0
char DATAZ1 = 0x37; //Z-Axis Data 1
//This buffer will hold values read from the ADXL345 registers.
unsigned char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
int i=0;
int1 indicator=0;
//Function declearation
void initialize();
void readRegister(int max);
#INT_SSP
void i2c_isr(){
printf("Device responding..");
x = ((int)values[1]<<8)|(int)values[0];
//The Y value is stored in values[2] and values[3].
y = ((int)values[3]<<8)|(int)values[2];
//The Z value is stored in values[4] and values[5].
z = ((int)values[5]<<8)|(int)values[4];
printf("%2u %2u %2u\n\r",x,y,z);
}
void main(){
set_tris_b(0x00);
printf("Program starting...");
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
initialize();
while (true){
//if (indicator==0)
//Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
//The results of the read operation will get stored to the values[] buffer.
printf("In do loop...");
output_toggle(PIN_B0);
readRegister(6);
//The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
//The X value is stored in values[0] and values[1].
//Print the results to the terminal.
//putc(((int)values[1]<<8)|(int)values[0]);
//values[9]=0;
//disable_interrupts(GLOBAL);
//disable_interrupts(INT_SSP);
delay_ms(1000);
}
}
void initialize(){
output_toggle(PIN_B1);
delay_ms(2000);
printf("Initialize...");
i2c_start();
i2c_write(0xA6);
//delay for ack in the slave device
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
i2c_write(DATA_FORMAT);
i2c_write(0x01);
i2c_stop();
delay_ms(1);
i2c_start();
i2c_write(0xA6);
i2c_write(FIFO_MODE);
i2c_write(0x40);
i2c_stop();
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
delay_ms(1);
i2c_start();
i2c_write(0xA6);
i2c_write(0x2c);
i2c_write(0x0c);
i2c_stop();
delay_ms(1);
i2c_start();
i2c_write(0xA6);
i2c_write(POWER_CTL);
i2c_write(0x08); //Measurement mode
i2c_stop();
output_toggle(PIN_B1);
delay_ms(2000);
}
void readRegister(int max){
//int i=0;
i2c_start();
i2c_write(0xA6);
i2c_write(DATAX0);
//i2c_stop();
i2c_start();
i2c_write(0xA7);
//values[i]=i2c_read(1);
for(i=0;i<6;i++){
//putc(values[i]);
//while(!i2c_poll());
values[i++]=i2c_read(1);
}
i2c_stop();
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Dec 21, 2011 3:01 am |
|
|
First, get rid of the INT_SSP.
Basically this is not wanted/needed for a master device (it triggers when a byte - or control signal - has been received, which is always controlled by the master). As written, this will cause real problems because of the time involved. It takes over 19mSec to execute, and will be triggering multiple times during the I2C transaction, taking the timings way beyond those that are likely to work....
Then you have the problem of voltage. The ADXL345, is designed for 2.5v operation (up to an absolute max of 3.6v). The PIC you are using operates down to 4.2v minimum. If your pullups go to the PIC supply rail, the signal on the ADXL, will be above there maximum ratings, while if they go to the ADXL supply rail, the signals will not go high enough to be accepted by the PIC. YOu _need_ either to be using a PIC that operates at lower voltages, or to have buffer amplifiers on the I2C signals (device like the P82B96).
Then you have the obvious thing that CS on the ADXL needs to be high to switch it to I2C mode - is it?.
Then have you got the ALT_ADDRESS pin grounded?. The addresses you are using (A6, and A7), only apply if this pin is grounded. The default addresses are 3A and 3B.
I stopped reading at this point.....
Take a deep breath, step back, redesign your hardware so you either have a buffer or use a lower voltage PIC, check the connection to ALT_ADDRESS, and then come back if you still can't get it working.
Best Wishes |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Wed Dec 21, 2011 3:42 am |
|
|
Also (int)values[i]<<8 will always give you 0. in CCS C int is 8 bits (and the same as unsigned char by the way), so shifting any int by 8 bits in either direction will shift all the bits out leaving you with zeros. You seem to be wanting to produce 16 bit int, so your casting should be:
(int16)values[5]<<8 || values[4]
AND x, y and z must be int16 (or anything else larger than int which is 8 bits).
RF Developer. |
|
|
henyhollar
Joined: 09 Aug 2009 Posts: 10 Location: Nigeria
|
adxl345 help |
Posted: Thu Dec 22, 2011 6:26 pm |
|
|
Thank you so much for your contributions. I will get to carry out all your suggestions and i will get the result over to you. I guess I have seen a green light, my next post shall be a success IJN |
|
|
henyhollar
Joined: 09 Aug 2009 Posts: 10 Location: Nigeria
|
adxl345 help |
Posted: Wed Jan 18, 2012 6:51 am |
|
|
Thank you all for the help, I got the adxl345 responding now. But how can I address multiple adxl345s on the i2c bus ? The devid on the device is read only. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Jan 18, 2012 8:09 am |
|
|
On a single bus, you can only have two devices.
All you do is pull the SDO pin, which is unused when operating in I2C mode, high on one, and low on the other at boot time (physically wire this pin high/low in the circuit). This switches the device between addresses 0x3A/3B and 0x53/54.
If you need to go beyond two devices, then you need to implement multiple I2C busses.
DEVID, doesn't come into this. Even if you could change it, it wouldn't alter the I2C addressing.
Best Wishes |
|
|
henyhollar
Joined: 09 Aug 2009 Posts: 10 Location: Nigeria
|
help |
Posted: Sat Jan 28, 2012 10:27 pm |
|
|
Please, how do I make sure that the adxl345 returns values only when data is available and not some constant values on x,y and z axes even when the device is static ? Also I am not getting negative values from the device and this gives me a concern if the device is working properly as I claimed above. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Sun Jan 29, 2012 2:14 pm |
|
|
Post your new program. It could be bad formatting of the print fucntion or wrong handling of the data from the sensor. |
|
|
henyhollar
Joined: 09 Aug 2009 Posts: 10 Location: Nigeria
|
adxl345 help |
Posted: Mon Jan 30, 2012 4:03 pm |
|
|
Yes it is temtronic. I am getting something more promising now. Thank you so much. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jan 30, 2012 8:44 pm |
|
|
Also, your readRegister() function has a bug. It doesn't do a NACK on
the last i2c_read(). It needs to do it. Look at the MULTIPLE BYTE READ
diagram on page 18 of the ADXL345 data sheet:
http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf
It shows the last read operation must do a NACK at the end. This is
done in CCS by using a 0 parameter for i2c_read(). You need to fix
your code. |
|
|
|