TINY USI Interface in I2C mode and the AVR312 Appnote

  1. What's wrong with the AVR Appnote ?
  2. What can be done better ?
  3. Master precautions:
  4. Timing example:
  5. Source Code:

updated 2014-05-26

What's wrong with the AVR Appnote ?

Pic 1. Wrong I2C behaviour of USI Interface

Let's see what happens is a start condition occurs (1a).
The SCL line is falling while SCK remains HI, this is a standard Start condition on I2C bus.
The Start condition detector of the USI hardware Interface detects the Start at the point (1a).
Now, the SCK counter starts counting the edges of SCK, beginning with the edge at (1b) and..... bäng !
The 16th (0) edge is the rising edge of Bit 8, the counter overflows and clock stretching will start immediately while Bit 8 is running.
If the USI Interruopt is now handled fast enough, the SCL pin is released before SCL is pulled down by the master (2b).
The rising edge of the SCK line is now detected as the edge for the ACK bit and the drama is running on.......

What can be done better ?

Pic 2. Correct I2C behaviour of USI Interface

Now, the following change has to be added to the code:
Keep in Start detection Interrupt until SCK and SDA are LO

Now, the interrupt wait's until (1b).
The first counted SCL edge is (1c=1), the 16th is (2a=0)  and now pulling SCL low for Clock stretching is valid.

Keep in mind, that  the Start detection interrupt need's some time to be ready (see below).
Also, the master should take care of not allow too long times for the clock stretching, a timout is a fine thing and a must if the master is implemented in Bitbang mode.
Additional, the USI also makes clock stretching after the ACK Bit, so be prepared, the master must handle this !

! Warning !  
If the USI interface is running in interrupt mode, than the processor is halted until SCL is LO in case of SCL is falling (START)
If this happens e.g. because of  not terminated pins (no I2C connected), then the processor wouldn't do anything else than waiting for the falling SDA edge, wich, in worst case, never happens !
Use the watchdog timer to reset device or watchdog interrupt to finish this state (e.g. by polled nonvolatile flags in the USI interrupt)

Master precautions:

Tested slave was a TINY44 running at 8MHz, but other USI interfaces should behave the same.

Tds (Delay after start and before rising SCL of Bit0)  should be 4µs at minimum, 5µs is save (8 MHz slave).
Tcs (Delay after Bit8 falling edge to ACK rising edge) is 7µs at minimum, but can be longer. 500µs timout should be enough in most cases.

1/(Tlo+1/Thi) = Frequency should be lower then SlaveClock / 4, but keep in mind, that pullups and cables makes timing slower!
But 400kHz should be possible if slave is running at 8MHz and more


There are three possible pints of clock stretching from the slave's USI:
1. Directly after the Start condition occurs.
2. After databit #8 and before ACK
3. After ACK and before the next byte.

1. can be avoided to be test if there's enough time after START and before the SCL's edge of databit #0.
2. should be handled by master by testing the value of SCL after setting it HI for the ACK  bit
3. must be handled by master by testing the value of SCL after setting it HI for databit #0.

Timing example:

Start condition                    5µs+5µs      = 10µs
8 databits @ 400kHz         2.5µs*8       = 20µs
ACK + clock stretching      7µs + 2.5µs = 9.5µs

makes in total ~40µs per Bytes and that makes ~ 25kByte/s

Source Code:

The original AVR312  Appnote can be found on the Atmel website.

modifications on the Slave code:

Please keep in mind, that the code above only handles the parts to be changed !
This is not the whole function !