I2C Overview
I²C or I2C is a two-wire synchronous serial protocol typically used to send data between chips. I2C is considered an advanced topic. A good knowledge of the protocol is recommended. Troubleshooting may require a logic analyzer or oscilloscope. We recommend users inexperienced with I2C purchase our LJTick-DAC and get I2C working with it before attempting configuration with a third-party sensor. LabJack does not typically provide support for specific I2C sensors beyond clarifying the necessary I2C configuration steps. Some general troubleshooting guidance can be found below, including two useful troubleshooting utilities. See the attached "I2C_Test_Utilities.zip" at the bottom of the page (Windows only).
T-series I2C Support
T-series devices support master-mode Inter-Integrated Circuit (I²C or I2C) communication. Two digital IO are required to act as clock (SCL) and data (SDA). Any T-series digital I/O line can be SDA or SCL.
The I²C bus generally requires pull-up resistors of perhaps 4.7 kΩ from SDA to VS and SCL to VS.
EIO and CIO digital I/O lines should be used, instead of the FIO lines, due to the extra lower output impedances on those lines. Look at the Digital I/O Specifications page for more details.
Lua scripting is often convenient for serial applications. For example, a script can run the serial communication at a specified interval, and put the result in USER_RAM registers. The host software can read from the USER_RAM registers when convenient. This puts the complications of serial communication in a script running on the T-series device. The I²C Sensor Lua examples contain several serial communication examples.
This I²C bus is not an alternative to the USB connection. Rather, the host application will write/read data to/from the LabJack, and the LabJack will communicate with some other device using I²C.
Data Rates
I²C is done in command-response mode, either from a host application or an on-board Lua script. Throughput can be estimated by looking at the bit rate (I2C_SPEED_THROTTLE) and number of bits to transfer, and for external host communication adding the packet overhead estimates from the beginning of Appendix A-1. A further consideration is how much you can fit in 1 packet or whether multiple packets will be required.
Clock Stretching
T-Series devices support clock stretching. When a slave device needs more time to complete an operation it can use clock stretching to pause the bus. T-Series devices will allow up to 1000 clock periods of clock stretching. If a slave device needs more time, a slower clock speed should be used.
How-To
Running an I2C operation on a T-series device requires:
- Initial configuration.
- Transmit load data.
- Specify the number of bytes to read.
- Execute the I²C operations.
- Read the data that was read from the slave device, if any.
- Debugging (optional): Read the acknowledgement array to determine which bytes were acknowledged by the slave device.
Steps 2-5 can be repeated as long as I²C has not been used to communicate with a different device.
1. Initial Configuration
Several registers need to be written to configure the T-series device.
Digital IO lines need to be selected to act as SDA and SCL:
Name |
Start Address |
Type |
Access |
I2C_SDA_DIONUM
The number of the DIO line to be used as the I2C data line. Ex: Writing 0 will force FIO0 to become the I2C-SDA line.
|
5100 |
UINT16 |
R/W
|
I2C_SDA_DIONUM
- Address: 5100
The number of the DIO line to be used as the I2C data line. Ex: Writing 0 will force FIO0 to become the I2C-SDA line.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
I2C_SCL_DIONUM
The number of the DIO line to be used as the I2C clock line. Ex: Writing 1 will force FIO1 to become the I2C-SCL line.
|
5101 |
UINT16 |
R/W
|
I2C_SCL_DIONUM
- Address: 5101
The number of the DIO line to be used as the I2C clock line. Ex: Writing 1 will force FIO1 to become the I2C-SCL line.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
Set the clock speed:
Name |
Start Address |
Type |
Access |
I2C_SPEED_THROTTLE
This value controls the I2C clock frequency. Pass 0-65535.<br>Default=0 corresponds to 65536 internally which results in ~450 kHz.<br>1 results in ~40 Hz, 65516 is ~100 kHz.
|
5102 |
UINT16 |
R/W
|
I2C_SPEED_THROTTLE
- Address: 5102
This value controls the I2C clock frequency. Pass 0-65535. Default=0 corresponds to 65536 internally which results in ~450 kHz. 1 results in ~40 Hz, 65516 is ~100 kHz.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
The options register controls several compatibility settings:
Name |
Start Address |
Type |
Access |
I2C_OPTIONS
Advanced. Controls details of the I2C protocol to improve device compatibility.<br>bit 0: 1 = Reset the I2C bus before attempting communication.<br>bit 1: 0 = Restarts will use a stop and a start, 1 = Restarts will not use a stop.<br>bit 2: 1 = disable clock stretching.
|
5103 |
UINT16 |
R/W
|
I2C_OPTIONS
- Address: 5103
Advanced. Controls details of the I2C protocol to improve device compatibility. bit 0: 1 = Reset the I2C bus before attempting communication. bit 1: 0 = Restarts will use a stop and a start, 1 = Restarts will not use a stop. bit 2: 1 = disable clock stretching.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
For example, setting bit 1 of I2C_OPTIONS to true supports the repeated start condition.
Load the address of the slave device:
Name |
Start Address |
Type |
Access |
I2C_SLAVE_ADDRESS
The 7-bit address of the slave device. Value is shifted left by firmware to allow room for the I2C R/W bit.
|
5104 |
UINT16 |
R/W
|
I2C_SLAVE_ADDRESS
- Address: 5104
The 7-bit address of the slave device. Value is shifted left by firmware to allow room for the I2C R/W bit.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
2. Transmit load data.
Load an array of bytes to send to the slave device. This array does not include the device address.
Name |
Start Address |
Type |
Access |
I2C_NUM_BYTES_TX
The number of data bytes to transmit. Zero is valid and will result in a read-only I2C operation.
|
5108 |
UINT16 |
R/W
|
I2C_NUM_BYTES_TX
- Address: 5108
The number of data bytes to transmit. Zero is valid and will result in a read-only I2C operation.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
I2C_DATA_TX
Data that will be written to the I2C bus. This register is a buffer.
|
5120 |
BYTE |
W
|
I2C_DATA_TX
- Address: 5120
Data that will be written to the I2C bus. This register is a buffer.
- Data type: BYTE (type index = 99)
-
Write-only
- Default value: 0
- This register is a Buffer Register
|
3. Specify the number of bytes to read.
Write the number of bytes to be read from the slave device. Read operations will always be performed after any write operations.
Name |
Start Address |
Type |
Access |
I2C_NUM_BYTES_RX
The number of data bytes to read. Zero is valid and will result in a write-only I2C operation.
|
5109 |
UINT16 |
R/W
|
I2C_NUM_BYTES_RX
- Address: 5109
The number of data bytes to read. Zero is valid and will result in a write-only I2C operation.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
|
4. Execute the I²C operations.
Instruct the T-series device to run the write and read operations specified in the last two steps.
Name |
Start Address |
Type |
Access |
I2C_GO
Writing to this register will instruct the LabJack to perform an I2C transaction.
|
5110 |
UINT16 |
R/W
|
I2C_GO
- Address: 5110
Writing to this register will instruct the LabJack to perform an I2C transaction.
- Data type: UINT16 (type index = 0)
-
Readable and writable
- Default value: 0
-
T8:
-
T7:
|
5. Read the data that was read from the slave device, if any.
Data received from the slave device will be saved in buffer on the T-series device. Use the I2C_DATA_RX to read the buffer:
Name |
Start Address |
Type |
Access |
I2C_DATA_RX
Data that has been read from the I2C bus. This register is a buffer. Underrun behavior - fill with zeros.
|
5160 |
BYTE |
R
|
I2C_DATA_RX
- Address: 5160
Data that has been read from the I2C bus. This register is a buffer. Underrun behavior - fill with zeros.
- Data type: BYTE (type index = 99)
-
Read-only
- Default value: 0
- This register is a Buffer Register
|
6. Debugging: Read the acknowledgement array to determine which bytes were acknowledged by the slave device.
The below register can help troubleshoot I²C issues. The ACKs register will record all Acknowledgement signals transmitted from the slave device to the master (master is the T-series device). Data is always transmitted over I²C in the following sequence: Slave Address, Write data, Slave Address, Read data. After each byte sent to the slave device an acknowledgement will be stored in bit 0. A 1 indicates that the bytes was acknowledged, a 0 indicates no acknowledgement. Before saving the an ACK or no-ACK the register is shifted left.
For example, if two bytes are transmitted and three are read there will be four ACKs. Bit 3 represents the acknowledgement to the first slave address which starts the write operation, bit 2 is the first data byte, Bit 1 is the seconds data byte, bit 0 is the second slave address which starts the read operation.
Name |
Start Address |
Type |
Access |
I2C_ACKS
A binary encoded value (array of bits) used to observe ACKs from the slave device.
|
5114 |
UINT32 |
R/W
|
I2C_ACKS
- Address: 5114
A binary encoded value (array of bits) used to observe ACKs from the slave device.
- Data type: UINT32 (type index = 1)
-
Readable and writable
- Default value: 0
-
T8:
-
T7:
|
Example
This demonstrates I²C communications with an LJTick-DAC connected to FIO0/FIO1.
First, configure the I²C settings:
I2C_SDA_DIONUM = 1 // Set SDA pin number = 1(FIO1)
I2C_SCL_DIONUM = 0 // Set SCL pin number = 0 (FIO0)
I2C_SPEED_THROTTLE = 0 // Set speed throttle = 0 (max)
I2C_OPTIONS = 0 // Set options = 0
I2C_SLAVE_ADDRESS = 80 // Set 7-bit slave address of the I²C chip = 80 (0x50)
Read from EEPROM bytes 0-3 in the user memory area. We need a single I²C transmission that writes the chip's memory pointer and then reads the data.
I2C_NUM_BYTES_TX = 1 // Set the number of bytes to transmit to 1
I2C_NUM_BYTES_RX = 4 // Set the number of bytes to receive to 4
I2C_DATA_TX = {0} // Set the TX data. byte 0: Memory pointer = 0.
I2C_GO = 1 // Do the I²C communications.
I2C_DATA_RX = {?, ?, ?, ?} // Get the RX data (4 bytes).
Write EEPROM bytes 0-3 in the user memory area, using the page write technique. Note that page writes are limited to 16 bytes max, and must be aligned with the 16-byte page intervals. For instance, if you start writing at address 14, you can only write two bytes because byte 16 is the start of a new page.
I2C_NUM_BYTES_TX = 5 // Set the number of bytes to transmit to 5
I2C_NUM_BYTES_RX = 0 // Set the number of bytes to receive to 0 (not receiving data)
I2C_DATA_TX = {0, 156, 26, 2, 201} // Set the TX data. byte 0: Memory pointer = 0, bytes 1-4: EEPROM bytes 0-3.
I2C_GO = 1 // Do the I²C communications.
If using multiple I²C busses, just include writes to set the DIONUMs each time you want to communicate on a different bus. Other configuration is global also, so if different busses need different configuration include those writes also:
I2C_SDA_DIONUM = 2 // Set SDA pin number = 2 (FIO2)
I2C_SCL_DIONUM = 3 // Set SCL pin number = 3 (FIO3)
I2C_SPEED_THROTTLE = 65516 // Set speed throttle for ~100 kbps
I2C_NUM_BYTES_TX = 1 // Set the number of bytes to transmit to 1
I2C_NUM_BYTES_RX = 4 // Set the number of bytes to receive to 4
I2C_DATA_TX = {0} // Set the TX data. byte 0: Memory pointer = 0.
I2C_GO = 1 // Do the I²C communications.
I2C_DATA_RX = {?, ?, ?, ?} // Get the RX data (4 bytes).
Note: When writing the TX and RX data, LJM functions eWriteNameArray and eReadNameArray functions are recommended for ease of use.
2 comments
Multiple I2C channels
Hi
Is it possible to set up 2 or more sets of outputs as separate I2C comms channels? This is useful in the situation where you have multiple OTS sensors with the same hardcoded address.
Thanks
Yes. If you were just doing
Yes. If you were just doing 1 I2C bus, then looking at How-To above you would just do step #1 one time and then do 2-5 for each write/read. With multiple busses you do 1-5 each time so you can change the pin numbers as needed.