/** \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 #include #include "delay.h" #include "pinio.h" #include "memory_barrier.h" #if defined I2C_MASTER_MODE && defined I2C_SLAVE_MODE #error Cant be I2C master and slave at the same time. #endif #ifdef I2C_SLAVE_MODE #define I2C_MODE 1 #else #define I2C_MODE 0 #endif #define I2C_MODE_MASK 0b00001100 // Start-Addr_R-Read-Stop: just read mode. #define I2C_MODE_SARP 0b00000000 // Start-Addr_W-Write-Stop: just write mode. #define I2C_MODE_SAWP 0b00000100 // Start-Addr_W-WrPageAdr-rStart-Addr_R-Read-Stop. #define I2C_MODE_ENHA 0b00001000 // Transponder is busy. #define I2C_MODE_BUSY 0b01000000 // Transponder is free. #define I2C_MODE_FREE 0b10111111 // Transmission interrupted. #define I2C_INTERRUPTED 0b10000000 // Transmission not interrupted. #define I2C_NOINTERRUPTED 0b01111111 #define I2C_ERROR_BUS_FAIL 0b00000001 #define I2C_ERROR_NACK 0b00000010 #define I2C_ERROR_NO_ANSWER 0b00010000 #define I2C_ERROR_LOW_PRIO 0b00100000 // Address of the device that is communicated with. uint8_t i2c_address; // State of TWI component of MCU. volatile uint8_t i2c_state = I2C_MODE_FREE; /** Wether transmission should be terminated on buffer drain. This also means no new bytes get stuffed into the buffer until this drain happened. It's used to allow distinct transmissions. */ volatile uint8_t i2c_should_end = 0; #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]; #endif /* I2C_SLAVE_MODE */ // Ringbuffer logic for buffer 'send'. #define BUFSIZE I2C_BUFFER_SIZE volatile uint8_t sendhead = 0; volatile uint8_t sendtail = 0; volatile uint8_t sendbuf[BUFSIZE]; #include "ringbuffer.h" /** Inititalise the I2C/TWI subsystem. \param address Address the system should listen to in slave mode, unused when configured for master mode. In master mode, receiver address is given to the send command. This also sets the I2C address. In slave mode it's the address we listen on. In master mode it's the communication target address. As master one can talk to different devices. Call again i2c_init() for changing the target address, then. Doing so won't interrupt ongoing transmissions and overhead is small. */ void i2c_init(uint8_t address) { // In case this is a re-inititalisation, // don't interrupt an ongoing transmission. while (i2c_state & I2C_MODE_BUSY) { delay_us(10); } i2c_address = address; #ifdef I2C_MASTER_MODE #ifdef I2C_ENABLE_PULLUPS SET_INPUT(SCL); PULLUP_ON(SCL); SET_INPUT(SDA); PULLUP_ON(SDA); #endif /* I2C_ENABLE_PULLUPS */ /** 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 TWAR = i2c_address; // We listen to broadcasts if lowest bit is set. TWCR = (0<