dknute
Posts: 57
Joined: Thu Nov 08, 2012 9:05 pm

I2C problems

Sat Mar 01, 2014 1:23 pm

I'm trying to interface RPi with I2C device. It kind of works, but not properly.

I'm using ioctl's with I2C_RDWR, rather than read/write since I need to specify internal register address in the device for read/write operation. I've seen some code do that exactly the same way I'm trying and it works, but not for me. Basically, a register write looks like this:

Code: Select all

int reg_write (int reg, int data)
{
  struct i2c_rdwr_ioctl_data io;
  struct i2c_msg msg [2];
  char buf [2];

  buf [0] = reg;
  buf [1] = data;
  msg [0].addr = dev_addr;
  msg [0].flags = 0;
  msg [0].len = 1;
  msg [0].buf = buf;
  msg [1].addr = dev_addr;
  msg [1].flags = I2C_M_NOSTART;
  msg [1].len = 1;
  msg [1].buf = buf+1;
  io.msgs = msg;
  io.nmsgs = 2;
  if (ioctl (fd, I2C_RDWR, &io) < 0)
    return -1;
  return 0;
}
This doesn't work. It only works if I modify the code to look like this:

Code: Select all

int reg_write (int reg, int data)
{
  struct i2c_rdwr_ioctl_data io;
  struct i2c_msg msg [2];
  char buf [2];

  buf [0] = reg;
  buf [1] = data;
  msg [0].addr = dev_addr;
  msg [0].flags = 0;
  msg [0].len = 2;
  msg [0].buf = buf;
/*
  msg [1].addr = dev_addr;
  msg [1].flags = I2C_M_NOSTART;
  msg [1].len = 1;
  msg [1].buf = buf+1;
*/
  io.msgs = msg;
  io.nmsgs = 1;
  if (ioctl (fd, I2C_RDWR, &io) < 0)
    return -1;
  return 0;
}
Why am I splitting it into 2 writes anyway? Well, for write it doesn't make much sense but this is just an example of a bit more complicated code that can also handle pure data writes (no register address at all). For reads though I need to start with write to specify register address, then repeat start and do the actual reading. So it has to be split, and it shouldn't make a difference during a write anyway.
With split transaction it looks like there is a stop condition added in between, that resets the reg address to zero. So writes will fail (reg zero is RO anyway). Reads will always return reg zero contents, but if I try to pull 256 bytes I can get the whole address space dumped properly. So it does actually read data, it's not a bus speed problem, I get all the acks in places I should be getting them, except reg offset always starts at zero. Which my docs says will happen after a stop condition.

I haven't actually checked if there really is a stop condition with a scope as the RPi and device are in a different location (I only have remote access) - I'm trying to figure this out purely from software side at the moment. Any ideas?

User avatar
DougieLawson
Posts: 38505
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: I2C problems

Sat Mar 01, 2014 1:26 pm

What's the device?
Have you looked at Gordon's WiringPi to make your I2C programming easier? http://wiringpi.com
Note: Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

I'll do your homework for you for a suitable fee.

Any DMs sent on Twitter will be answered next month.
All non-medical doctors are on my foes list.

dknute
Posts: 57
Joined: Thu Nov 08, 2012 9:05 pm

Re: I2C problems

Sat Mar 01, 2014 6:10 pm

Sorry, can't say what the device is. For now it's a prototype but it might end up being manufactured, in that case I'd be in trouble if I said too much :)

I guess I'll have to set up a mirror project somewhere where I can access it, and test I2C with a known, working chip. I just thought it might be a known issue or something, I haven't used I2C hardware under Linux control before. I'm more familiar with MCUs without OS, and/or driving IO pins in software.

MagPi
Posts: 4
Joined: Fri Feb 21, 2014 5:05 pm

Re: I2C problems

Sat Mar 01, 2014 10:55 pm

I think you basically answered your own question. Without knowing the i2c device, it is hard to know but I'm going to guess anyway. The device's transaction definition may require the register number and the data be written in one operation. When you try to do it in two separate single-byte transfers, the STOP happens after the first byte which goofs up its little brain. If you stop in the middle of the transaction like this, how can it know if the next write is a register number or a data byte?

techpaul
Posts: 1512
Joined: Sat Jul 14, 2012 6:40 pm
Location: Reading, UK
Contact: Website

Re: I2C problems

Sun Mar 02, 2014 11:10 am

We dont need to know what the whole device is you are testing, just what the interface chip spec is for accessing its registers.
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/

dknute
Posts: 57
Joined: Thu Nov 08, 2012 9:05 pm

Re: I2C problems

Sun Mar 02, 2014 11:23 am

Precisely my problem. I was, however, under the impression that as long as the device address is the same, even a split transaction will happen without any stop conditions. After all, of what use would be I2C_M_NOSTART flag if there were always stops added?

And I did find these pages that seem to confirm it:
https://www.kernel.org/doc/Documentatio ... c-protocol
http://bunniestudios.com/blog/images/infocast_i2c.c

Except it doesn't work for me... So here I was thinking, maybe it's a silly mistake in low-level I2C code on Pi. I did find someone's fix for i2c-bcm2708.c:
http://www.raspberrypi.org/forums/viewt ... 71&t=49838

Code: Select all

		//bcm2708_wr(bi, BSC_C, BSC_C_I2CEN);
		bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);

User avatar
Douglas6
Posts: 4850
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: I2C problems

Sun Mar 02, 2014 3:36 pm

I don't know much about the low-level details of I2C, but it sounds like you may be running up against the clock-stretching bug on the Pi?

MagPi
Posts: 4
Joined: Fri Feb 21, 2014 5:05 pm

Re: I2C problems

Mon Mar 03, 2014 4:21 am

I agree your split transaction should work. In fact the kernel.org document describes the RDWR ioctl as "Do combined read/write transaction without stop in between." But now I am quite certain it does not work that way. For a test I connected a 24c02 eeprom and a logic analyzer and ran a test much like yours--my test wrote two bytes and then four more. I chose 0x55 and 0xaa so it is easy to see on the analyzer. I found a STOP condition at the end of the two byte transfer. The 24c02 would not ACK the first byte of the second transaction, because it is busy doing an internal write after it saw the STOP, and that's why the second part of the transaction stopped after one byte.

Here's the test code:

Code: Select all

unsigned char wrbuf[20] = { 0x55, 0xaa };
unsigned char wrbuf2[20]= { 2, 8 };

write_stuff(int file) {
    struct i2c_rdwr_ioctl_data packets;
    struct i2c_msg messages[2];

    messages[0].addr  = 0x50;
    messages[0].flags = 0;
    messages[0].len   = 2;
    messages[0].buf   = wrbuf;

    messages[1].addr  = 0x50;
    messages[1].flags = I2C_M_NOSTART;
    messages[1].len   = 4;
    messages[1].buf   = wrbuf2;

    packets.msgs  = messages;
    packets.nmsgs = 2;
    if(ioctl(file, I2C_RDWR, &packets) < 0) {
        perror("write failed");
        return 1;
    }
}
Here is the timing from the analyzer. The top part shows the whole transaction, and the bottom is zoomed in to the end of the first half where the bogus STOP happens (at the marker). Also notice the second part of the transaction starts with a START bit in spite of the NOSTART flag.
timing.png
i2c timing
timing.png (3.4 KiB) Viewed 4557 times
So I think it isn't going to work as you had hoped.

dknute
Posts: 57
Joined: Thu Nov 08, 2012 9:05 pm

Re: I2C problems

Mon Mar 03, 2014 11:43 am

Many thanks. This will save me a trip to the site :)

I read the docs at http://www.raspberrypi.org/wp-content/u ... herals.pdf and it seems Broadcom Serial Controller (BSC) is not capable of what I want. There is no separate control bit for sending stop condition so I assume it'll do so automatically every time transmit FIFO empties. So much for hacking i2c-bcm2708.c file to "fix it". And Broadcom claims that it's compliant with I2C version 2.1, and even teases with a mention of supporting repeated start on page 37, except it's not really a repeated start if you have stop condition before it. It's just a completly separate command.

Well, no choice then, I'll just fall back to bit banging over GPIO.

techpaul
Posts: 1512
Joined: Sat Jul 14, 2012 6:40 pm
Location: Reading, UK
Contact: Website

Re: I2C problems

Mon Mar 03, 2014 12:24 pm

For repeated start issues see http://www.raspberrypi.org/forums/viewt ... 71&t=49838 which may help
Just another techie on the net - For GPIO boards see http:///www.facebook.com/pcservicesreading
or http://www.pcserviceselectronics.co.uk/pi/

dknute
Posts: 57
Joined: Thu Nov 08, 2012 9:05 pm

Re: I2C problems

Mon Mar 03, 2014 6:00 pm

It's the same link I posted earlier :) And, as I've said, it's not really a repeated start if there's a stop in there as well.

I installed WiringPi and now I toggle SDA/SCL lines myself, slowing things down with usleep. Works like a charm. Thanks again, everyone!

lauri_pirttiaho
Posts: 2
Joined: Tue Aug 26, 2014 10:31 am

Re: I2C problems

Tue Aug 26, 2014 11:48 am

The repeated start transaction, known as "combined" transaction works just fine. It just has to be properly enabled in the driver. See http://www.raspberrypi.org/forums/viewt ... rt#p603520

-- Lauri

Return to “Interfacing (DSI, CSI, I2C, etc.)”