interrupt-driver, hardware-handshaking I2C

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

I've written a rather complex I2C driver to enable 4 IC's to communicate (mega64, mega88's and RTC). Everything is interrupt-based - the data is pushed into a fifo and then the rest of the program continue as normal.

The AVR's use Master-transmit (MrTx) and Slave-receive (SlRx) to communicate and then the mega64 uses master-receive (MrRx) to communicate with the RTC.

I experienced 1 problem that cost be a lot of time (and headache pills):

The THEORY:
is when MCU1 does a MrTx to MCU2, MCU2 will go into SlRx mode and when it receives the STOP condition it will set a flag. When the data has not been extracted by the time MCU2 is again addressed as slave (TWSR = 0x60), it must return from the ISR, but this time instead of clearing the TWINT bit it must clear TWIE - thus disabling I2C-INT, but leaving the flag set.
Because TWINT is not cleared the SCL line will be held low and prevent whoever the master is from sending more data. The moment the previous SlRx data is extracted by the main program (SlGet() is called) TWIE will be set. This will cause the TW-ISR to execute immediately which will then clear TWINT and this will release the bus (SCL) so the first data byte can
be received.

The REALITY:
is that everything works out as planned, but the first data-byte being sent by MrTx is always lost. It seems to me that after MCU2 is addressed and I clear TWIE, it continues to receive the first data-byte and then halts the bus but does not put that first data-byte into TWDR.

In PRACTICE:
I now clear TWIE after receiving a STOP/RESTART condition (0xA0). This effectively halts the bus the moment a complete frame has been received by a Slave and prevents two other MCU's to exchange data until MCU2 has extracted its received data.
This method works, but as you can think is less than ideal.

Has anybody ever tried a multi-master handshaking scheme like this with the AVR. At this moment it seems to me like a hardware bug in the TW module.

Besides that I must say that I2C is a brilliantly thought out protocol. Viva Philips! I wonder on what basis did Atmel win the I2C court case against Philips and I wonder how much compatability guarantee comes with the 'I2C' stamp (which AVR doesn't carry)? Like the USB-compatible logo for instance.

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

Ok, so nobody has ever tried this before? Or my post is just too long and boring? Maybe someone from Atmel can just give me an indication of what to test for - or if they know about this problem.
Before I make this post I read all the I2C and TWI posts on this forum and somewhere between them I found 1 that mentioned a bug in the TWI hardware.

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

Hi Johan, I am just in the process of starting to also write an I2C driver. From my reading of the I2C spec it seems it would be a better implementation to just leave TWIE on all the time, but set the TWEA bit in TWCR to zero, when busy. As a slave it will then NACK the addressing of itself, but leave the bus free for other devices to use. I have also noticed comment in the forum of a hardware bug with multi-master use of the I2C. I therefore plane to use ony one I2C master on the bus and stay away form this problem.

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

Hi Johan, I thought about that. The only problem is that the sending MCU cannot know the difference between a NACK caused by a full buffer and a NACK caused by a faulty receiver. Therefore an error condition will occur - which complicates the communication even further.
"Anders om 'n SA hier te sien."

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

Hi, I now understand the reason for your design choice. For myself, I am rather going to leave the bus free and retry the communications. Several failed retries will give me the answer that the unit is probably unavailable for some failure. The reason for steering away from allowing any slave to hold the bus is, a software bug at the wrong point in time will effectivly hang the I2C bus, instead of allowing only the one unit to die in peace. I have a healthy respect and fear for Murphy.

[Ek is ook in Pretoria, stuur my 'n privaat mail dan gesels ons bietjie. javascript:emoticon(':D')
Very Happy]
Cheers :D

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

This is Atmel's TWI bug.

Quote:
I just want to confirm that we are still working on this issue and that we are able to reproduce the issue you have encountered. We at the moment working on a software workaround. I will send you more information as soon as I have verified the workaround.

Best Regards
Lars Thore Aarrestad
Atmel AVR Technical Support

Please keep the complete mail
correspondence in your reply!
--------------------------------------------
AVR Vikings: avr@atmel.com

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

I will appreciate any fix or workaround, thanks.

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

The only workaround I'm using so far is to disable and re-enable TWI with TWEN bit in TWCR after every message received

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

do you mean after every packet (e.g. START, SLA-ACK, DATA, STOP) or just after the frame (STOP/RESTART).

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

johannkok wrote:
just after the frame (STOP).

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

I'm not sure about whether this is a hardware bug or not, but I'd suggest trying Atmels own code for implementing interrupt-driven I2C - application note AVR315.
Seems a lot easier than writing all code yourself :-)

/Jakob Selbing

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

jaksel wrote:
I'm not sure about whether this is a hardware bug or not, but I'd suggest trying Atmels own code for implementing interrupt-driven I2C - application note AVR315.
Seems a lot easier than writing all code yourself :-)

I work with brberie and can confirm that the Atmel code does not fix the multi-master problem. So far we have only two "working" (if you can call them that) solutions. The first is to disable and re-enable the TWI as mentioned previously by brberie. This has the downside of increasing the number of missed messages, so error handling and retries become very important. Also winds up significantly cutting the bandwidth available. The second is a token passing scheme so that the order of communications is limited to a known good pattern. One microcontroller in the TWI network powers up able to transmit and the others must wait. If the MCU with the token has something useful to say, it sends a message with the useful data, otherwise it sends a blank message to the next microcontroller in line to pass the token. The microcontroller receiving the message (or token) is then allowed to either send a message or pass the token on to another mcu. This also results in wasted bandwidth and code overhead. Also, as pointed out in another post, if the microcontroller with the token dies, then the entire TWI bus is taken down with it.

For the curious, the bug has to do with the timing between when a stop condition and a start condition occur. The minimum time is not always met in multi-master mode and so a microcontroller can miss a start condition, think the bus is still free, and start talking in the middle of someone else's transmission. This confuses both of them and the bus goes south.
-Will

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

Quote:
I'm not sure about whether this is a hardware bug or not, but I'd suggest trying Atmels own code for implementing interrupt-driven I2C - application note AVR315.
Seems a lot easier than writing all code yourself

AVR315 only handles masterTx mode. There is another (AVR311) that covers slaveRx, but I use masterTx, slaveRx and masterRx so I need to do more coding anyway.

Quote:
The first is to disable and re-enable the TWI as mentioned previously by brberie.

I just need to confirm that this is the same than the method I talked about in the original post. Are we taling about the same solution?

Quote:
In PRACTICE:
I now clear TWIE after receiving a STOP/RESTART condition (0xA0). This effectively halts the bus the moment a complete frame has been received by a Slave and prevents two other MCU's to exchange data until MCU2 has extracted its received data.
This method works, but as you can think is less than ideal.

Is this bug on Atmel's priority list for fixing in new devices?