[En-Nut-Discussion] TWI and Lua problem

Ulrich Prinz uprinz2 at netscape.net
Sun Apr 10 23:20:49 CEST 2011

Good work!

> I'd make more test and found some interesting things. First, I use 
> the function TwMasterTransact to send an address an two data bytes. 
> The function TwMasterRegWrite should be the better one. But I am not 
> sure if will fix this issue.

Normal chip sequence is addressing the chip, addressing something inside
the chip, then read or write something there.
TwMasterTransact is for doing anything else but this :)
It is mostly for I2C communication between several self made boards or so.
The routines you might like to use are TwMasterRegRead and -Write if you
address a real I2C chip.

> With an digital scope I see the start bit was send, then the address 
> byte, next the first data byte. And next I see the stop bit, but this
> is wrong. Now I see the second data byte with the glitch.

Ok, with TwMasterRegRead/Write mostly all special functions of the SAM
hardware I2C are used, as it delivers automatic start/stop generation,
chip address and inside-chip address handling. So the driver fills in
all this information at once and then fires the first run.
With the first interrupt, the first data byte is fetched and written to
the bus. So the first interrupt after rolling the hardware is the one
that requests the first databyte. As the TWDR is empty at that point it
is the cause for the stop bit.

The driver needs a modification to write the first databyte too, before
or right after firing the system.

What the SAM does is a clear violation of the I2C specification! As the
it does not know what to do next it clearly needs to halt and wait until
the next thing happens, either a stop request from the software (Abort)
or a databyte to send. It should never act alone and decide to break the
communication with a glitch like stop. The mechanism completely breaks
the Bit- and ACK-stretching what is used to slow down communication if
the system cannot react fast enough.

> In the data sheet under "Master Transmitter Mode" I found:
> "When an acknowledge is detected, the TXRDY bit is set until a new 
> write in the TWI_THR. When no more data is written into the TWI_THR, 
> the master generates a stop condition to end the transfer."

Looks like they tried to implement a auto-stop functionality... How
awful is that!
> The address byte and the first data byte are send in the function 
> TwMasterTransact, the second data byte is put in the buffer to send 
> it in the TwInterrupt function. Every thing is fine so long the 
> interrupt will be handled fast enough. If the TWI_THR is not filled 
> fast enough the stop bit is send. But the interrupt is handle and 
> (too late) the byte is written to TWI_THR. I think this confuses the 
> TWI hardware and produces the glicht(es).
The TwMasterTransact is just setting up the start condition. With that
sent out the mechanism gets another interrupt that then fetches the data
and everything else. If all data is sent, it checks if it needs to
receive some.

> Until now, I do not found a way to suppress the stop bit until the 
> interrupt is handled.

If the chip is really that fast with the illegal stop condition, you
have no chance. Either you modify the TwMasterTransact and the other two
routines to prefetch one databyte or you switch to DMA mode.
> I think this is a weakness in the TWI hardware. If you have high 
> speed on the TWI bus or a complex system with disabled interrupts, 
> the interrupt driven TWI handling will not work. The async TWI bus 
> has now some synchron aspects and this is worse!

Weakness is really not the right word, its (beeeeep)... (SCNR)
> This behavior fits good my application. If I send the data before
> all the threads are running, it works. If the Lua thread and all the 
> other threads are running it fails.
The driver is a bit complex, but it should not be a problem to prefetch
the first databyte. I have to check the datasheets for the
double-buffering on TWI. If the SAM supports double buffer, you get an
interrupt if the TWDR is empty but the hardware is still sending the
previous byte. So you have the time of one byte to fetch again the next


More information about the En-Nut-Discussion mailing list