ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Following example from Documentation/i2c/dev-interface I wrote very simple code to read out raw data from ITG3200 ... but the odd thing is that I hadto skip data from other devices in an unexpected way.
What am I doing wrong ?
Code:
#include <sys/ioctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <errno.h>
#define I2C_DEVICE "/dev/i2c-1"
#define I2C_DEV_ADDR 0x69
#define I2C_DEV_SELF 0x0
#define I2C_DEV_INT 0x1a
#define I2C_DEV_REG_START_ADDR 0x1b
#define I2C_DEV_REG_END_ADDR 0x22
main ()
{ int file,buffer;
int i,j,k;
int raw_data[4],data[4];
char buf[256] = {0};
if ((file = open(I2C_DEVICE, O_RDWR)) < 0)
{ /* ERROR HANDLING: you can check errno to see what went wrong */
perror("Failed to open the i2c bus");
exit(1);
}
if (ioctl(file, I2C_SLAVE, I2C_DEV_ADDR) < 0)
{ printf("Failed to acquire bus access and/or talk to slave.\n");
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
/*For some unexpected reason I'm getting responses from the other I2C devices
on the same bus so I'm ignoring data that does not match the WHO AM I reg
and also data that has not set the interrupt register (meaning that data is
not really avalible)
*/
while (buf[0] != 0x69 || buf[26] == 0)
{ if (read(file,buf,sizeof(buf)) != sizeof(buf))
{ /* ERROR HANDLING: i2c transaction failed */
printf("Failed to read from the i2c bus.\n");
exit(1);
}
}
j=0;
for(i=I2C_DEV_REG_START_ADDR;i<=I2C_DEV_REG_END_ADDR;i++)
{ k=0;
k= (buf[i] << 8) + buf[i+1];
i++;
raw_data[j]=k;
printf("%4x \n",raw_data[j]);
j++;
}
close(file);
}
I2C is a common wire bus, the other devices may be communicating with other software for other purposes. Yes, you'll "see" those interactions; hence why you need to select only the data which is relevant to your communications. This is not privatized point-to-point. The messaging to/from all devices is visible at all devices; hence why you need the start sequence to grab the line and alert all devices that you wish to use the bus. There are rules for whether or not you can take the line; I forget what you're supposed to do, listen-try-listen again or something else. But that's why you're seeing data not relevant to your specific device, because you're seeing all data on that particular I2C bus.
Interesting ... this is happening on a PI running Slackware ARM and I don't know of anything else using the I2C bus. On that bus I can detect only the devices on the 10DOF that I wired up ... what else would be talking to the devices on the IMU board ?
ioctl(file, I2C_SLAVE, I2C_DEV_ADDR) should be asserting to what device I want to communicate with (ioctl(3, 0x703, 0x69))
I had a closer look at the data that I was discarding and it looked very much like the data was being rotated around full circle ... like as if I was reading 256 bytes from something that was a few bytes longer then 256 and each consecutive 256 byte read would get padded at the front with the leftover of the previous reading.
OK, well your first post implied that you did have other devices hooked up, or at least didn't clarify that you feel nothing else is hooked up.
The software way to attack this is to add some debug to the I2C code, or write your own I2C code to bitbang the interface and diagnose more closely what is happening.
The better (IMHO) way to attack this is to hook a scope up to that interface and look at the signals.
What exactly do you mean by "The software way to attack this is to add some debug to the I2C code, or write your own I2C code to bitbang the interface and diagnose more closely what is happening."
I'm using i2c-dev kernel module to read data out of the bus and apart from the example code in the linux Documentation section the code fragment is all my poorly written code: are you suggesting that I should fiddle with i2c-deb module code ? (I think that's too much for me poor C programming skills) or should I be using a totally different approach for reading data out of the IMU ?
What if I try reading 512 or 1024 bytes at a time to see exactly how much data there is before pattern start over again ?
On the gyro the first byte is the "who am I id" it should be easy to recognize the beginning of a data pattern.
I meant either to replace the driver with your own or modify the existing driver to add some debug to it. OK, not an option.
Your original issue was that you had to examine the data by way of testing that the address matched the register or device you intended to read.
Actually in looking, you need to do more to the device to read registers, you need to send the register address you wish to read. And you can't just bulk read from the start of registers to the end of registers, in fact you can't bulk read unless the manufacturer states that you can. For instance, there is a gap after the WHO_AM_I register, therefore saying you wish to read more than one byte from that address means nothing, you'll either get an error, or you'll get that one byte and the rest will be invalid.
Datasheet for the 3200. If you give no address information, it will assume the register you intend to read is 0x00 which happens to be the WHO_AM_I register. And you probably should read the TEMP and GYRO registers in bulk.
Take a look at the attached code. It is an example program for tickling the I2C port and specifically check out the get_i2c_register() and how it's used. There's also an example to set (write) a register. Much thanks to Sean Cross, the cited author.
What you'll see is that the author is using an i2c_rdwr_ioctl_data structure as well as an i2c_msg structure array, because you need to send two messages to read or write. You first need to indicate the address of the register you wish to read or write, and then you need to send a second message to execute the read or write.
I haven't specifically run this code; however looking at it, it appears to be the correct way.
Code:
/*
This software uses a BSD license.
Copyright (c) 2010, Sean Cross / chumby industries
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
* Neither the name of Sean Cross / chumby industries nor the names
of its contributors may be used to endorse or promote products
derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#define I2C_FILE_NAME "/dev/i2c-0"
#define USAGE_MESSAGE \
"Usage:\n" \
" %s r [addr] [register] " \
"to read value from [register]\n" \
" %s w [addr] [register] [value] " \
"to write a value [value] to register [register]\n" \
""
static int set_i2c_register(int file,
unsigned char addr,
unsigned char reg,
unsigned char value) {
unsigned char outbuf[2];
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[1];
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = outbuf;
/* The first byte indicates which register we'll write */
outbuf[0] = reg;
/*
* The second byte indicates the value to write. Note that for many
* devices, we can write multiple, sequential registers at once by
* simply making outbuf bigger.
*/
outbuf[1] = value;
/* Transfer the i2c packets to the kernel and verify it worked */
packets.msgs = messages;
packets.nmsgs = 1;
if(ioctl(file, I2C_RDWR, &packets) < 0) {
perror("Unable to send data");
return 1;
}
return 0;
}
static int get_i2c_register(int file,
unsigned char addr,
unsigned char reg,
unsigned char *val) {
unsigned char inbuf, outbuf;
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];
/*
* In order to read a register, we first do a "dummy write" by writing
* 0 bytes to the register we want to read from. This is similar to
* the packet in set_i2c_register, except it's 1 byte rather than 2.
*/
outbuf = reg;
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = &outbuf;
/* The data will get returned in this structure */
messages[1].addr = addr;
messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
messages[1].len = sizeof(inbuf);
messages[1].buf = &inbuf;
/* Send the request to the kernel and get the result back */
packets.msgs = messages;
packets.nmsgs = 2;
if(ioctl(file, I2C_RDWR, &packets) < 0) {
perror("Unable to send data");
return 1;
}
*val = inbuf;
return 0;
}
int main(int argc, char **argv) {
int i2c_file;
// Open a connection to the I2C userspace control file.
if ((i2c_file = open(I2C_FILE_NAME, O_RDWR)) < 0) {
perror("Unable to open i2c control file");
exit(1);
}
if(argc > 3 && !strcmp(argv[1], "r")) {
int addr = strtol(argv[2], NULL, 0);
int reg = strtol(argv[3], NULL, 0);
unsigned char value;
if(get_i2c_register(i2c_file, addr, reg, &value)) {
printf("Unable to get register!\n");
}
else {
printf("Register %d: %d (%x)\n", reg, (int)value, (int)value);
}
}
else if(argc > 4 && !strcmp(argv[1], "w")) {
int addr = strtol(argv[2], NULL, 0);
int reg = strtol(argv[3], NULL, 0);
int value = strtol(argv[4], NULL, 0);
if(set_i2c_register(i2c_file, addr, reg, value)) {
printf("Unable to get register!\n");
}
else {
printf("Set register %x: %d (%x)\n", reg, value, value);
}
}
else {
fprintf(stderr, USAGE_MESSAGE, argv[0], argv[0]);
}
close(i2c_file);
return 0;
}
I was doing the read that way because it did appear that i2cget (from i2ctools) was going more or less the same thing.
Here's s the relevant part of the strace I got while reading a ITG3200 register range:
According to i2c-dev.h this is what those ioctls do:
Code:
ioctl(3, 0x705, 0xbee842f0)= 0 -> I2C_FUNCS Get the adapter functionality mask
ioctl(3, 0x703, 0x69) = 0 -> I2C_SLAVE Use this slave address
ioctl(3, 0x720, 0xbee842f4)= 0 -> I2C_SMBUS SMBus transfer
So they just seem to check out adapter functionality and then just bulk transfer a register range. I got put off into thinking that the register range could be as wide as the whole register set ... I had a look at what i2cdump does and it's much more complicated.
Maybe for what I need I can just read what I need instead of dumping everything.
Thanks for the help ... hope this can get me going ... if not I'll be back ;-)
Incidently the code example does not compile on my system:
Code:
root@pi:~# cc -O -o testme i2c_example.c
In file included from i2c_example.c:39:0:
/usr/local/include/linux/i2c-dev.h:37:8: error: redefinition of 'struct i2c_msg'
In file included from i2c_example.c:38:0:
/usr/include/linux/i2c.h:68:8: note: originally defined here
In file included from i2c_example.c:39:0:
/usr/local/include/linux/i2c-dev.h:89:7: error: redefinition of 'union i2c_smbus_data'
In file included from i2c_example.c:38:0:
/usr/include/linux/i2c.h:126:7: note: originally defined here
root@pi:~#
But maybe it's some conflict on structure definitions in i2c.h and i2c-dev.h ... if I comment out the first it seems to compile ok.
I'd be more concerned if it couldn't compile and the compiler couldn't therefore understand the structures. But a conflict of two include files or some other behavior is less a concern. You can also compile it with a debugging flag, for instance using gcc you'd add -ggdb as the argument to use GDB debugging, and then debug under GDB and verify that it properly recognizes the structures; or add debug print/log statements to do the same. You're on the correct track though.
Cool I can now read repetitively and successfully as many times as I want and take an average over let's say the last 10 readings (which should settle out the gyro jitter dew to ambient vibration).
Thanks rtmistler ... your post #7 was really helpful but it has already 2 people finding it helpful so it won't let me add a 3'rd.
Good to know that I was not the only one stuck on this sort of issue
For anyone intrested I'm keeping notes of what I'm doing for future reference and for anyone else intrested: have a look here. There are examples of bash scripts reading data via i2c-tools and the C code doing the same sort of thing but by using i2c-dev kernel module to do the low lever communication (much like the i2c-tools do internally).
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.