TINY USI Interface in I2C
mode and the AVR312 Appnote
wrong with the AVR Appnote ?
- What can be done better ?
- Master precautions:
- Timing example:
- Source Code:
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
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
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 !
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)
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
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.
8 databits @ 400kHz
2.5µs*8 = 20µs
ACK + clock stretching 7µs + 2.5µs
makes in total ~40µs per Bytes and that makes ~ 25kByte/s
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
This is not the whole function !