Inter-Integrated Circuit (I2C)
- As the name suggests, Inter-IC (or the Inter-Integrated Circuit), often shortened as I2C (pronounced eye-two-see), I2C (pronounced eye-squared-see), or IIC, was developed as a communication protocol to interact between different ICs on a motherboard, a simple internal bus system.
- It is a revolutionary technology developed by Philips Semiconductor (now NXP Semiconductors) in 1982, and is used to connect low speed peripherals (like keyboard, mouse, memory, IO/serial/parallel ports, etc.) to the motherboard (containing the CPU) operating at much higher speed.
- These days you can find a lot of devices which are I2C compatible manufactured by a variety of companies (like Intel, TI, Freescale, STMicroelectronics, etc).
- The Inter-integrated Circuit (I2C) Protocol is a protocol intended to allow multiple “slave” digital integrated circuits (“chips”) to communicate with one or more “master” chips.
- Like the Serial Peripheral Interface (SPI), it is only intended for short distance communications within a single device.
- Like Asynchronous Serial Interfaces (such as RS-232 or UARTs), it only requires two signal wires to exchange information.
- I2C bus is used by many integrated circuits and is simple to implement.
- Any microcontroller can communicate with I2C devices even if it has no special I2C interface.
I2C terminology
- Transmitter This is the device that transmits data to the bus
- Receiver This is the device that receives data from the bus
- Master This is the device that generates clock, starts communication, sends I2C commands and stops communication
- Slave This is the device that listens to the bus and is addressed by the master
- Multi-master I2C can have more than one master and each can send commands
- Arbitration A process to determine which of the masters on the bus can use it when more masters need to use the bus
- Synchronization A process to synchronize clocks of two or more devices
This resulted in few upgrades to the standard-mode I2C specifications:
- Fast Mode – supports transfer rates up to 400 kbit/s
- High-speed mode (Hs-mode) – supports transfer rates up to 3.4 Mbit/s
- 10-bit addressing – supports up to 1024 I2C addresses
The before mentioned reference design is a bus with a clock (SCL) and data (SDA) lines with 7-bit addressing. The bus has two roles for nodes: master and slave:
Master node — node that generates the clock and initiates communication with slaves
Slave node — node that receives the clock and responds when addressed by the master
The bus is a multi-master bus which means any number of master nodes can be present. Additionally, master and slave roles may be changed between messages (after a STOP is sent).
There may be four potential modes of operation for a given bus device, although most devices only use a single role and its two modes:
master transmit — master node is sending data to a slave
master receive — master node is receiving data from a slave
slave transmit — slave node is sending data to the master
slave receive — slave node is receiving data from the master
example of the I²C protocol as an I²C master:
// Hardware-specific support functions that MUST be customized: #define I2CSPEED 100 void I2C_delay(void) { volatile int v; int i; for (i=0; i < I2CSPEED/2; i++) v; } bool read_SCL(void); // Set SCL as input and return current level of line, 0 or 1 bool read_SDA(void); // Set SDA as input and return current level of line, 0 or 1 void clear_SCL(void); // Actively drive SCL signal low void clear_SDA(void); // Actively drive SDA signal low void arbitration_lost(void); bool started = false; // global data void i2c_start_cond(void) { if (started) { // if started, do a restart cond // set SDA to 1 read_SDA(); I2C_delay(); while (read_SCL() == 0) { // Clock stretching // You should add timeout to this loop } // Repeated start setup time, minimum 4.7us I2C_delay(); } if (read_SDA() == 0) { arbitration_lost(); } // SCL is high, set SDA from 1 to 0. clear_SDA(); I2C_delay(); clear_SCL(); started = true; } void i2c_stop_cond(void){ // set SDA to 0 clear_SDA(); I2C_delay(); // Clock stretching while (read_SCL() == 0) { // add timeout to this loop. } // Stop bit setup time, minimum 4us I2C_delay(); // SCL is high, set SDA from 0 to 1 if (read_SDA() == 0) { arbitration_lost(); } I2C_delay(); started = false; } // Write a bit to I2C bus void i2c_write_bit(bool bit) { if (bit) { read_SDA(); } else { clear_SDA(); } I2C_delay(); while (read_SCL() == 0) { // Clock stretching // You should add timeout to this loop } // SCL is high, now data is valid // If SDA is high, check that nobody else is driving SDA if (bit && read_SDA() == 0) { arbitration_lost(); } I2C_delay(); clear_SCL(); } // Read a bit from I2C bus bool i2c_read_bit(void) { bool bit; // Let the slave drive data read_SDA(); I2C_delay(); while (read_SCL() == 0) { // Clock stretching // You should add timeout to this loop } // SCL is high, now data is valid bit = read_SDA(); I2C_delay(); clear_SCL(); return bit; } // Write a byte to I2C bus. Return 0 if ack by the slave. bool i2c_write_byte(bool send_start, bool send_stop, unsigned char byte) { unsigned bit; bool nack; if (send_start) { i2c_start_cond(); } for (bit = 0; bit < 8; bit++) { i2c_write_bit((byte & 0x80) != 0); byte <<= 1; } nack = i2c_read_bit(); if (send_stop) { i2c_stop_cond(); } return nack; } // Read a byte from I2C bus unsigned char i2c_read_byte(bool nack, bool send_stop) { unsigned char byte = 0; unsigned bit; for (bit = 0; bit < 8; bit++) { byte = (byte << 1) | i2c_read_bit(); } i2c_write_bit(nack); if (send_stop) { i2c_stop_cond(); } return byte; }
No comments:
Post a Comment