i2c problem waiting for start condition interrupt to occur

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

Hey all. I'm using standard TWI in an ATMega16. Currently, I have normal interface code, for example:

TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while(!(TWCR & (1<<TWINT)));

for my start byte. My problem is that my program gets stuck inside the while loop, waiting for the START to occur. I don't run into this problem until I attach a second device to the bus. Could this be due to violating setup or hold conditions? My application uses a DAC and operates correctly until an extra device is added to the bus (IO expander). After an additional device is added, the program will start operating, but lock up shortly after starting (after the input to the DAC gets past a certain point). Debugging in AVR Studio showed my TWI_Start function was causing the infinite loop. Any ideas?

Thanks.

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

After a bit more probing, I've found that the last valid status code being sent before the lockup corresponds to the TWI controller losing arbitration in write mode. Why might I be losing control of the bus? The IO expander device shouldn't be creating any bus activity, all its interfacing code is commented out.

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

What kind of pull-up resistors are you using on the TWI lines? How far apart are your TWI devices? Schematics?

If the IO expander is not initialized (does it have some sort of reset pin) it might jam the bus (mm, rasberry). I've seen one I2C chip that will jam the TWI bus when the chip has been set to powerdown mode with an external pin.

- Jani

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

pull-ups are currently 4.7k, a little high but should be fine. Bus is operating at 100kHz. Expander is a prototype, so it's physically farther away than it will be for final design. There's around 1ft of cable for the SDA/SCL lines.

I have the IO expanders init routines written, as I said it was tested independently and could be read from and written to successfully. I've attached the schematics for the main controller and the io expander, simplified but showing the i2c bus completely. As you can see, reset is tied high, while all other inputs but the unused one (NC) are tied to ground.

Last Edited: Mon. May 1, 2006 - 08:15 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You show several of the M32's vcc pins wired via capacitors to vcc, not tied directly to vcc. Is this just a drawing error or did you really wire it this way? All vcc and gnd pins need to be wired directly to the power source, not capacitive coupled. Also if you could reduce those images down, we can read the messages without having to scroll back and forth.

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

I believe the schematic is incorrect, the 3 vcc's are showing 5V on my voltmeter. The capacitors aren't inline with VCC, they're (presumably) acting as stabilising caps. I didn't lay out the hardware, so I'm not entirely sure, but the controller has been operating correctly as wired for several revisions, so presumably this isn't a problem.

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

With these PCB layout schematics, as long as a pin is given a net name it doesn't need a wire drawn to it. You can make a whole schematic drawing without a single line on it (and I hate people who do that). So the caps and the pins will all be connected to VCC on the PCB.

Atmel Data Sheet wrote:
Arbitration is carried out by all masters continuously monitoring the SDA line after outputting data. If the value read from the SDA line does not match the value the Master had output, it has
lost the arbitration.

One way to lose arbitration is to mess up the STOP condition at the end of an I2C read. If you ACK (instead of NAK) the last read byte, the slave will send you another one. If you didn't want it and you send a STOP condition, the slave doesn't see the STOP and sits there waiting for the master to send it some more clocks. The next clock is, of course, the START condition, but the slave doesn't care, it just outputs its next bit. Since the bus is wire-and, a low from the slave overrides a high from the master, and bingo, you lose arbitration.

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

I don't ever use the read operation for the DAC, only writes. My IO expander code isn't being used in the program currently, but reads are terminated with a nack from the master. Writing to the DAC takes two bytes of data, and the first byte is ACKed, but the status code on the mega32 changes to indicate lost arbitration after the second byte is written. There doesn't seem to be a pattern to the bit sequence that causes it to break, but it is consistent on the values it breaks on.

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

Consistent on the values it breaks on? That sounds like a clue. Could these values be something like - oh, I don't know - 0b0100xxx1, or 0b100xxx1x? I'm inclined to one of two things - either there's some unknown hardware problem affecting the signal levels, or some unforeseen software interaction with the IO expander. Perhaps both. Perhaps, due to SCK-SDA timing skew, the IO expander thinks it sees a start condition followed by its own address and RD. Can you scope it?

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

Hi Zalfrin

I had a very similar effect in a past project.

My code was also hanging in the same while loop if a start condition did occur, before the last stop condition was really finished, respectively the last addressed device has released the bus!

There is no bit you can poll, to wait until the stop is really finished, so I did put a fixed delay of a few micro seconds after sending any stop condition. Well, this is a little waste of CPU-time, but it did help!

Regards Peter

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

Peter wrote:
There is no bit you can poll, to wait until the stop is really finished

There is, actually. From the data sheet,
Quote:
When the STOP condition is executed on the bus, the TWSTO bit is cleared automatically.

I know this works, I use it here and there.

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

@peret

Okydoky, I didn't recognice this point in the datasheet, thanks a lot for the hint!

So you are waiting for the TWSTO-Bit is cleard, before you init the next start?

Peter

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

Quote:

So you are waiting for the TWSTO-Bit is cleard, before you init the next start?

I only use it for page-writing an EEPROM. When I hit the page boundary I set TWSTO to start the write, and I noticed occasional problems if I immediately went to ACK polling with no break. Waiting for TWSTO to clear keeps things tidy.

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

waiting for the stop bit to be cleared, or just inserting arbitrary delay after the stop condition unfortunately does not help. I got ahold of a TI IO expander and tested it in isolation. It did not cause the program to malfunction. I'm waiting for the IO expander board to come back with the TI chip wired up to see if it causes the same problem.

peret: I'm not entirely sure of the bit sequence that is causing the lockup, but theoretically the value it is trying to send to the DAC is 0.88 in decimal. As I said, this is split into a high and low byte, and the problem seems to occur during the transmission of the second byte; status code indicates succesful transmission of first byte.

RPM values that cause lockups: 123, 158, 166, 181

double speedHz = speedRpm * RPM_TO_HZ_CONSTANT = speedRpm * 6.66667

double gNewVoltage = speedHz*speedHz*VConstant1 + speedHz*Vconstant2 + Vconstant3
VConstant1 = 0.0000005 Vconstant2 = 0.0004 Vconstant3 = 0.2157

value passed to DAC = (int) (13107 * gNewVoltage)

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

Well I ran a couple of those numbers without seeing what I expected, but I'll spend a little more time later. What I'm thinking is that if the DAC response is a bit slow, it might not pull down SDA for the ACK until SCL has gone high, which wouldn't upset the AVR or the DAC but would appear to everything else on the bus as a start condition. If the next byte following can possibly be recognized as a device address by the IO expander, it might wake up and its ACK would interfere with the data transmitted by the AVR, causing the loss of arbitration. One way to check this would be to dramatically slow down the TWI with some large prescale value. See if it happens at 10kHz or less.

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

Tried setting bits 0 and 1 in the TWSR reg to get a prescaler of 64, which translates to an extremely slow baud rate. Problem is still occuring consistently at 123rpm. Motor takes noticeably longer to spin up, but otherwise there is no change. I will bring in my digital camera on friday and take a picture of the scope with bus operating, maybe it will provide some insight. There are some odd spikes on the data line, but I believe they correspond with ACKs coming from the DAC.

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

I work out those values to give 0x0DF3, 0x0EEB, 0x0F26, 0x0F96 respectively. Like you, I can't see any particular pattern in the bits. They all have a 1 to 0 transition at or within one bit of the byte boundary, but so do lots of other numbers.

This doesn't make a lot of sense to me:

Quote:
the value it is trying to send to the DAC is 0.88 in decimal

0.88 of what? 0.88 of 12 bits is 0x0E14, which is in your trouble range, but the DAC8571 is sixteen bits, so I would have said 0.88 is 0xE146 and the 123RPM value is 0.055 of full scale.

I don't see any pullup resistors on the main controller. I'd try a couple of extra 4.7k's at the AVR pins next.

You are sending the DAC control byte before the two data bytes, I suppose? I was going to ask that earlier but I thought nah, he wouldn't have overlooked that.

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

Maybe an other hint:

If you are reading from a I2C device, in general the master must not acknowledge the last databyte before sending the stop condition. There are some devices which may block the I2C bus if they got an stop after an acknowledge.

I am using this function....

void TWI_read(u08 TWI_adr, u08 *val, u08 count)
//------------------------------------------------
// Read n=count bytes from I2C-Bus in polled mode
// needs about 200us for reading addr + one byte
//------------------------------------------------
{
  u08 i=0;
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);    // send START condition
  while (!(TWCR & (1<<TWINT)));              // wait for response
  if ((TWSR & 0xF8) == TW_START)             // if START was successful
  {
    TWDR = (TWI_adr | 0x01);                 // put slave address+READ to TWDR
    TWCR = (1<<TWINT)|(1<<TWEN);             // and start transmission
    while (!(TWCR & (1<<TWINT)));            // wait for response
    if ((TWSR & 0xF8) == TW_MR_SLA_ACK)      // if acknowledge ok
    {
      count--;
      while (count>i)                        // while more than one byte to read
      {
        TWCR=(1<<TWINT)|(1<<TWEA)|(1<<TWEN); // then start transfer with ACK
        while (!(TWCR & (1<<TWINT)));        // wait for response
        val[i++]=TWDR;                       // read databyte from TWDR
      }
      TWCR=(1<<TWINT)|(1<<TWEN);             // last byte transfer without ACK
      while (!(TWCR & (1<<TWINT)));          // wait for response
      val[i]=TWDR;                           // read databyte from TWDR
    }
    else
    {
      UART0_putl_I("Error: I2C[R] Addr");
    }
  }
  else
  {
    UART0_putl_I("Error: I2C[R] Start");
  }
  TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);     // transmit STOP condition
  delay_us(10);                               // wait until STOP is transmitted
}

Regards, Peter

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

It seems to be related to the Microchip IO expander specifically. Switching the IO expander on the PCB with a PCF8574N I had laying around resulted in no more lock-ups in the main program, and correctly functioning reads and writes to the expander.

peret: the 0.88 I quoted was the value I calculated as being sent to the DAC for 123 rpms, although running it again now gives a different number. Probably a mistake on my part, or windows calculator's. You are correct, there are no pull-ups on the main board. Before adding the IO expander, we were using the internal pull-ups. The IO board includes pull-ups, however, and I really don't think the issue is related to rise time. And yes, the write sequence for the DAC is correct, including control byte. Not to mention if that were the problem, it should have shown up before adding the IO expander.

I got some pictures of the bus on the scope, I'll post them when I get home since I don't have an SD card reader at work.

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

Thanks to everyone helping me out. I've finally managed to locate the problem. Your idea turned out to be correct, Peret. The microchip expander was acking at strange times because it was a first revision chip, which was incorrectly designed. Instead of reading for its opcode every 9-bits (8 data + ACK), it was reading every 8-bits. This was why your calculations and pattern searching were fruitless.

http://ww1.microchip.com/downloa...

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

It was a no-brainer that the expander was talking when it shouldn't. There was no other way you could be losing arbitration. But I'm astonished it turned out to be a silicon mistake, and something so fundamental! That would be costly. I imagine there was a blood-letting ...

The ex-Intel guy says, "Tonight's Top-9.9999299 is ..."
The ex-Nasa guy says, "I'm here to put the insulating foam in your wall cavity"
The ex-Microchip guy says, "Would you like fries with that?"