Basic TWI hardware interface notes


Click to download example code

***Warning, messy code, not particularly useful***

See other sample programs on this site for more "gerneral" code

This program is very simple. It merely uses the Mega32 to connect to the DS1307 RTC (Real Tme Clock) via hardware TWI, reset the second's field to 00 and continually read back the second's value displaying it on the serial port. The Procyon library is used for UART communications but not for I2C (TWI). You might need to change the location of the Procyon header files to get the code to compile for you. You also might need to modify the makefile SRC = directive if that is the case.


The DS1307

See the DS1307 datasheet

The DS1307 remembers what register was last accessed and will send the data in that register if asked to send data. That is why the program acess 0x00. As you can see from the table taken from the datasheet below, register 0x00 (00H) contains the seconds information. If we wanted to read / write minutes instead we would access register 0x01 (01H).

Make sure you read through the DS1307 datasheet, otherwise some areas of the I2C (TWI) code might be confused with DS1307 specific items.

Time keeping registers of theDS1307 (from datasheet)

Also note that the DS1307 outputs data in BCD (Binary coded decimal) this means you need to display the output as hex if you want 60 seconds to a minute. Displaying it as decimal will result in it displaying counting up to 96 before resetting to 00.


TWI (I2C) hardware operation

See Atmel appnote 315 and the datasheet for the Mega32 (see the TWI section).


In addition to the above documents I will just give a few quick notes on hardware I2C (my code has lots comments and they are the real source of information from me). Basically the code works on 2 registers, TWSR (Status Register) and TWCR (control register) as well TWDR and TWBR occasionally. Here is the process of how this program writes a byte to a slave device.

Send a START condition by setting three bits in the TWCR register.

TWCR = (1<<TWINT) | (TWSTA) | (1<<TWEN);

Wait until the the TWINT bit is set by the hardware. TWINT is found in the TWCR register

while(!((TWCR&0x80)==0x80)) {}

See if a START condition was found on the bus (display an error if there was one)

if(!((TWSR&0xF8)==START)) {rprintf("\r\n**********E R R O R - START not set***********"); }

Set the TWDR to reflect the address of the TWI slave device


Then tell the TWI hardware to start opearations by setting the TWEN bit in the TWCR register

TWCR = (1<<TWINT)|(1<<TWEN);

Wait until the the TWINT bit is set by the hardware. TWINT is found in the TWCR register

while(!((TWCR&0x80)==0x80)) {}

Check that the slave acknowledged the byte (mask TWSR against 11111000, and see if ACK bit set or not)

if(!((TWSR&0xF8)==MT_SLA_ACK)) { rprintf("\r\n**********E R R O R - Slave Address sending not complete***********"); }

If this was all, you'd need to send a STOP condition etc but you can see how the whole app works by looking at the code



The whole thing is gloriously simple once you get to grips with it. I have deliberately not wrapped my code in layers of function calls so as to allow everyone to see exactly what is going on at each stage and understand it all.

Any questions or suggestions please email me or discuss it on the forum



Website subject to copyright. No unauthorised distribution.