reading data via i2c-dev
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> |
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:
/* |
Ok that gives me some very good hints.
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: Code:
open("/dev/i2c-1", O_RDWR) = 3 Code:
ioctl(3, 0x705, 0xbee842f0)= 0 -> I2C_FUNCS Get the adapter functionality mask 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 |
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). |
All times are GMT -5. The time now is 10:42 PM. |