EEVblog Electronics Community Forum

Electronics => Microcontrollers => Topic started by: eneuro on July 01, 2015, 11:24:51 am

Title: Good USI I2C master / slave ATTiny85 library (optionally master arbitration )
Post by: eneuro on July 01, 2015, 11:24:51 am
After using software master I2C on ATTiny85 succesfully before, now trying use USI I2C and this what I've noticed in this sample I2C master library described there:
ATTiny USI I2C Introduction - A powerful, fast, and convenient communication interface for your ATTiny projects! (
it looks there is no timeout support etc :/
Additionally, I've no idea .. how I2C frequency is defined, since it looks like they use something like this for timing in usi_i2c_master.c:
#define USICR_CLOCK_STROBE_MASK         0b00101011

 #define USI_CLOCK_STROBE()                      { USICR = USICR_CLOCK_STROBE_MASK; }
I've no external clock in many ATTiny projects since I do not need fast I2C and what I've noticed is
USI USICR register mask defined in this file

I've downloaded this example USI I2C ATTiny library from this linked mentioned in above instructables: (

Added definitions for ATTiny85 port and SCL/SDA pin definitions like this:
#if defined (__AVR_ATtiny25__) | \
        defined (__AVR_ATtiny45__) | \
        defined (__AVR_ATtiny85__)
        #define DDR_USI                 DDRB
        #define PORT_USI                PORTB
        #define PIN_USI                 PINB
        #define PORT_USI_SDA    PB0
        #define PORT_USI_SCL    PB2
        #define PIN_USI_SDA             PINB0
        #define PIN_USI_SCL             PINB2

It compiles now, but while trying to talk to RTC (PCF8563) to set its output clock out to 1 Hz in my hand watch project, for the moment probably waits forever in one of those:  USI_I2C_WAIT_HIGH()  / USI_I2C_WAIT_LOW() routines since for the moment I didn't have timeout support-just tried to use this library and see how it works on ATTiny85  :palm:
Maybe external crystal clock was used in this project, so USICR_CLOCK_STROBE_MASK bits 00101011

In ATTiny85 datsheet I found something like this:
The clock can be selected from three different sources: The USCK pin, Timer/Counter0 Compare Match or from software.
The clock is generated by the Master device software by toggling the USCK pin via the PORTB register or by writing a one to bit USITC bit in USICR.

ATTiny85 USICR register below:
Such bits are set in clock strobe routines in USICR: 00101011  -there is no F_CPU or something like I2C frequency settings in this linked USI I2C library...

Last page of ATTiny85 USI documentation shows how clock is selected and it looks like bits USICR[3:1] (101) in this I2C master library selects clock source as "External, positive edge" with "Software  clock strobe USITC" .
( (
Does it mean this I2C master library uses external clock connected to SCL pin? Doesn't setting USITC toggle this SDA line?
According to this page they only mention that to be able see SCL changes DDR output pin must be set (1) to allow "easy" clock generation when implementing master devices  :-//

What exactly this "External, positive edge" clock source means?  Which clock?-I haven't got external crystal clock.
I could create timer and drive this SCL pin, since I do not want any external clocks in low speed I2C setups.
I'm lost for the moment with USI I2C setup, but have ready Attiny85 programmed so will try hard today talk to this RTC as I2C  master  >:D

Support for I2C master arrbitration could be additional advantage and challenge, since in a few projects I might want use this more advanced I2C master mode.

Could someone give some hints (maybe I'm missing something) USI I2C master ATTiny85 library (without any external crystal clocks), please?

Reading again this ATTiny USI datasheet (pages from 108 in linked below PDF): (

NOTE: I've F_CPU set to 8MHz, but no fuses set for this-I switch to 8MHz at the beginning in software, than wait 1s and try to talk via I2C to RTC  using routines described above... so my ATTiny85 runs at 8MHz now , but it will be much lower frequency in hand watch project to save battery life .
Code: [Select]
#define F_CPU    8000000UL
Title: Re: Good USI I2C master / slave ATTiny85 library (optionally master arbitration )
Post by: eneuro on July 01, 2015, 12:02:37 pm
OK. I've found where SCL timings [us] are defined in usi_i2c_master.* files:
Code: [Select]
//I2C Bus Specification v2.1 FAST mode timing limits
 #ifdef I2C_FAST_MODE
        #define I2C_TLOW        1.3
        #define I2C_THIGH       0.6

//I2C Bus Specification v2.1 STANDARD mode timing limits
        #define I2C_TLOW        4.7
        #define I2C_THIGH       4.0

Than those [us] delays are used in code to wait for bus wheen needed to slowdown things:
Code: [Select]
#define USI_I2C_WAIT_HIGH()                     { _delay_us(I2C_THIGH); }
 #define USI_I2C_WAIT_LOW()                      { _delay_us(I2C_TLOW);  }

Update: Yep they takem those delays from I2C specification ver 2.1 (2000) (
( (
Adding 10kHz slow (~10 times slower than I2C Standard maximum 100kHz) mode could be good idea on 8MHz MPU and (slower) since we are still below limits of _delay_us(double) used in this I2C master library, which is:
The maximal possible delay is 768 us / F_CPU  in MHz
and even slow optoisolated I2C buses should work since cut off frequency of very slow cheap PC817/EL817 is 80kHz, etc  8)

So, probbaly will add much slower mode . eg. I2C_SLOW_MODE or I2C_TEST_MODE to modify those timings to slow things even more for I2C protocol testing purposes with not perfectly choosen I2C pullup resistors ;)
This library comes with I2C standard speed ~100kHz max and those SCL timings gives us such frequency, which might be too fast in some I2C setups...
Title: Re: Good USI I2C master / slave ATTiny85 library (optionally master arbitration )
Post by: eneuro on July 01, 2015, 05:45:50 pm
Mystery of I2C master MPU hang up resolved -I've forgot solder pull up resistors on test prototype, so I2C lines had no chance to go high :-DD
Anyway, it was intersting experiment and watchdog or I2C timeout support needed, to avoid this.

Now it is time implement I2C multi-master ( arbitration logic into USI I2C library ;)

Monster Attiny85 MPU
and RTC
ready to run forever powered by... sun/artificial light in hand watch clock project :popcorn:
No bloody AC mains chargers, no wires... no buttons-wireless power transfer and synchronization with pc/tablet/smartphone/cell phone  :)
Title: Re: Good USI I2C master / slave ATTiny85 library (optionally master arbitration )
Post by: bingo600 on July 01, 2015, 07:40:48 pm
afaik this is working code

Master is in the main thread in the below url

slave is linked to in this post (

This is also based on Don's code (

Title: Re: Good USI I2C master / slave ATTiny85 library (optionally master arbitration )
Post by: eneuro on July 02, 2015, 08:29:37 am
afaik this is working code
Yep, but I do not like error handling in this USI I2C master module and this software I2C (single) master by Peter Fleury ( is much more compact and provides pure TWI implementation as well as software version written in assembler.
I've removed in assembler module i2c_delay_T2 and implemented it using _delay_us(double) in custom I2C header:
void i2c_delay_T2();

void i2c_delay_T2() {
which allows me easy define I2C bus speed, while added to my I2C header files definitions like this:
// Delays in [us]/2
        // 100kHz
        #define I2C_DELAY_T2 (5.0)
 #ifdef I2C_SLOW_MODE
        // 10kHz
        #define I2C_DELAY_T2 (5.0*10)
 #ifdef I2C_TEST_MODE
        // 1kHz
        #define I2C_DELAY_T2 (5.0*100)
        // I2C_DEBUG_MODE
        // 100Hz
        #define I2C_DELAY_T2 (5.0*1000)
 #endif // I2C_TEST_MODE
 #endif // I2C_SLOW_MODE
 #endif // I2C_STANDARD_MODE
So, default I2C speed in this software implementation of I2C (single) master library is as low as 100Hz, set for debug mode  ;)

Hopefully, I've found this Atmel AVR310: Using the USI Module as a I2C Master ( so I should have now better understanding what happends on hardware USI registers level in this USI I2C (single) master implementation from first post in this thread, having in mind those typical I2C timing diagrams:

( (

So, need to review this code again and make another tests, but probably software I2C master might better option, however USI I2C might be good for slave, so this way I will have I2C slave implemented in USI hardware and on other two MPU pins software I2C, to be able gather information from another I2C internal MPU network and provide this information as I2C slave device with assigned slave address to external I2C masters  8)
Title: Re: Good USI I2C master / slave ATTiny85 library (optionally master arbitration )
Post by: eneuro on July 03, 2015, 09:03:32 am
I've found this Atmel AVR310: Using the USI Module as a I2C Master (
This was what I was looking for and now USI TWI/I2C (single) master works as expected with I2C error codes like those below- I was able to detect easy that there were no RTC device on bus or missed his address, since I've got error code 0x1
Code: [Select]
#define USI_TWI_NO_ERROR            0x00// NO error
 #define USI_TWI_NO_DATA             0x08  // Transmission buffer is empty
 #define USI_TWI_DATA_OUT_OF_BOUND   0x09  // Transmission buffer is outside SRAM space
 #define USI_TWI_UE_START_CON        0x07  // Unexpected Start Condition
 #define USI_TWI_UE_STOP_CON         0x06  // Unexpected Stop Condition
 #define USI_TWI_UE_DATA_COL         0x05  // Unexpected Data Collision (arbitration)
 #define USI_TWI_NO_ACK_ON_DATA      0x02  // The slave did not acknowledge  all data
 #define USI_TWI_NO_ACK_ON_ADDRESS   0x01  // The slave did not acknowledge  the address
 #define USI_TWI_MISSING_START_CON   0x03  // Generated Start Condition not detected on bus
 #define USI_TWI_MISSING_STOP_CON    0x04  // Generated Stop Condition not detected on bus
 #define USI_TWI_BAD_MEM_READ        0x0A  // Error during external memory read

I2C device detection and error handling is now as simply as it is ;)
Code: [Select]
                // Try to set 1 Hz RTC clock out               

                if( rtc_set_clock_out_1hz() ) {
                        isclock= 1;
                } else {
                        isclock= 0;

                // Output result as morse byte code
                err= i2c_master_error_code();
                if(err ) {
                        morse_byte(PWMPIN, err );
                        // #define USI_TWI_NO_ACK_ON_ADDRESS   0x01 
                        // The slave did not acknowledge  the address

                        addr= i2c_master_error_addr();
                        morse_byte(PWMPIN, addr );


                        isclock= 0;
No scope needed to find typical I2C errors, since in the case of bus error in debug mode error code with I2C 7bit device address is displayed on one MPU pin using... Morse byte codes (blinking led at ~1Hz bit legths to be able read those bytes bits by humans) >:D

Master arbitration is another thing I'd like to support optionally in this USI I2C master library.
For the moment some hints comes from oryginal NXP I2C manuals, but implementing this might be a little bit challenge, since master clock synchronization need to be performed, etc.
( (