I2C [U3, U6, UE9] | LabJack
« Close

Datasheets and User Guides

App Notes

Software & Driver


Free Shipping for U.S. Orders $150+   |   5-year Warranty   |   Try Our Devices & Support for 60 Days, Risk Free  |   50 of 54 Products In-Stock Now

I2C [U3, U6, UE9]

This application note explains the operation and usage of the I2C functionality for UD series LabJack devices. For I2C configuration support on T-series devices, see the T-Series Datasheet.

I2C is considered an advanced topic. A good knowledge of the protocol is recommended, and 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.

Devices Discussed

  • UE9
  • U6
  • U3

Options for using I2C on LabJack devices

In general, our LabJack devices have two primary ways of being configured. They can be controlled using our High Level LabJackUD Driver, recommended when using a Windows PC, or they can be controlled using low level functions. This application note will focus on our high level driver.

Overview of I2C communication using the UD Library

Before sending I2C commands using our devices it is important to understand the available functions that can be used in the UD Driver. The most useful functions are "AddRequest" and "GoOne". Using these two functions you can configure, send, and receive I2C commands. In order to send I2C information using UD LabJack devices you need to follow three simple steps.

  1. Connect the Sensor
  2. Configure the I2C Data Bus
  3. Figure out how data needs to be sent and send it using the proper read and write commands

1. Connect the Sensor:

One of the most common causes of I2C issues is a minor sensor connection error. Always double check that your sensor is properly connected to a good, valid supply voltage and GND. Make sure that there are pull up resistors from the SCL and SDA lines to the supply voltage. Some common pull up resistor values are 1.8kΩ, 4.7kΩ and 10kΩ. For our application note examples we typically use 4.7kΩ resistors.

2. Configure the I2C Data Bus:

There are five pieces of information that you need to configure before you can start communicating with your sensor.

  1. Finding the preprogrammed address of the sensor
  2. Deciding what pin on the LabJack will be connected to the SCL pin
  3. Deciding what pin on the LabJack will be connected to the SDA pin
  4. Defining the I2C options register (most complicated)
  5. Adjust the clock speed of the I2C bus

1. The first step in configuration is to search the sensor's datasheet and find a 7 bit address that the sensor is preprogrammed to respond to. You then need to shift this address over one bit (5A (7 a bit address) becomes B4 (8bit address)). If the datasheet for your device gives you an 8 bit address you should be able to use this address with out shifting it. This is required because our High Level Driver needs to be able to change the smallest bit to indicate that you are either trying to read or write to the sensor.
2-3. The second and third steps is to decide what pins are going to be defined as SCL and SDA and then simply define them in your code.
4. The fourth and most complicated step is to configure the I2C Options. There are three settings that you can change here, you can enable clock stretching, tell the LabJack device to not stop transmitting when restarting, and you can tell the LabJack to Reset at Start.

  • Clock stretching is a fairly uncommon feature, but it allows the I2C slave to slow down the master when it needs to do more calculations or processes before data becomes available. A more detailed description of what this feature means can be found here.
  • Enabling "No Stop when restarting" tells the LabJack not to send a stop condition when sending more than a single command at once. Most I2C devices require you to write some information to the sensor in order to tell the sensor what information you will be requesting later and if you do not want there to be a pause in communication this should be enabled. A good picture showing the difference in transmission that occurs from toggling this setting are below:

The circled area is the brief pause between a write command (left) and a read command (right). FYI address 42 was configured in these two pictures. Sensors will recognize 21 as the address with a write or read bit following the address.

The circled area is where the pause used to exist between a write command (left) and a read command (right)

  • Enabling Reset at Start tells the LabJack to send 9 clock pulses before transmitting data to clear any half transmitted information that the sensor may think it has been sent. Times where you may want to enable this feature are when your LabJack lost power in the middle of transmission and your sensor didn't, when there may be a lot of noise along the SCL and SDA lines that could cause the devices connected in parallel to think they have received something but didn't, or other setups that require a robust I2C setup.

All three of these settings are packaged into a single byte that gets passed into the "AddRequest" function as a byte. These parameters get added together to get an integer from 0 to 255 that gets sent to the LabJack. If you wish to enable clock stretching, add 2^3 or 8, if you wish to enable "no stop when restarting" add 2^2 or 4, and if you wish to enable "Reset at start" add 2^1 or 2.
5. The last option that you can configure is the speed adjust parameter. This allows the communication frequency to be reduced. 0 is the maximum speed of about 150 kHz. 20 is a speed of about 70 kHz. 255 is the minimum speed of about 10 kHz.

Pseudocode for Configuration:

Now that you have all of the configurations figured out, you can now prepare the information to be sent using the AddRequest function, this can be easily shown through some pseudocode (an example for configuring our LJTick-DAC using I2C here). As an example, we will build the code that sent the above transmission over I2C.

//The following code configures I2C to try and communicate to the sensor/device responding to address 21
AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_ADDRESS_BYTE, 42, 0, 0);

//The following code configures I2C to use FIO7 as the SCL output pin
AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SCL_PIN_NUM, 7,0,0);

//The following code configures I2C to use FIO6 as the SDA output pin
AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SDA_PIN_NUM, 6,0,0);

//The following code configures I2C to enable the "no stop when restarting" I2C feature
AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_OPTIONS, 4,0,0);

//The following code configures the speed of transmission, sets SpeedAdjust to 0.
AddRequest(lngHandle, LJ_ioPUT_CONFIG, LJ_chI2C_SPEED_ADJUST, 0,0,0);

After all of these AddRequest functions have been called you need to execute the configuration requests:

//The following code executes the configuration requests

Because this tutorial was designed around the use of LabView, I will note a useful VI that we have created and are distributing that you can download and use here. It is called "AddS-Go-Get.vi" located in the following directory: "LabVIEW_LJUD\Utility VIs\AddS-Go-Get.vi" This VI takes in all of these settings, calls the AddRequest function for each of them, and then calls the GoOne function, we recommend that you use this VI when using LabVIEW on a Windows PC.

You can also download the Configure_I2C.vi a code snippet from a later VI that uses the AddS-Go-Get.vi and configures the LabJack to send I2C information.


After you have properly configured the LabJack to communicate over I2C there are three more options that our High-Level driver exposes for you. You can use the commands "LJ_chI2C_WRITE", "LJ_chI2C_GET_ACKS", and "LJ_chI2C_READ". These functions allow you to set up what information you want to send to the sensor (write), reports how many ACK bits were sent from the slave (get_acks), and reads back a given amount of information that is transmitted by the I2C device (read). Figuring out the information that you need to transmit to the sensor and how much information you will be looking to receive from the sensor are where problems start to arise. You can get bad results for many reasons including but not limited to trying to talk to an invalid address, using an invalid configuration, or sending the device a bad write array.

Pseudocode for Transmission:

To finish off creating the transmission in the above pictures, we need to add a write command where we write 0x41 and then read 2 bytes of information.

//build write request
numWrite = 1;
AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_WRITE, numWrite, array, 0);

//build read request
numRead = 2;
AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_READ, numRead, array, 0);

//Execute the requests

We recommend that you download this VI instead of trying to copy it, you can find it here. The "ljud eadd go get u8 array" vi that is used can be found in the same download as before, but in this directory "LabVIEW_LJUD\LabJackUD DLL Functions\LJUD_eAddGoGet (U8 Array).vi".

Another useful function that can help you debug some common I2C problems is the "LJ_chI2C_GET_ACKS" function. A useful VI that combines the read, write, and get ACKs functions can be found here. Pseudocode for doing this looks exactly like the transmission code except there is an extra AddRequest statement:

//tell the LabJack to count the ACK bits
AddRequest(lngHandle, LJ_ioI2C_COMMUNICATION, LJ_chI2C_GET_ACKS, numRead, array, 0);

For more examples of I2C implementation, you can look at the other AppNotes that we have created that communicate with I2C devices, look at example code in the LabVIEW download, look in the corresponding Python library for your device, or look at example code for our LJTick-DAC.

Support - Further I2C Resources

Further reading and Examples for I2C

Some posts and more resources about using LabJack devices with I2C sensors can be found on the forums section of our website as well as in some external locations:

  • A website dedicated to the I2C Bus.
  • There are some I2C examples for LabVIEW, Matlab, and Lua for the UD devices as well as devices that support LJM on GitHub in the I2C-AppNotes repository. In particular, look at the LJM_I2C_Utils.m file for LJM compatible devices and the UD_I2C_Utils.m file for UD compatible devices.
  • There are some detailed descriptions of I2C on UD devices on DAQFactory's forum regarding the MCP23017 I2C chip on a forum topic titled I2C Problem (MCP23017)
  • For T-series LabJack devices: The T-series I2C Simulator is a quick visualization tool aimed to help users understand how the LJM I2C registers affect the resulting I/O data pattern that you would see on a logic analyzer.
  • The generic I2C AppNote describes some general properties about I2C and has some logic analyzer screen shots describing some of the I/O patterns.



Referenceable: I2C FAQ/Common Questions

I2C FAQ/Common Questions


Q: Why are no I2C ACK bits being received?

  • Double check to make sure pull-up resistors are installed.  A general rule for selecting the correct size pull-up resistors is to start with 4.7kΩ and adjust down to 1kΩ as necessary.  If necessary, an oscilloscope should be used to ensure proper digital signals are present on the SDA and SCL lines.
  • Double check to make sure the correct I/O lines are being used.  It is preferred to do I2C communication on EIO/CIO/MIO lines instead of the FIO lines due to the larger series resistance (ESD protection) implemented on the FIO lines.
  • Use an oscilloscope to verify the SDA and SCL lines are square waves and not weird arch signals (see "I2C_SPEED_THROTTLE" or use EIO/CIO/MIO lines).
  • Use a logic analyzer (some oscilloscopes have this functionality) to verify the correct slave address is being used.  See this EEVblog post on budget-friendly options.  It is common to not take into account 7-bit vs 8-bit slave addresses or properly understand how LabJack handles the defined slave address and the read/write bits defined by the I2C protocol to perform read and write requests.
  • Make sure your sensor is being properly powered.  The VS lines of LJ devices are ~5V and the I/O lines are 3.3V.  Sometimes this is a problem.  Consider buying a LJTick-LVDigitalIO or powering the sensor with an I/O line or DAC channel.

Q: I've tried everything, still no I2C Ack Bits...

  • Try slowing down the I2C bus using the "I2C_SPEED_THROTTLE" register/option.   Reasons:
    • Not all I2C sensors can communicate at the full speed of the LabJack.  Check the I2C sensor datasheet.  
    • The digital signals could be getting corrupted due to the series resistors of the I/O lines on the LabJack.
  • Consider finding a way to verify that your sensor is still functioning correctly using an Arduino and that it isn't broken.
  • Try to establish communications with an LJTick-DAC to ensure the DIO are operating properly and that you are configuring I2C properly.

Q: Why is my device not being found by the I2C.search function?

  • See information on I2C ACK bits above.

Q: What are I2C Read and Write functions or procedures?

Q: Why am I getting a I2C_BUS_BUSY (LJM Error code 2720) error?

  • See information on I2C ACK Bits above. Try different pull-up resistor sizes.


When I view this page, two of the graphics are missing.  There are broken icons instead.

I see 2 graphics above of LabVIEW wiring diagrams, and they both show up fine for me.  Does it work with a different browser?  Perhaps it was a temporary problem or a bad connection?

Right, there are two, there should be four.

The missing graphics are noted below the quoted text where they should appear:


"The circled area is the brief pause between a write command (left) and a read command (right).  FYI address 42 was configured in these two pictures.  Sensors will recognize 21 as the address with a write or read bit following the address."

<========= HERE

"The circled area is where the pause used to exist between a write command (left) and a read command (right)"

<========= HERE


In the example you put the I2C address in the config, not in the I2C_COMMUNICATION field. I have a number of I2C sensors which get polled at various frequencies so I need to change the address frequently. Is storing the address in the config still correct, or is there a better way?

You perform I2C communication in two steps when using a LabJack.  The goal of this is to make the user not have to bit-bang the protocol.  You have to save information to the LJ_ioPUT_CONFIG IO type in order to configure the I2C buss.  Then you can perform standard read & write requests by writing to and reading from the LJ_ioI2C_COMMUNICATION IO type.  In short, no there isn't a different way to use I2C comm. 

In the text above

1. The first step in configuration is to search the sensor's datasheet and find a 7 bit address that the sensor is pre-programed to respond to.  You then need to shift this address over one bit (5A (7 a bit address) becomes B4 (8bit address)).  If the datasheet for your device gives you an 8 bit address you should be able to use this address with out shifting it.

A simple clarification can be that the shift is 1 bit to the left.



office1's picture

Is there a software tool available for exploring the connected sensor - having brute force address and port guessing etc.?

labjack support's picture

Hello, we don't have any specific tools for exploring a connected sensor.  We do however have a I2C Lua Library with a "search" function that you can call if you want to write a Lua Script.  The I2C Tutorial Hardware Check script may assist you with this too.

office1's picture


thanks to your help I have completed the C-program collecting the stream from the U3, and should combine that with sensor data aquired via I2C. So a fully worked out example for the I2C-bus in C would be great.


many thanks


best regards

labjack support's picture


We don't have any C code that specifically follows this App-Note, however we do have an I2C example in our UD library C/C++ example code in the /Any Device/I2C folder.