Table of Contents > QUARC > User's Guide > QUARC Communications Protocols
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 Call block or Stream Connect block in QUARC or stream_connect call in MATLAB.
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. The QUARC I2C Multiple Devices Demo example illustrates multiple devices sharing the same I2C port. |
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 ordering option of the Stream Call block, 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 Write block, configured to minimize latency (so that it always flushes the underlying stream buffer to the I2C bus). The input to the Stream Write block would be a 3-vector of uint8 elements containing the offset of the slave register, REG, followed by the two data bytes i.e. uint8([REG DATA DATA]). In the C language, a stream_send, or one of its variants, followed by a stream_flush is required.
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 a Stream Read block. For the single byte read
shown above, the Output data type parameter of the Stream Read block would be set to uint8
or int8 and the Dimensions parameter would be set to 1
. Multiple bytes or different data types
could be received by changing these two parameters appropriately. Note that if data types other than boolean, int8
or uint8 are being read then the byte order (which byte is the most-significant) will be interpreted according to the
Byte ordering parameter of the Stream Call or
Stream Connect block that created the stream. In the C language, the
stream_receive function, or one of its variants, is used to receive data from the stream.
The byte ordering is configured using the stream_set_byte_order
or stream_set_swap_bytes function.
For an example that uses both the Stream Write and Stream Read blocks to interface to an I2C device, refer to the QUARC I2C Temperature Sensor Demo.
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 Write block, for example, configured to minimize latency, 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.
When using the Advanced Stream blocks, such as Stream Send, the data will not be written to the I2C bus until the stream is flushed using the Stream Flush block. The Stream Write block combines these two blocks into one when it is configured to minimize latency. |
Invoking the Stream Read block 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. There are two ways to combine a write and read operation into a single I2C transaction, as illustrated above. The easiest way is to use the Stream Write-Read block, which performs just such a transaction. The register offset is fed to the block's input and the value of the register is read at the block's output. The Output data type and Dimensions parameters should be set according to the data being read.
For an example that uses both the Stream Write and Stream Write-Read blocks to interface to an I2C device, refer to the QUARC I2C Gyroscope Demo.
Combining Operations for an I2C Device
A lower-level, but more flexible, technique requires using a Stream Write followed by a Stream Read, while exclusive access has been acquired for the I2C bus.
Exclusive access to the I2C bus is obtained using the Stream Set Property block. By using the Stream Set Property
block to set the boolean STREAM_PROPERTY_IS_EXCLUSIVE property to true
, exclusive access is gained to the I2C bus. All read and writes to the stream
while exclusive access has been obtained will be combined into a single I2C bus transaction. When the combined message is complete, the I2C bus must be released again by
setting the STREAM_PROPERTY_IS_EXCLUSIVE property to false
with another Stream Set Property block.
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 |
This technique is exactly what the Stream Write-Read block does under the hood. However, it is more flexible because any combination of Stream Write and Stream Read blocks may be used while exclusive access to the bus has been acquired to perform more complex I2C combined messages.
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 to the Stream Write-Read block.
The best way to handle this situation is to use a Bus Object. Using a Bus Object allows the data to be read directly as the data types desired and to be output as a bus containing the expected values. It also handles byte order correctly. A Simulink Bus is essentially equivalent to a C structure, with each element of the bus corresponding to a field in the structure. Refer to Using Bus Objects with QUARC for more details on how to use bus objects to read mixed data types. An example using a bus object to read mixed data types from an I2C digital output gyroscope is provided by the QUARC I2C Gyroscope Mixed Types Demo.
Another way to handle this situation is to read data as a vector of bytes and then use the
MATLAB Command Line
Click to copy the following command line to the clipboard. Then paste it in the MATLAB Command Window:
doc('Demux');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.
Link to this page.