Step 8: TWI / I2C Explained

I2C stands for Inter-Integrated Circuit. I2C busses are also known as TWI for Two Wire Interface, since it uses only two wires.

Related Readings:
On a TWI bus, the two signal wires are SDA and SCL, basically data and clock. These signals are open drain (meaning its logic level is either high impedance or low, it cannot ever be high), but there must be a pull-up resistor on each of these signals (we are using the AVR's internal pull-up resistors). This is significant because any device on a TWI bus can drive the signals low at any time, so the signal can only become high when all the devices allow it to become high. This allows devices to detect when the bus is occupied ("arbitration using SDA") and also allow a slow device to dictate the speed of the clock, or even pause a transmission if the slower device is too busy (doing this is called "clock stretching". These facts makes the TWI bus good for communication between a bunch of chips using only two wires.

Every transaction is between a master (the one driving the clock signal) and a slave device. Every transaction starts with a "start condition" and ends with a "end condition". A start condition is when the bus master drives SDA low first, then driving SCL low second. An end condition is when the master releases the TWI bus by releasing SCL and then releasing SDA.

After the start condition, the master has to choose which device to talk to by sending a 7 bit address byte. The 8th (last being sent) bit indicates whether or not the master wishes to read (1) from or write (0) to the slave being addressed. If the master is writing, it will then send more data. If the master is reading, it will release the SDA line so the slave sends data (but the master is still driving the clock). When addressed

All bytes are sent MSB first (most significant bit first). Every byte is optionally ended by an acknowledgement/nacknowledgement. Check the device datasheet to see what the device will expect or will send back. Usually, to quote Wikipedia: "If the master wishes to write to the slave then it repeatedly sends a byte with the slave sending an ACK bit. (In this situation, the master is in master transmit mode and the slave is in slave receive mode.) If the master wishes to read from the slave then it repeatedly receives a byte from the slave, the master sending an ACK bit after every byte but the last one. (In this situation, the master is in master receive mode and the slave is in slave transmit mode.)"

More intricate details are usually specific to a particular device, and such information will come from its datasheet.

When I use I2C/TWI with AVR microcontrollers, I use the low level layer of the "Wire" library for Arduino. The Wire library is the C++ wrapper for the lower level "twi.c" and "twi.h" module, which I modify slighly and compile into my own code (since I don't usually use C++). It takes care of almost everything.

The Wii Classic Controller has a I2C address of 0x52, keep that in mind. Using "twi.c" and "twi.h", to send some data to the Wii Classic Controller, start by creating a byte array containing the data to be sent, and then pass that to the "twi_writeTo" function, along with the destination address, the amount of data to send, and tell it "wait until all data is sent". The code will look like:
unsigned char dataArray[3] = { 'a', 'b', 'c', };
twi_writeTo(0x52, dataArray, 3, 1);

To read three bytes, use the function "twi_readFrom", and tell it the address, the data is saved to a array you pass in, and you specify the amount of data. The code looks like:
unsigned char dataArray[3];
twi_readFrom(0x52, dataArray, 3);

Now do you think it's possible to do this the other way around? Like spoof the classic controller?<br>
Yes, perfectly possible, I have done this already but I re-created a Rock Band drum set<br><br>If you want to see it, go here http://frank.circleofcurrent.com/index.php?page=wii_drum
Oh by the way, the Wii version of Guitar Hero World Tour comes with a drum set that you plug into the Wiimote, which operates very similarly to a Classic Controller (the encryption is the same, the difference is one byte in the ID field and a slightly different data packet format). The library I created allows for any Wiimote extensions to be created. I use a drum as my best example of its usage.
Hello, frank <br>amazing work done by you especially VBUS and USB HID details on your site but i need little help , as i can see that you have attached saleae logic analyzer to analyze the usb bytes i was also trying to do tht but my logic analyzer didnt give me any good results most of them were errors <br>my connection was something like this <br><br>keyboard USB PLUG ----(saleae logic analyzer in parallel with gnd common and D- and D+ connected to 0 and 1 channel ) ----- PC USB port <br><br>but i was aunable to figure about why it didnt work so please help me with its connection so i can implement USB protocol in project
<p>Hi, thanks for the tutorial.</p><p>I'm having trouble in here: </p><p>twi_writeTo(WIIEXT_TWI_ADDR,twiBuffer,7,1);</p><p>It seems program cannot get past this line due to waiting for writing to finish (setting last parameter to 0 lets program continue, however, no communication with classic controller seems to be happening).</p><p>WIIEXT_TWI_ADDR is defined as 0x52</p><p>I'm using Atmel Studio 6.2 to compile and a clone Classic Controller, any idea on what i can try?</p>
<p>You've encoded the analog positions as signed ints from -127 to 127... this is against spec and very unconventional. I'd be interested in hearing if people have had difficulties with this report descriptor configuration on some platforms, as this may be the cause. The spec states that analogs should range from 0 to 255, with 127 as a neutral position. I've checked the report descriptors of several commercial gamepads (made by Microsoft, Logitech and Hori, and with vintages ranging from 2005 to 2012) using USBLyzer, and confirmed that this standard is respected in all cases (though the wired xbox360 actually uses 256, instead of 255 like all the others).<br><br>See:<br><a href="http://www.usb.org/developers/hidpage/Hut1_12v2.pdf" rel="nofollow">http://www.usb.org/developers/hidpage/Hut1_12v2.pd...</a></p>
Why are the gamepad sticks absolute while a mouse is relative? If I press up on my gamepad, surely I am moving up relative to my current position? Pressing up does not (alone) define my position. <br> <br>Thanks for the tutorial :-)
Hello sir ,I am using avrstudio4 for compiling your HID gamepad code and after compiling i am getting error message : <br>dep/usbdrv.c:8: *** target pattern contains no `%'. Stop. <br>sir please help me ,this is my final year project. <br>THANKING YOU IN ANTICIPATION.
Is it possible to remove the middle man and have a controller port coming out of the PC also will it work on a hackintoshi i am a noob when it comes to programing also a noob when it comes to computer hardware?
You must have the &quot;middle man&quot; if you want to use the Wii Classic Controller
im wondering if you know if a usb controll pad can be converted to plug into a wii remote? i have a usb arcade stick and would like to make it wirless by plugging it into a wiimote. is there a way of cutting off the nunchuk plug and wire it up to my arcade stick? <br> <br>thanks
kind of hard, I know how to do it, but is it worth the effort? how skilled are you? what kind of equipment do you have?<br><br>basically you need a microcontroller that can perform USB host duties, and also I2C slave duties. I have already created the code for the I2C stuff. The USB host stuff can either be LUFA if you are using a AT90USB1287 or you can use a &quot;USB host shield&quot; or similar. Or you can dive into ARM but then I don't have the code for it.
Hey! i love your project! but one question... do you think you can compile this on attyin85? similar to the http://hobbyelektronik.org/w/index.php?title=SNES-Joypad
It'll need some major changes. I don't think the ATtiny has dedicated I2C so that has to be changed to bit-banging. It is certainly possible.
wow thats great! i recently finished a nes to usb controller and i loved it. but i would of loved to be able to use a classic controller. But thus im not a avr programer so i dont know much. just enough to mess around a bit with the code.<br><br>but great tutorial! loved it! hopefully one day i can implement this on a attiny85.
Thank you for this project! <br> <br>Not because I've actually used it&hellip; But I copy-pasted this HID Descriptor into my project (that has a quite similar HID with keyboard+mouse), and found that your HID did work, while mine didn't. <br> <br>4 hours later, I finally found the bug in my project. I had written 0x0f where should have been 0x10, somewhere in the middle of my HID descriptor. <br> <br>So, thank you to help me find the typo in my code! :-) <br>I guess you never thought this intructable would be useful for that! :-P
You really put a lot of work into this instructable. Great work! <br><br>I have a question in regards to the format of your instructable. How did you get those dotted borders around your code? It makes the instructable look so neat and orderly.
In the editor, press &quot;view source&quot; to edit your Instructable in HTML (I think this is a &quot;Pro&quot; feature)<br><br><br>The bordered code is done within tags, but with a style attribute that specifies the border style<br><br><br>http://www.w3schools.com/TAGS/tag_pre.asp<br><br>http://www.w3schools.com/css/css_border.asp

About This Instructable




Bio: I am an electrical engineer. I graduated from U of Waterloo. I used to work for Adafruit Industries as an EE. Now I work for ... More »
More by frank26080115:LED Pocket Watch Easy Cord Wrapping Around Power Bricks Using SMD Components on Breadboards 
Add instructable to: