will be read-only starting December 31st, 2018. For more info please look at this Forum Post

I2C (master and slave) on the ATtiny85

bHogan Update - January 2017:

It's been years since I posted this. I'm not personally supporting this any more, but wanted to mention a few things that happened to it over the years.

There are now severial versions out in the wild - many with improvements and fixes. Some are mentioned below. However, one thing I want to mention is that I heard that the Modified LiquidCrystal_I2C lib is no longer working. It's just the LiquidCrystal_I2C lib with the "Wire" include defined out. The newer version of this lib can be easily modified to make it work.

On a personal note, I was very happy to see how useful these libs have become. However, it would have been nice if someone really built on my naive attempt and made these libs what they should be. Oh well.


The ATtiny85 microprocessor is an 8 pin chip with 6 (max!) I/O ports. Using an I2C bus greatly expands the possibilities of what you can do with this chip.

The ATtiny85 (and it's cousins) does not have I2C (or SPI) "built in". Instead it has a Universal Serial Interface (USI) that can be used to facilitate I2C and SPI.

After a bit of searching, I found 2 sets of code that use the USI for I2C - one for I2C master and the other for I2C slave. I wrapped each in a separate class and had them follow a similar usage as the Wire lib.

Status & Usage:

I don't consider myself a "sharp guy" when it comes to coding, and this was my first experience with making a class, so go easy. As far as I'm concerned, these libraries are done. However it would be nice to see the master and slave libraries combined like the Wire library is. The slave lib is also missing the "onReceive" and "onRequest" functions - however it is still usable.

I've only tested these libraries with an ATtiny85. They may work on an ATtiny45 and others that use USI with easy mods to the include files.

Testing was done using the the ATtiny85 core files from "high-low tech" and also the core files from and uploaded with the ArduinoISP or the USBtinyISP.

Both the 1MHz and 8MHz clock speeds were tested.

By default the I2C master library (TinyWireM) is set to run at 1MHz. To run at 8MHz, #defines in USI_TWI_Master.h / .cpp must be changed. No changes are necessary for the I2C slave library (TinyWireS).

Each library includes examples, and there is documentation in the headers of these, and more in the associated .h files.

Be sure to use pullups! (4.7K on 5V). I2C with these libs is not as forgiving as the Wire lib. (Maybe the internal pullups are not set.)

I2C Master:

The base code for this lib came from 'jkl' at CMU - see .h for link. I've tested send and receive on severial I2C devices. You can download the lib here:

 USAGE is modeled after the standard Wire library . . .
  Put in setup():
	TinyWireM.begin(){                               // initialize I2C lib
  To Send:
	TinyWireM.beginTransmission(uint8_t slaveAddr){  // setup slave's address (7 bit address - same as Wire)
	TinyWireM.send(uint8_t data){                    // buffer up bytes to send - can be called multiple times
	someByte = TinyWireM.endTransmission(){          // actually send the bytes in the buffer
	                                                 // returns (optional) 0 = sucess or see USI_TWI_Master.h for error codes
  To Receive:
	someByte = TinyWireM.requestFrom(uint8_t slaveAddr, uint8_t numBytes){      // reads 'numBytes' from slave's address
	                                                 // (usage optional) returns 0= success or see USI_TWI_Master.h for error codes
	someByte = TinyWireM.receive(){                  // returns the next byte in the received buffer - called multiple times
	someByte = TinyWireM.available(){                // returns the number of unread bytes in the received buffer


There are 3 example sketches in the "examples" folder.

I2C Slave:

The base code for this lib came from Don Blake at AVR freaks - see .h for link. I've tested receive and respond while connected to a "master send a receive" sketch on the Arduino. You can download it here:

 USAGE is modeled after the standard Wire library . . .
  Put in setup():
	TinyWireS.begin(I2C_SLAVE_ADDR);              // initialize I2C lib & setup slave's address (7 bit - same as Wire)

  To Receive:
    someByte = TinyWireS.available(){                // returns the number of bytes in the received buffer
    someByte = TinyWireS.receive(){                  // returns the next byte in the received buffer

  To Send:
	TinyWireS.send(uint8_t data){                // sends a requested byte to master


There's an example sketch in the "examples" folder.

Modified LiquidCrystal_I2C for the ATtiny:

After becoming quite tired of counting flashing LEDs on the ATtiny, I made a small mod to Mario H's LiquidCrystal_I2C library that will use TinyWireM instead of Wire when compiling for an ATtiny85. It's pretty cool to see a 2x16 LCD display running from that tiny chip! I added an example "HelloWorld_Tiny" to his examples. You can download the modified LiquidCrystal_I2C library for the ATtiny here: (v1+ IDE)

This lib still supports the ATmega as it always had, so you can safely replace your LiquidCrystal_I2C lib with this one.

I hope you find these libraries fun and useful.


(Blog with I2C/85 project -

Update 2012.08.18

I have implemented onRequest and onReceive (with limitations) support, get the files from my Github repository and check out example attiny_i2c_slave.ino

This version also includes improvements from others that I have found when trying to solve my issues with the original library.

ATtiny84 Support 2012.10.30

If you need support for the ATtiny84 (or 44), there is a forked version of the above library on Github that supports the ATtiny44/84 series.

Composed Master/Slave library TinyWire: 2017.10.29

I united the TinyWireM and TinyWireS libraries to get master and slave functionality in one library. It is now possible to init the library as slave and sending as temporary master (and being a slave again after it). With this, the library behaves a bit more like the Wire library. As in the latest version of the TinyWireS library, you can use the onRequest and onReceive user callback and the library implements bus arbitration (it just doesn't check on arbitration lost, if it was addressed itself). It should also implement correct slave clock streching (see issue #1). For supporting other than ATTiny25/45/85 you only have to fill in the device dependent definitions in the library. You can find the library on