I2C/TWI error states are confusing to me

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all again! I have a new problem today, and it's with the I2C bus. Specifically, what the behavior is when the device you are addressing is off.

 

So, as background, I am writing code to control a system with a controller board and daughter cards. There can be up to 10 daughter cards installed, but by the system's design there can be any number from 1 to 10 actually inserted at any time. I am using a Mega for the controller board and a Mega for each card, and am using I2C to communicate with them. I can talk to all of them just fine IF they are installed, but the problem comes when I try to determine whether or not the cards are there.

 

I am using Atmel Studio and C, but I took the Arduino Wire interface's underlying C library to use, "twi.h - TWI/I2C library for Wiring & Arduino" and twi.c from the arduino library if you want to follow along. I used the twi_writeTo() function, which should return 0 for success, 1 for length too long for buffer, 2 for address NACK, 3 for Data NACK and 4 for other bus error. When sending to a card that is plugged in, it returns 0 and I can see the result in the status LEDs that it worked. When I try to send a command to a removed card, I either get a 0 returned immediately (which is bizarre because how did a removed device ACK?) or it hangs forever, as if I didnt have pull-up resistors on the line (I do, and don't get ACK problems with micros I can see, which should be the case if I had SCL problems).

 

I am at my wit's end with this particular issue, and it's holding up my project because this behaviour is critical to the functionality of the system. Any help will, as usual, be greatly appreciated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Each I2C Slave has a unique address.   If the device is not present,  you do not get an ACK from i2c_start(ads)

 

Very few libraries can cope with a Slave being removed part way through a I2C byte.

The same applies to a lot of peripheral code.

 

In practice,  you check whether a device is present and just assume it remains present during the subsequent transaction.

If paranoid,   you have Timeouts to cope with "hot-unplugging".    Not part of the I2C spec but will allow you to sleep at night.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simply poll all of the possible addresses and record which provides an acknowledgement. 

 

For the "hot unplugging" issue, you can get part way there by paying attention to the ack (or lack of ack) during the initial addressing. It is MUCH more difficult to manage a disconnect in the middle of an exchange. As David suggests, you may want to implement timeouts on acknowledgements. It will be up to you to go through the spec and figure out what the consequences will be for a disconnect at any given point in the transfer, and design a method to deal with each of those.

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I really need to learn how to communicate better, because I am unsure of how you got that I was unplugging it in the middle of the byte (but this isn't a passive aggressive dig at you; I really have a problem with people inferring a lot from what I say and I have a hard time figuring out why, but it is definitely my problem if I am the commonality). What I meant was any of the ten cards can be plugged in upon startup and I am  trying to identify which cards are present at the start.

 

Basically, what I am saying happens is that I send the command and I receive a return status that indicates an ACK, even when I KNOW the device is not there. It turns out the hanging had to do with a loose connection on the breadboard, so we can throw that out I think.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry,  if we have misunderstood you.    If there is no hot unplugging,   there is nothing to worry about.

 

You have 10 individual Slave addresses.    You just try i2c_start() on all 10.   Determine which ones are present.

 

There are many respected I2C Master libraries.   I suggest that you use Fleury.    Others are available.

 

You hinted that you had hacked some existing code.   (I apologise if I have misunderstood.)

It is always wise to stick with proven code.   Get everything working reliably first.

 

Only start "improving" the proven code when you have got a working project to "test" your new contribution.

 

David.

Last Edited: Wed. Oct 12, 2016 - 06:42 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, let's try again.... I am literally trying to do exactly what you are requesting already. When the controller starts up it needs to determine which card are installed. Their addresses should be between 0x10 and 0x1A. So I scan from 0x10 to 0x1A. However, i wanted to get even more basic than that in order to get this working, so I only sent one byte to one slave from one master using the arduino TWI code (which I would have thought was "proven code"). If the slave is there the function returns '0', and if the slave isn't there the function still returns '0', even though it should return '2' because the address byte couldn't have been ACKed.

 

I have tried Fleury's code in the past and I couldn't make it work at all so I just gave up and went into the arduino library.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you have an Arduino,  use the Wire.h library.   But use it as Nature intended.    Post your sketch here.

 

If you are using C with non-Arduino hardware,   I suggest that you use Fleury.    Post your C program here.

 

I could post either version here.   But I suspect that you want to do it yourself.   And it is an excellent learning technique to post, get feedback,  post, ...

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would love to use Fleury's code, but again, I can't get it to work. I also can't seem to even find a download link for it to try again.

 

However, I can post my code that uses the arduino library.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It should return 2 if no slave, do you have pull up resistors on your twi lines?    4k7 is normal for 5v vcc.

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Most I2C libs aren't to good in handling any strange conditions.

Your main cpu "hanging forever" for a non existing node might well be because it's still waiting for the missing ack pulse.

 

When trying to understand HW & SW interactions a logic analyser is an almost indispensible tool

It will take the guesswork out of half of your equations by just telling you what the hardware side is doing.

Salaea sells some from USD200+ but you can get a clone from Ali for < USD10.

These clones work pretty well with Sigrok (=Open Source LA).

 

The cy7c68013a chip used in these analysers have no internal software.

Software is uploaded by the driver via dfu when you plug it into usb.

http://sigrok.org/wiki/Supported...

 

 

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By Wire.h library,   I was expecting to see a regular Arduino sketch.

 

For Fleury:

#include <avr/io.h>
#include <stdio.h>
#include "i2cmaster.h"

void main(void)
{
    uint8_t slave;          //7-bit slave address
    i2c_init();
    initstdio();
    printf("detect Slaves\n");
    for (slave = 0x10; slave < 0x1A; slave++) {
        if (i2c_start(slave<<1) == 0) {      //Fleury uses 8-bit
            printf("slave %02X is present\n", slave);
            i2c_stop();
        }
    }
}

Typed from memory.   Untested.   But it shows just how simple the test is.

 

As Paul suggested,   a Saleae (or clone) is an excellent investment.

All the same,  you can just as well use the return values from the Fleury functions.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the suggestion, I finally figured out how to get the .c file for fleury so I'll try to get it working again. I am running at 3.3v and am using 2k2Ohm resistors. If I pull the resistors it always hangs indefinitely, which is, I guess, an encouraging sign of sorts.