/** \file \brief I2C / TWI subsystem "TWI", "Two Wire Interface", is Atmel's name for the (patented) I2C bus system. I2C is technically pretty sophisticated, it also takes the current state of these two wires as part of the protocol into account. Like SPI it's a master/slave system with a clock signal on the wire. Unlike SPI, communication partners aren't choosen by setting a pin, but by by transferring an address byte before the actual data. Accordingly, code has to deal with states, transmissions have a start and an end, and actions on the bus can result in different states, like success or failure. avr-libc comes with good sample code: http://www.nongnu.org/avr-libc/examples/twitest/twitest.c For technical details see section 22 of atmega328 datasheet. */ #include "i2c.h" #ifdef I2C #include #include #if defined I2C_MASTER_MODE && defined I2C_SLAVE_MODE #error Cant be I2C master and slave at the same time. #endif // Address of the device that is communicated with. uint8_t i2c_address; // State of TWI component of MCU. volatile uint8_t i2c_state; // Index into the send/receive buffer. uint8_t i2c_index; // Count of bytes to be sent. uint8_t i2c_byte_count; #ifdef I2C_EEPROM_SUPPORT // For SAWSARP mode (see ENHA in i2c.h). uint8_t i2c_page_address[I2C_PAGE_ADDRESS_SIZE]; // Index into the page address buffer. uint8_t i2c_page_index; // Count of bytes in page address. uint8_t i2c_page_count; #endif /* I2C_EEPROM_SUPPORT */ #ifdef I2C_SLAVE_MODE uint8_t i2c_in_buffer[I2C_SLAVE_RX_BUFFER_SIZE]; uint8_t i2c_out_buffer[I2C_SLAVE_TX_BUFFER_SIZE]; #else uint8_t *i2c_buffer; #endif /* I2C_SLAVE_MODE */ I2C_HANDLER i2c_master_func = &i2c_do_nothing; I2C_HANDLER i2c_slave_func = &i2c_do_nothing; I2C_HANDLER i2c_error_func = &i2c_do_nothing; void i2c_init(uint8_t address, I2C_HANDLER func) { i2c_address = address; #ifdef I2C_MASTER_MODE #ifdef I2C_ENABLE_PULLUPS I2C_DDR &= ~((1 << I2C_SCL_PIN) | (1 << I2C_SDA_PIN)); I2C_PORT |= (1 << I2C_SCL_PIN) | (1 << I2C_SDA_PIN); #endif /* I2C_ENABLE_PULLUPS */ i2c_master_func = func; /** TWI Bit Rate register SCL_freq = CPU_freq / (16 + 2 * TWBR) See: page 235 of atmega328 datasheet. */ TWBR = ((F_CPU / I2C_BITRATE) - 16) / 2; /** TWI Status Register Lower two bits set the prescaler value. See: page 236 of atmega328 datasheet. */ TWSR = 0x00; #endif /* I2C_MASTER_MODE */ #ifdef I2C_SLAVE_MODE i2c_slave_func = func; TWAR = i2c_address; // We listen to broadcasts if lowest bit is set. TWCR = (0<