I2C Protocol
The I2C protocol supports sending and receiving data over an Inter-Integrated Circuit (I2C) connection.
Syntax
i2c://hostname:port?option=value,... % Use I2C channel "port" with specified options
Description
The I2C protocol supports sending and receiving data over an I2C connection. It is identified by using i2c as the protocol name in a URI. Appropriate hardware supporting I2C must be present on the system using the protocol.
The hostname in the URI is ignored, if specified. The port is an unsigned integer indicating which I2C port to use. Port 0 is the first I2C port in the system.
The options for the I2C protocol depend on the underlying device-specific I2C protocol used, but these options have been standardized for consistency. The options listed below are the standard options. Some of the options may not be available on some platforms.
The I2C protocol uses a master-slave paradigm. It is a synchronous protocol in which the master supplies the clock, often dubbed SCL, and the slave uses that clock. The master transmits and receives data over the serial data (SDA) line. Multiple slaves may be connected and are selected by the master using a 7-bit or 10-bit slave address. The slave address is transmitted as part of the I2C protocol.
Slave Address
The slave address is specified through the address option of the I2C URI. Hence, each URI uniquely identifies a single slave device on the I2C bus attached to a particular port.
Therefore, each slave device requires its own communication channel and its own stream_connect call.
Unlike a serial port, more than one communication stream can be opened on the same I2C port. Each communication stream should have a unique slave address configured via the address option of its URI. |
Note that the slave address is not the same as the port. Just as the port of a serial URI determines the COM port over which serial communications are performed, so the port of the I2C URI determines which I2C port will be used in systems that support more than one I2C port. If there are multiple I2C devices attached to one port then each one of those slave devices will have its own address on that port.
Slave addresses are generally predetermined by the manufacturer of the slave device and are assigned by NXP Semiconductors. In order to support more than one slave device of the same type, slaves usually allow some of the least-significant bits of the address to be set via pins on the device.
The I2C protocol is a two-wire protocol. There are no read or write lines because a read/write bit is transmitted along with the slave address as part of the I2C protocol. Handling of the slave address and read/write bit is all done internally by the I2C driver.
Baud Rate
The baud rate used by the I2C master is determined by the baud option of the URI. Standard baud rates for I2C are:
Baud Rate |
Description |
---|---|
100 kHz |
Original speed. |
400 kHz |
Fast mode (Fm). |
1 MHz |
Fast mode plus (Fm+). |
3.4 MHz |
High-speed mode (Hs). |
5 MHz |
Ultra-Fast mode (UFm). Requires USDA and USCL lines, which do not use pull-up resistors. |
Most devices only support the original 100 kHz mode or the 400 kHz Fast mode.
Data transmitted by QUARC over an I2C connection is always sent eight bits at a time, with an acknowledgement after each byte. The standard requires that the most-significant bit of each byte be transmitted first. When sending or receiving words consisting of more than one byte, the order of the bytes is slave-dependent. The standard byte-ordering options of the Stream API may be used to automatically re-order the bytes if necessary so that 16-bit or 32-bit words may be sent or received even when the byte-ordering of the slave device does not match the native byte-ordering of the QUARC target.
The byte ordering may be configured using the byte_order argument of the stream_set_byte_order function, for example.
Writing to an I2C Device
A sample transaction on the I2C bus is shown below:
The transaction begins with a START bit (shaded green) and is followed by a 7-bit slave address and a direction bit (labelled R
).
For a write operation, the direction bit is set to 0 to indicate a write. The slave acknowledges (ACK) the receipt of the
address and direction bit and then the master provides the first byte of data. This initial byte is typically the offset of
a register within the slave device. The slave acknowledges the receipt of this byte and then the master sends the actual data
byte that will be written to the selected register in the slave. This byte too is acknowledged by the slave and then a STOP
bit (shaded red) is sent by the master to complete the transaction and release the I2C bus. Any number of bytes may be written
per transaction before the STOP bit. When multiple bytes are written the slave typically auto-increments the initial register
offset and writes each data byte to successive registers. The table below shows a typical multi-byte write transaction:
Step |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
---|---|---|---|---|---|---|---|---|---|---|
Master |
START |
ADDR+W |
|
REG |
|
DATA |
|
DATA |
|
STOP |
Slave |
|
|
SACK |
|
SACK |
|
SACK |
|
SACK |
|
where:
START |
= |
The START bit which begins an I2C transaction on the bus or a repeated START bit which indicates a new slave address and direction bit being sent. |
ADDR+W |
= |
The slave address (predetermined by device manufacturer and optional address pins) plus the write bit (0). |
SACK |
= |
The slave acknowledgement of the byte received by the slave. |
REG |
= |
The offset of the slave register to which to write the data. |
DATA |
= |
Data to write to the slave register, or successive registers. |
STOP |
= |
The STOP bit which ends the I2C transaction on the bus. |
Such a write transaction can be performed using a stream_send, or one of its variants, followed by a stream_flush.
Reading from an I2C Device
A sample transaction on the I2C bus is again shown below:
The transaction begins with a START bit (shaded green) and is followed by a 7-bit slave address and a direction bit (labelled R
).
For a read operation, the direction bit is set to 1 to indicate a read. The slave acknowledges (ACK) the receipt of the
address and direction bit and then the slave provides the first byte of data. The master acknowledges the receipt of this
byte and then the slave sends the next byte of data. When the master receives the last byte it requires then it responds
with a negative acknowledgement to indicate that the slave should not send any more data, and then a STOP
bit (shaded red) is sent by the master to complete the transaction and release the I2C bus. Any number of bytes may be read
per transaction before the STOP bit. A simple read operation in which a single byte is read is depicted in tabular form below:
Step |
0 |
1 |
2 |
3 |
4 |
5 |
---|---|---|---|---|---|---|
Master |
START |
ADDR+R |
|
|
NMACK |
STOP |
Slave |
|
|
SACK |
DATA |
|
|
or for reading multiple bytes in the same transaction:
Step |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
---|---|---|---|---|---|---|---|---|---|---|
Master |
START |
ADDR+R |
|
|
MACK |
|
MACK |
|
NMACK |
STOP |
Slave |
|
|
SACK |
DATA |
|
DATA |
|
DATA |
|
|
where:
ADDR+R |
= |
The slave address (predetermined by device manufacturer and optional address pins) plus the read bit (1). |
MACK |
= |
Master acknowledgement of the byte received by the slave. Indicates the master received the byte and expects more bytes from the slave. |
NMACK |
= |
No master acknowledgement of the last byte received by the slave to signal the slave that no more bytes will be read. |
These read transactions may be performed using the stream_receive function, or one of its variants, to receive data from the stream. The byte ordering is configured using the stream_set_byte_order or stream_set_swap_bytes function.
Reading Using a Combined Message from an I2C Device
Reading from an I2C device is typically more complicated than the read transactions in the previous section. For many slave devices, reading from a register within the slave devices involves a write operation to tell the slave which register is being read, followed by a read operation, all combined into a single I2C transaction. A typical combined write-read transaction is depicted below:
Step |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
---|---|---|---|---|---|---|---|---|---|---|---|
Master |
START |
ADDR+W |
|
REG |
|
START |
ADDR+R |
|
|
NMACK |
STOP |
Slave |
|
|
SACK |
|
SACK |
|
|
SACK |
DATA |
|
|
or for reading multiple bytes in the same combined write-read transaction:
Step |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Master |
START |
ADDR+W |
|
REG |
|
START |
ADDR+R |
|
|
MACK |
|
MACK |
|
NMACK |
STOP |
Slave |
|
|
SACK |
|
SACK |
|
|
SACK |
DATA |
|
DATA |
|
DATA |
|
|
The key thing to note about these transactions is that the master has exclusive access to the I2C bus as long as the STOP bit has not been sent. Transmitting the STOP bit releases the I2C bus so that other masters on the bus can perform their own transactions, since the I2C bus is a multi-master serial bus.
But how does the Stream API reproduce these combined transactions on the I2C bus? Writing to the stream using a stream_send function, for example, followed by a stream_flush, will send all the bytes in the signal at its input to the I2C bus in a single I2C multi-byte write transaction, which is terminated by a STOP bit. Hence, writes to the slave device are simple and straightforward.
Invoking a stream_receive function reads from the slave device, but it does not
do the initial write of the slave register offset. What is required is a combination of the write and read into a single I2C bus transaction. To do so,
use the stream_set_boolean_property function with the STREAM_PROPERTY_IS_EXCLUSIVE
property to gain exclusive access to the I2C. Then use one of the stream_send functions to set the register offset.
Next use one of the stream_receive functions to read the data, and finally, release exclusive access to
the I2C bus by making another call to the stream_set_boolean_property function.
Combining Operations for an I2C Device
The following table shows the required sequence of events for the typical read transactions illustrated above.
Step |
Operation |
Description |
---|---|---|
1 |
Stream Set Property |
Set the STREAM_PROPERTY_IS_EXCLUSIVE property to |
2 |
Stream Write |
Write the register offset as a uint8. Sometimes one bit of this offset is used to indicate whether the register offset should be auto-incremented when multiple values are read. |
3 |
Stream Read |
Read the contents of the slave register using whatever data type is appropriate (often int8 or int16). Note that multiple values may be read at the same time if the slave supports it. |
4 |
Stream Set Property |
Set the STREAM_PROPERTY_IS_EXCLUSIVE property to |
Handling Multiple Data Types
Sometimes the data read from or written to a slave device involves a combination of different data types. For example, with the L3GD20 gyroscope one might be reading the Status Register (a uint8), the Temperature (an int8) and three axes (three int16s) in a single call transaction. Multiple stream_send and/or stream_receive calls may be performed while hold exclusive access to the I2C bus to handle such situations.
Limitations
Performance
The performance of the I2C protocol depends on the performance of the underlying I2C device. Be sure to check the capabilities of your underlying hardware. Rates of 400 kHz are typical. Signal integrity issues also affect the maximum baud rate achievable. For example, at high rates the capacitance of the lines can slow down the signals and limit the baud rate attainable particularly since the I2C protocol uses open-drain clock and data lines with resistive pullups.
Also note that the baud rate refers to the number of bits transferred per second and not the number of bytes. The number of bytes per second is usually less than 1/9th of the baud rate due to the overhead (albeit small) of the protocol.
QUARC Target Manager
The I2C protocol cannot be used for communicating with the target (via a target URI) because the I2C protocol does not allow multiple connections on the same port. Nor should it be used as a model URI.
Options
mode
The mode option configures the I2C device providing I2C services as either a master or slave. Valid values for this option are "master" or "slave" accordingly. The default mode is generally the "master" mode.
address
The address option specifies the address of the slave device with which the stream will be communicating. The address may be specified in hexadecimal by adding an '0x' prefix, such as '0x48', or in binary by adding an '0b' prefix, such as '0b1001000'. Slave addresses are 7-bit or 10-bit. If the data sheet for the slave device provides an 8-bit "address" then it is including the read/write bit as part of the address. In that case, only provide the upper 7 bits of the "address" since the read/write bit is handled automatically by the I2C protocol driver.
baud
The baud option specifies the frequency of the I2C clock (SCL) in Hertz. For slave devices, the I2C clock rate is determined by the master, but it should still be configured, in case the rate is used to configure oversampling or filtering.
The baud rate determines the number of bits transferred per second, not the number of bytes. The default baud rate depends on the underlying I2C device. Baud rates of 100 kHz and 400 kHz are generally supported, but some devices may support the higher rates.
delay
The delay option specifies the delay in seconds between the I2C data line (SDA) and the edge of the I2C clock (SCL). Normally this option need not be specified, because the default value is suitably chosen by the protocol based on the baud rate. However, the default can be overridden by specifying this option if necessary.
The only target which currently supports this option is the QUARC Linux x64 target. Valid values range from 0 to 280e-9 (280 ns).
memsize
The memsize option determines the size of the send and receive buffer (in bytes) used for I2C transfers. This size determines the maximum number of bytes that can be transferred in one send or receive operation. It is not the same as the Stream API's send and receive buffers but is used in interfacing with the low-level drivers that implement the I2C protocol. The default buffer size depends on the underlying I2C device. Setting this option is equivalent to setting both the rcvsize and sndsize options at the same time.
rcvsize
The rcvsize option determines the size of the receive buffer (in bytes) used for I2C transfers. This size determines the maximum number of bytes that can be transferred in one receive operation. It is not the same as the Stream API's receive buffers but is used in interfacing with the low-level drivers that implement the I2C protocol. The default buffer size depends on the underlying I2C device.
sndsize
The sndsize option determines the size of the send buffer (in bytes) used for I2C transfers. This size determines the maximum number of bytes that can be transferred in one send operation. It is not the same as the Stream API's send buffers but is used in interfacing with the low-level drivers that implement the I2C protocol. The default buffer size depends on the underlying I2C device.
Driver
The driver supporting the I2C protocol is called qrt_i2c
.
Targets
Target |
Supported |
Comments |
---|---|---|
No |
Not currently supported. |
|
No |
Not currently supported. |
|
Yes |
Fully supported. |
|
No |
Not currently supported. |
|
No |
Not currently supported. |
|
No |
Not currently supported. |
|
Yes |
Fully supported. |
|
No |
Not currently supported. |
|
No |
Not currently supported. |
|
Yes |
Fully supported. |
|
Yes |
Fully supported. |
|
Yes |
Fully supported. |
|
No |
Not currently supported. |
|
No |
Last fully supported in QUARC 2018. |
See Also
Copyright ©2024 Quanser Inc. This page was generated 2024-10-17. Submit feedback to Quanser about this page.