I2C (Inter-Integrated Circuits), as it's name suggests, is a bus standard for allowing IC's to talk to each other.
I2C is not very difficult to implement at all. Some Micro Controllers, such as the 80C552, and the BS2p, have I2C support built in, and it's a simple matter of calling the appropriate built in commands. But others (like the BS2) do not have native support for I2C.
Not to worry! I'll attempt to show you how to get I2C working with this page. Before we get in to the sample circuits and software, a little explanation of how I2C works is needed.
I2C is a two wire protocol, and requires the following basic elements:
Bytes are sent MSB first
EXAMPLE CIRCUITS AND SOFTWARE:
To write an "A" to address 0 of an EEPROM who's device address is 011, the protocol would be as follows:
The above is represented in the figure below
To read from address 0 of the EEPROM:
The protocol is a little different to writing.
The above is represented in the figure below

As you can see, it's very easy to wire up an I2C device. Pins 1 to 3 of the 24LC02 (2kb EEPROM - 256Bytes) determine the IC's address. Then there is SCL and SDA (Serial Clock and Serial Data). /WR isn't used in this case, but if it is high it will prevent accidental writes to the Chip (unwired, it is held low internally). To add more I2C devices (eg - more EEPROM), simply tie them to SDA and SCL, and set the address pins to a different address. The Outputs of I2C chips are open drain, so you will need the pull up resistors.
The code is approached in two parts. The first program stores the message "Lennard Electronics www.lennard.net.nz" in the EEPROM.
There are a few debug routines so we can see what is happening (eg - Acknowledges, and to check that the bytes are converted to serial data correctly).
The second program reads the EEPROM, and displays the message in the debug window. Again, there are a few debug routines so we can see what is going on.
Some notes:
The code is a simple demonstration of getting I2C to work. Ideally, code should be added to act upon a NO Acknowledge condition (example, the eeprom may be busy writing internal data to it's memory cells, and the Master may therefore have to resend a byte). At this point in time, though, a pause for 10 milliseconds works fine as that is the longest time it takes for the eeprom to write to all it's cells.
|
'{$STAMP BS2} 'I2C test program.
28/8/2002 Ben Lennard 'CONSTANTS 'VARIABLES Company DATA
"Lennard Electronics" 'MAIN CODE Send_to_bus: 'Check for
Receiver Acknowledge 'Start Procedure.
Set start condition on bus: SDA Hi-Lo while SCL Hi 'Stop Procedure.
Set stop condition on bus: SDA Lo-Hi while SCL Hi 'Write Address/Data
Procedure |
Screen shot of debug screen:
|
'{$STAMP BS2} 'I2C test program.
28/8/2002 Ben Lennard 'CONSTANTS 'VARIABLES DIRS = %1100001111111111 'MAIN CODE 'Check for
Receiver Acknowledge - not really needed in this example... 'Start Procedure.
Set start condition on bus: SDA Hi-Lo while SCL Hi 'Stop Procedure.
Set stop condition on bus: SDA Lo-Hi while SCL Hi 'Write Address/Data
Procedure |
Screen shot of debug screen:
After looking at the code above, and thinking how to optimise the code, the thought occurred that I could save memory space in the BS2, simplify the code, and make eeprom reads and writes faster if I were to use shiftout and shiftin for sending the bytes down the line, rather than using the for loops and a Mask byte. The For loops and Mask byte were adapted from a Pascal program I used to talk to a PCF8574 a few years ago using a 68HC11, but it makes sense to use shiftin and shiftout with the Stamp. For example, (and you will see it in the Serial to Parallel bus example below), the Write_data routine above can be simplified to this:
|
IMPORTANT NOTE: Using Shiftin and Shiftout, there is the risk that a bus short could occur (example, if the I2C chip takes a line low, while the Stamp is outputting a High). One solution, that I can think of, would be to put a 220R resistor in series with each pin from the stamp, so that if there is a short, the current will be limited to below the maximum that the Stamp's pins can handle.
Serial to Parallel conversion using a PCF8574A.
The 74HC245 is a bidirectional buffer. I use the buffer circuit to monitor the ports on my bread board prototypes, without loading them. You can connect the LEDs directly to the PCF8574A, but you will need to make sure total power dissipation of the PCF8574A is no more than 400mW.
The code simply displays the byte sent to the PCF8574A on 8 LEDs. Starting from 00000000 to 11111111.
|
'{$STAMP BS2} 'I2C test program.
4/9/2002 Ben Lennard 'CONSTANTS 'VARIABLES DIRS = %1111111111111111 'Start Procedure.
Set start condition on bus: SDA Hi-Lo while SCL Hi 'Stop Procedure.
Set stop condition on bus: SDA Lo-Hi while SCL Hi 'Write Address/Data
Procedure |
This example uses the Philips PCF8583 Real Time Clock chip (RTC) and a Matrix Orbital Graphics LCD (122 x 32 pixels). Talking to the PCF8583 is very similar to the EEPROM examples above.
The PCF8583 is, basically, a 256byte RAM chip, hence it's ID code is the same as for an EEPROM (1010).
The only differences are:
Setting up the time, and reading the time, is a simple matter of reading and writing the appropriate memory locations.
The PCF8583 also understands leap years (if the year counter = 0, it's a leap year).
The RTC Circuit:

The BS2sx Circuit:

Circuit Notes:
i. I constructed the RTC circuit on a veroboard. The battery is mounted on the component side, and the components soldered "surfacemount style" on the copper side. That way, it becomes a useful module that I can reuse for future breadboarding of projects, rather than the RTC circuit taking up valuable space on the breadboard. The Matric Orbital's SDA and SCL lines are connected to the same points as the RTC's SDA and SCL lines.
ii. C1 and C2 are needed to compensate for stray capacitance and to ensure a stable supply rail. C1 should be in the range of 5pF to 25pF. The value of C1 depends on your component placing and trace layout. I kept the tracks short on the Veroboard, with the Crystal connected right up next to the IC. Without C1, the circuit gained 5 seconds a minute. With C1, it is spot on.
iii. The backup battery is a Rayovac Alkaline "841". I had great difficulty finding any information about it on Rayovac's web site - mainly because their site is terrible to navigate. However, Apple Computer uses this battery in some of their Macs. You can easily get one, just go to any Apple reseller (in New Zealand go to MagnumMac), and ask for a PRAM battery - part number 922-0750. Cost is about $25NZ plus GST.
iv. D1 prevents the battery from powering the other circuitry that the RTC may be connected to, and therefore going flat very quickly. D2 prevents the backup battery from being charged by the main supply. The RTC has data retention with Vdd down to *1V, so the Rayovac can be drained to 1.7V (1V plus the voltage drop of the diode of 0.7V) before it needs replacing - about 3 or 4 years. Using a more elaborate circuit, for example, one that disconnects the battery when Vdd is being supplied by the main power system, the battery will last a lot longer.
*Vdd must be 2.5V minimum when the chip is talking to other parts of the circuitry.
v. I've created and used various fonts for use on the display. You can read up on the Matrix Orbital website on how to do this, or just modify the code to talk to a normal 20 x 2 character LCD from Matrix Orbital (it's not hard). A quick intro on how to drive a Matrix Oribital Display using I2C is here.
The Code is here. It just fits in to a 2k space on the BS2sx's eeprom (95%). The code allows display of the date and time. Year is adjustable from 2000 to 2049, and leap years are accounted for as well. It is fully functional, but could do with some cleaning up. You can save about 12% of EEPROM space by using the RS232 port of the display to talk to it, rather than including it in the I2C comms. Just connect it's RX pin to the Stamps Sout pin, and use the code here.