--- /dev/null
+/* I2C communication */
+
+#include <stdio.h>
+
+#include <util/twi.h>
+
+#include "i2c.h"
+
+//#define I2C_DEBUG { printf("<0x%02x>", (TWSR & 0xF8)); }
+#define I2C_DEBUG
+
+void i2c_init(void)
+{
+ TWSR = 0; /* Prescaler 1 */
+ TWBR = 12; /* 72 = 100 kHz @ 16 MHz, 12 = 400 kHz @ 16 MHz */
+ TWCR = (1 << TWEN); /* enable I2C pins */
+
+ /* test low address PCF8574 */
+ i2c_write(I2C_ALOW, 0x33); if(i2c_read(I2C_ALOW) != 0x33) while(1);
+ i2c_write(I2C_ALOW, 0x55); if(i2c_read(I2C_ALOW) != 0x55) while(1);
+ i2c_write(I2C_ALOW, 0xAA); if(i2c_read(I2C_ALOW) != 0xAA) while(1);
+ i2c_write(I2C_ALOW, 0xFF); if(i2c_read(I2C_ALOW) != 0xFF) while(1);
+
+ /* test high address PCF8574 */
+ i2c_write(I2C_AHIGH, 0x33); if(i2c_read(I2C_AHIGH) != 0x33) while(1);
+ i2c_write(I2C_AHIGH, 0x55); if(i2c_read(I2C_AHIGH) != 0x55) while(1);
+ i2c_write(I2C_AHIGH, 0xAA); if(i2c_read(I2C_AHIGH) != 0xAA) while(1);
+ i2c_write(I2C_AHIGH, 0xFF); if(i2c_read(I2C_AHIGH) != 0xFF) while(1);
+
+ /* test data PCF8574 */
+ i2c_write(I2C_DATA, 0x33); if(i2c_read(I2C_DATA) != 0x33) while(1);
+ i2c_write(I2C_DATA, 0x55); if(i2c_read(I2C_DATA) != 0x55) while(1);
+ i2c_write(I2C_DATA, 0xAA); if(i2c_read(I2C_DATA) != 0xAA) while(1);
+ i2c_write(I2C_DATA, 0xFF); if(i2c_read(I2C_DATA) != 0xFF) while(1);
+}
+
+static void i2c_start(void)
+{
+ TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); /* START */
+ while(!(TWCR & (1 << TWINT))); /* wait */
+ I2C_DEBUG;
+}
+
+static void i2c_stop(void)
+{
+ TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN); /* STOP */
+ I2C_DEBUG;
+}
+
+uint8_t i2c_read(uint8_t addr)
+{
+ uint8_t data;
+
+ i2c_start();
+ TWDR = (addr << 1) | 0x01; /* target address */
+ TWCR = (1 << TWINT) | (1 << TWEN); /* start transmission */
+ while(!(TWCR & (1 << TWINT))); /* wait until done */
+ I2C_DEBUG;
+ TWCR = (1 << TWINT) | (1 << TWEN); /* read date, NAK */
+ while(!(TWCR & (1 << TWINT))); /* wait until done */
+ data = TWDR;
+ i2c_stop();
+
+ return(data);
+}
+
+void i2c_write(uint8_t addr, uint8_t data)
+{
+ i2c_start();
+ TWDR = (addr << 1); /* target address */
+ TWCR = (1 << TWINT) | (1 << TWEN); /* start transmission */
+ while(!(TWCR & (1 << TWINT))); /* wait until done */
+ I2C_DEBUG;
+ TWDR = data;
+ TWCR = (1 << TWINT) | (1 << TWEN); /* receive data with NAK */
+ while(!(TWCR & (1 << TWINT))); /* wait until done */
+ I2C_DEBUG;
+ i2c_stop();
+}
+