|
|
View previous topic :: View next topic |
Author |
Message |
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
IMU 3000 I2C Question |
Posted: Thu Nov 28, 2013 2:38 pm |
|
|
Hello Everyone,
First off let me say thank you for taking the time to read this post, I will try to explain to the best of my ability my problem, however if anything remains unclear please post or pm me and I will get back to you within the hour!
The Problem: I have an IMU 3000 & ADXL 345 Fusion board from Sparkfun, https://www.sparkfun.com/products/10252
I am using an I2C connection type for all communications between my PIC 18F4520 and the board. I am using a logic leveler to go from the 5v 18f pic pins to the 3v3 sda, scl pins on the board. I have used some sample code to see If I get anything back on the lines and the pic successfully picked up on the Accel ack and Gyro Acks, so I suspect nothing is wrong with my hardware (side note I have also got the accelerometer to work on its own). For some reason whenever I compile and run the following code,
Code: | #include <18f4520.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7)
#use i2c(master, sda=pin_C4, scl=pin_C3, force_hw)
#define GYRO 0x68
#define GYRO_WRITE 0xD0
#define GYRO_READ 0xD1
#define GYRO_DATA 0x1D
#define ACCEL 0x53
#define ACCEL_WRITE 0xA6
#define ACCEL_READ 0xA7
#define ACCEL_DATA 0x32
#define ADXL345_POWER_CTL 0x2d
#define ACCEL_MEASURE_MODE 0x08
int buffer[12];
int gyro_x;
int gyro_y;
int gyro_z;
int accel_x;
int accel_y;
int accel_z;
int i;
void writeTo(int device, int address, int val){
i2c_start();
i2c_write(device);
i2c_write(address);
i2c_write(val);
i2c_stop();
}
void main()
{
writeTo(GYRO,0x16,0x0B);
writeTo(GYRO, 0x18,ACCEL_DATA);
writeTo(GYRO,0x14,ACCEL);
writeTo(GYRO, 0x3D,ACCEL_MEASURE_MODE);
writeTo(ACCEL, ADXL345_POWER_CTL, 8);
writeTo(GYRO,0x3d,0x28);
while(true) {
i2c_start();
i2c_write(GYRO);
i2c_write(GYRO_DATA);
i2c_start();
i2c_write(GYRO_READ);
buffer[0]=i2c_read();
buffer[1]=i2c_read();
buffer[2]=i2c_read();
buffer[3]=i2c_read();
buffer[4]=i2c_read();
buffer[5]=i2c_read();
buffer[6]=i2c_read();
buffer[7]=i2c_read();
buffer[8]=i2c_read();
buffer[9]=i2c_read();
buffer[10]=i2c_read();
buffer[11]=i2c_read(0);
i2c_stop();
gyro_x=buffer[0] << 8 | buffer[1];
gyro_y=buffer[2] << 8 | buffer[3];
gyro_z=buffer[4] << 8 | buffer[5];
accel_y=buffer[7] << 8 | buffer[6];
accel_x=buffer[9] << 8 | buffer[8];
accel_z=buffer[11] << 8 |buffer[10];
printf("%i",gyro_x);
printf(",");
printf("%i",gyro_y);
printf(",");
printf("%i",gyro_z);
printf(",");
printf("%i",accel_x);
printf(",");
printf("%i",accel_y);
printf(",");
printf("%i",accel_z);
printf("\n\r");
delay_ms(100);
}
} |
I get the following results,
0,112,-33,-25,-50,-86
0,0,0,0,0,0
0,0,83,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,17,0,0,119,104
0,0,0,0,0,0
0,0,0,50,0,0
0,0,0,0,0,0
0,0,0,0,0,0
121,28,113,-17,-80,-54
0,0,0,0,0,0
0,83,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
-113,0,32,104,0,0
0,0,0,0,0,0
0,0,0,0,50,0
0,0,0,0,0,0
0,0,0,0,0,0
-41,-99,-74,33,-101,-50
0,0,0,0,0,0
83,0,50,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,32,0,0,104,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,0
0,0,0,0,0,-111
119,0,104,0,0,0
0,0,0,0,0,0
0,50,0,0,0,0
0,0,0,0,0,0
As this is my first I2C project I am not sure what is wrong with my code, I suspect there is a problem with which the order I called the registers are wrong or the registers are wrong in general. I have read both datasheets and feel very stuck. If anyone could go through my code and make any suggestions, comments, I would be forever grateful!!
Again thank you for taking the time to read this post!
[/code] |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Nov 28, 2013 3:36 pm |
|
|
Haven't looked at the data, but suspect your code is based on an example from somewhere else?.
If so, there is one critical obvious thing wrong. In CCS C, an 'int', is an 8bit value. So a line like:
gyro_x=buffer[0] << 8 | buffer[1];
Rotates an 8bit value 8bits (result nothing....), and ore's this with an 8bit value, and writes the result back to an 8bit value. Result 'buffer[0]' has been thrown away.....
Your gyro values need to be declared as int16, and use the make16 instruction to combine the values (dozens of instructions more efficient than rotation and oring)....
Get in the habit of using the explicit sizes (int8, int16, int32), to avoid this type of problem, and remember your print instructions will have to use 'L' for the long values.
Best Wishes |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 3:52 pm |
|
|
Ttelmah !! You the man!
That little correction to my code did indeed fix the output of the accelerometer for my code that pulls the accelerometer data, however for the code that I posted below that talks with both gyros and accelerometer my data seems to still be random, just with a higher magnitude now. This leads me to believe that in fact I am indeed in the wrong registry.
And yes I have pulled several codes from the internet in attempt to get this to work. I have read the PIC18F User guide for I2C and tried to research on the net as much as possible, but as I haven't learned this communication type in class this is all self taught and I feel that I have many questions regarding accessing the registers. Again thank you so much for your help!! |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 4:21 pm |
|
|
PCMprogrammer,
Thanks for the input! I actually decided to use the make16() Function in the CCS compiler it worked perfectly, but for some reason the code is still outputting strange numbers which makes me think I'm not accessing the data registers for some reason, from what I have figured out from looking at other codes (mostly arduino) is after you set up all your modes for your device to actually read the data you do the following.
Device_Write_Address -> Device_Data_Address -> Device_Read_Address
I'm not sure if this is always true but that's what I tried to do in the code I posted above.
Where I am confused is the code I was following used the GYRO Address of 0x68 (which I cannot find in the datasheet) however from using a i2c program to ack different chips I know the Device_Write_Address is 0xD0, I tried using the 0xD0 for the #Define Gyro, but it just outputted zeros, so I changed it back to the 0x68 registry because at least then I was getting some numbers (even if not correct). I'm still trying to find information but I've tried different things I'm just not sure what is going wrong here.
Again thank you all so so so so so much for you're help, and definitely for being patient with this noobie! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 28, 2013 4:24 pm |
|
|
I deleted my post right after posting it because your reply to Ttelmah
implied you didn't need my info. I'll repost it below:
Also, even if you correctly declare gyro_x as an int16, your method of
packing the lsb and msb won't work. In the program below, gyro_x will
be displayed as 0034. That's why Ttelmah suggested using the CCS
function, make16(). If you are OK with using CCS's functions, and you
don't care about portability with other compilers, it's way easier to use
make16().
Quote: |
#include <18F4520.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
int8 buffer[12];
//======================================
void main()
{
int16 gyro_x;
buffer[0] = 0x12;
buffer[1] = 0x34;
gyro_x = buffer[0] << 8 | buffer[1];
printf("%lx \n\r", gyro_x);
while(1);
} |
If you don't want to use make16(), then you must promote the msb to
an int16 before doing the shift. Do it like this:
Quote: |
gyro_x = (int16)buffer[0] << 8 | buffer[1]; |
Then you will get gyro_x set to the correct value of 1234. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 28, 2013 4:27 pm |
|
|
Did you use this i2c bus scanner program here:
http://www.ccsinfo.com/forum/viewtopic.php?t=49713
The addresses that you get will be the actual i2c slave devices that
are active on the bus. Talking to an inactive address won't work.
Post the output that get from the bus scanner program. |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 4:30 pm |
|
|
PCM,
That is the exact scanner I used! It's an amazing tool,
When I run the scanner I get the following output
Code: | Start:
Ack Addr: A6
Ack Addr: D0
Number of i2c Chips Found: 2 |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 28, 2013 4:51 pm |
|
|
Here is the IMU3000 data sheet:
http://www.invensense.com/mems/gyro/documents/PS-IMU-3000A.pdf
Look in this section on page 11, about half way down the table:
Quote: | 3.2 Electrical Specifications |
It says:
Quote: | I2C ADDRESS: (AD0 = 0) 1101000 |
That's in Philips 7-bit (left justified) i2c address format. CCS uses 8-bit
format. To convert it to CCS, add a zero on the right side. It becomes
11010000, which is 0xD0. That's what you should use.
If it doesn't work with 0xD0, it probably means you are doing something
wrong when trying to communicate with the IMU3000.
Also when you display a 16-bit hex value with printf, you need to use a
format string with "lx" for hex values. That's a lower case L in front of
the x. |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 4:54 pm |
|
|
PCMprogrammer,
Thanks again, I really appreciate your help! I tried using the 0xD0 address, but it still just outputs zeros. hmmm I'll keep rereading the datasheet and try to figure out what is going on here. Thanks again! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 28, 2013 4:58 pm |
|
|
In that same table, it says the following:
Quote: | START-UP TIME FOR REGISTER READ/WRITE: 20 ms typical, 100 ms max |
This means you have a delay of at last 100ms, right at the start of main(),
before you try talking to the IMU3000. |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 5:09 pm |
|
|
PCM,
Hey nice eye! Yeah I tried that by adding a 120 ms delay at the beginning of the main but to no avail, I really think there is something wrong with the way I'm setting up the gyro/accel. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 28, 2013 5:54 pm |
|
|
1. Post your current program
2. Run it, and post the output. |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 6:12 pm |
|
|
PCM programmer,
Thanks for all the help man, I really appreciate it!
As requested
Code:
Code: | #include <18f4520.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7)
#use i2c(master, sda=pin_C4, scl=pin_C3, force_hw)
#define GYRO 0xD0
#define GYRO_WRITE 0xD0
#define GYRO_READ 0xD1
#define GYRO_DATA 0x1D
#define ACCEL 0xA6
#define ACCEL_WRITE 0xA6
#define ACCEL_READ 0xA7
#define ACCEL_DATA 0x32
#define ADXL345_POWER_CTL 0x2D
#define ACCEL_MEASURE_MODE 0x08
int16 buffer[12];
int16 gyro_x;
int16 gyro_y;
int16 gyro_z;
int16 accel_x;
int16 accel_y;
int16 accel_z;
int i;
void writeTo(int device, int address, int val){
i2c_start();
i2c_write(device);
i2c_write(address);
i2c_write(val);
i2c_stop();
}
void main()
{
delay_ms(120);
writeTo(GYRO,0x16,0x0B);
writeTo(GYRO,0x18,ACCEL_DATA);
writeTo(GYRO,0x14,ACCEL);
writeTo(GYRO,0x3D,ACCEL_MEASURE_MODE);
writeTo(ACCEL,ADXL345_POWER_CTL,8);
writeTo(GYRO,0x3D,0x28);
while(true) {
i2c_start();
i2c_write(GYRO);
i2c_write(GYRO_DATA);
i2c_start();
i2c_write(GYRO_READ);
buffer[0]=i2c_read();
buffer[1]=i2c_read();
buffer[2]=i2c_read();
buffer[3]=i2c_read();
buffer[4]=i2c_read();
buffer[5]=i2c_read();
buffer[6]=i2c_read();
buffer[7]=i2c_read();
buffer[8]=i2c_read();
buffer[9]=i2c_read();
buffer[10]=i2c_read();
buffer[11]=i2c_read(0);
i2c_stop();
gyro_x=make16(buffer[0],buffer[1]);
gyro_y=make16(buffer[2],buffer[3]);
gyro_z=make16(buffer[4],buffer[5]);
accel_x=make16(buffer[7],buffer[6]);
accel_y=make16(buffer[9],buffer[8]);
accel_z=make16(buffer[11],buffer[10]);
printf("%ld",gyro_x);
printf(",");
printf("%ld",gyro_y);
printf(",");
printf("%ld",gyro_z);
printf(",");
printf("%ld",accel_x);
printf(",");
printf("%ld",accel_y);
printf(",");
printf("%ld",accel_z);
printf("\n\r");
delay_ms(100);
}
} |
Output:
Code: | 0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0
0, 0, 0, 0, 0, 0 |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 28, 2013 7:49 pm |
|
|
Your code is based on this Hobbytronics sample code.
http://www.hobbytronics.co.uk/arduino-adxl345-imu3000
In your earlier Sparkfun link, several people comment that they get
all zeros as output when they use the Hobbytronics code. One person
says "never mind" but then of course doesn't ever tell what he did to fix it.
I need to read the data sheet more closely and see exactly what needs
to be done. I'll try to do this later tonight.
A few things:
1. This should be declared as 'int8':
2. Try using the i2c with the CCS software i2c library code. To do that,
delete the force_hw parameter below. Quite often, the software i2c
will be more reliable:
Quote: | #use i2c(master, sda=pin_C4, scl=pin_C3, force_hw) |
3. What is your CCS compiler verison ? It's given at the top of the .LST
file, and it's a 4-digit number, such as 3.249, or 4.141, or 5.016, etc. |
|
|
Zdetier
Joined: 28 Nov 2013 Posts: 28 Location: Stillwater, OK
|
|
Posted: Thu Nov 28, 2013 8:07 pm |
|
|
PCM,
#1 Done!
#2 Done, the reason I had the force_hw on was because I had read that a lot of people had a hard time with the accelerometer going to sleep and that little snippet of code kept it from doing that.
#3 I am using 5.012 |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|