The following examples outline how I2C communication can be achieved in Lua scripts.
The below examples utilize the I2C library with the functions built in to the firmware. More detail (at the ModBus register level) can be seen under the I2C Utilities, where the library is exposed as a Lua object with functions. A list of these functions with descriptions can be found here.
The T7 supports Inter-Integrated Circuit (I²C or I2C) communication as the master only. I²C is a synchronous serial protocol typically used to communicate with chips that support I2C as slave devices. More information on I2C can be found here (Wikipedia).
It is recommended to use the EIO or CIO lines for I2C communication on the T7 rather than the FIO lines. For more information on using the T7 with I2C devices, see the T7 Datasheet.
Many sensors can be on the same I2C bus, with very minimal circuitry for each additional I2C device. A total of 7 I2C devices are shown connected to the T7 below, and can all successfully connect and communicate with the T7.
These Lua scripts use the USER_RAM registers to pass data from the Lua script to any other program accessing the T-Series device. LabVIEW, C#, Python, or any other supported languages can access the T-Series device and read from or write to these registers. LJLogM, a LabJack application can be used for easy logging of data from the various sensors.
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?
There are a few really good resources for learning about the general flow of I2C communication.
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.
Differential Pressure Sensor (SDP611)
This Lua Script is an example of how to communicate with an SDP611 differential pressure sensor from Sensirion (datasheet link). Before running this example, connect the SCL line to EIO4 and the SDA line to EIO5.
Note: The default I2C configurations don't work for this sensor. Special configurations are required to account for the "Hold Master" part of the I2C packet.
This example script collects temperature data from the MLX90614 infrared temperature sensor available through Adafruit, SparkFun, Keyestudio, or Pololu.
The data obtained from the non-contact temperature sensor is published to the registers:
USER_RAM0_F32 (Ambient temperature)
USER_RAM1_F32 (Object Temperature)
These registers can accessed by any programs reading data from a T-Series device collecting this data. This enables any logging or SCADA application to easily collect data from the MLX90614 temperature sensor without any additional complexities.
When getting started with this sensor, the datasheet for this sensor is important to read. There are multiple online tutorials through SparkFun, Adafruit, and more that can serve as supplementary documents. There is also a legacy app-note worth reading Melexis MLX90614 IR Temperature Sensor - I2C (App Note). This sensor has multiple features that allow its slave address to be reprogrammed, enabling multiple IR sensors to exist on the same I2C bus. It can also be enabled for PWM output (not utilized by this application).
Schematic & Hook-up
Below is a picture of the MLX90614 IR temperature sensor connected to a LabJack with 1.8kΩ resistors installed on a breadboard.
Below is a schematic of the MLX90614 IR Temperature sensor connected to an I2C master MCU. Again, this example used 1.8kΩ resistors.
In this example, the MLX90614 IR Temperature sensor is connected to EIO6 and EIO7. A 3.3V supply was not needed to properly control this sensor. The VS could be 5V while the I/O lines were communicating with 3.3V logic.
Working Example with LJLogM
After configuring the below example script using Kipling, data can be collected using LJLogM.
This Lua script is useful as an example of how to combine I2C communication between many slave devices. This example utilizes a collection of I2C sensors, which are all available on the Adafruit 10-Degrees of Freedom Inertial Measurement Unit (10-DOF IMU, available here: https://www.adafruit.com/product/1604)
This example uses the following I2C Sensors:
L3GD20H Triple-Axis Gyro
LSM303 Triple-axis Accelerometer**
LSM303 Triple-axis Magnetometer**
*The BMP180 Barometric Pressure Sensor was not implemented in this example because of Lua script limitations. See the BMP180 Lua script for more information.
**Although the LSM303 devices are in the same package, they behave as two separate devices. See the LSM303 Accelerometer & Magnetometer Lua Script for more information.
Each of the 3 sensors must be initialized over I2C (to configure parameters such as range, data rate, and low/high power mode.
To switch between devices, the I2C bus is configured for one address, and MB.W(5104, 0, yourNewI2CAddress) is used to switch between slave devices. Reconfiguring the bus with I2C.config() would work, but takes unnecessarily long.
For more information on each I2C sensor, visit their specific lua script example.
Image 1 - L3GD20H and LSM303 breakout board.
The 10 DOF board requires very few components to run, a 3.3V supply is provided by the LJTick-LVDigitalIO.
Image 2 - T7-Pro connected to Adafruit 10-DOF.
The accelerometer can be tested by rotating it at angles to the earth, where +1.0g and -1.0g can be measured. Below is a graph of the accelerometer data (X is white, Y is red, Z is green) as the module is rotated.
This script configures the accelerometer inside the LSM303, as well as the magnetometer. These, while in the same package, behave as separate devices with different I2C addresses. The accelerometer can measure acceleration up to ±16g in each axis, and the magnetometer can measure up to 8.1 gauss in each axis. The main purpose of this unit is for a tilt-compensated compass, although it can be used for a variety of functions, depending on the application. The LSM303 on a breakout board is available here: https://www.adafruit.com/product/1120
The data obtained from the accelerometer and magnetometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the accelerometer and/or magnetometer data.
The other functionalities of this device, like configurable interrupts, fall detection, and tap detection can be configured just as the other options are configured, although these specialized functions are outside the scope of this example.
Below is the LSM303, as a part of the Adafruit 10DOF board.
The 10 DOF board requires very few components to run, a 3.3V supply is provided by the LJTick-LVDigitalIO.
The accelerometer can be tested by rotating it at angles to the earth, where +1.0g and -1.0g can be measured. Below is a graph of the accelerometer data (X is white, Y is red, Z is green) as the module is rotated.
This script configures the magnetometer inside the LSM303, which behaves as a separate device from the accelerometer that is part of the same unit. The magnetometer can measure acceleration up to ±8.1 gauss in each axis. The main purpose of this unit is for a tilt-compensated compass, although it can be used for a variety of functions, such as free fall detection or tap detection. The LSM303 on a breakout board is available here: https://www.adafruit.com/product/1120
The data obtained from the magnetometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the LabJack device simultaneously obtains the magnetometer data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range (±1.3, ±1.9, ±2.5, ±4.0, ±4.7, ±5.6, or ±8.1 gauss)
This script configures the accelerometer inside the LSM303, which behaves as a separate device from the magnetometer. The accelerometer can measure acceleration up to ±16g in each axis. The main purpose of this unit is for a tilt-compensated compass, although it can be used for a variety of functions, such as free fall detection or tap detection. The LSM303 on a breakout board is available here: https://www.adafruit.com/product/1120
The data obtained from the accelerometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the accelerometer data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range ( ±2g, ±4g, ±8g, or ±16g)
The other functionalities of this device, like configurable interrupts, fall detection, and tap detection can be configured just as the range is configured, although these specialized functions are outside the scope of this example.
Below is the LSM303, as a part of the Adafruit 10DOF board.
The 10 DOF board requires very few components to run, a 3.3V supply is provided by the LJTick-LVDigitalIO.
The accelerometer can be tested by rotating it at angles to the earth, where +1.0g and -1.0g can be measured. Below is a graph of the accelerometer data (X is white, Y is red, Z is green) as the module is rotated.
This script measures acceleration using the widely available ADXL345 Accelerometer, which can measure acceleration up to 16g on 3 axes. The accelerometer on a breakout board is available here: https://www.sparkfun.com/products/9836
The data obtained from the accelerometer is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the accelerometer data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range (2g, 4g, 8g, or 16g)
The other functionalities of this device, like configurable interrupts, fall detection, and tap detection can be configured just as the range is configured, although these specialized functions are outside the scope of this example.
In the above images, an inexpensive LJTick-LVDigitalIO was used to source the 3.3V needed for the ADXL345. A CB15 was used to expose the EIO4 and EIO5 connections.
Using a python script to read and write to the USER_RAM registers, it was possible to make a self-leveling platform using the ADXL345 and a servo motor.
This script uses the TCS34725 color sensor to determine the color of an object. The breakout board from Adafruit (https://www.adafruit.com/product/1334) has a built-in white LED to illuminate the object. This LED can be controlled by connecting it to a digital pin on the T-series devices. In the below example, FIO6 is used (although the LED pin is not connected in the images)
Information on how to use the values from the sensor can be found on the datasheet. In the example below, color (Simply "Red", "Green", or "Blue") is determined by the most intense color. Specific calculations can be created by the user for specific applications, such as detecting a hue value or the reflectivity of the object. A good understanding of the device's datasheet is important for modifying the script.
The data obtained from the gyroscope is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the gyroscope data.
The datasheet is extremely useful for determining the setting on the device, such as low-power mode and range (±245/±500/±2000 dps)
The other functionalities of this device, like configurable interrupts, sleep mode, and the built-in temperature sensor can be configured just as the range is configured, although these specialized functions are outside the scope of this example.
Below is the gyro as a part of the Adafruit 10 DOF board.
The Gyro is connected to EIO4 and EI5 with pullup resistors. Here, it is using the LJTick-LVDigitalIO to supply the 3.3V necessary.
This script measures rotational speed (degrees per second) using the PS-ITG-3200 Gyroscope, which can measure up to 2000 degrees/sec on 3 axes. The device on a breakout board is available here: https://www.sparkfun.com/products/11977
The data obtained from the gyro is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the gyro data.
The datasheet is helpful for identifying how to initialize the device and how to read data from the gyro.
In the above images, an inexpensive LJTick-LVDigitalIO was used to source the 3.3V needed for the ADXL345. A CB15 was used to expose the EIO4 and EIO5 connections.
The other functionalities of this device, like configurable interrupts, filtering, and other functions are outside the scope of this example, but can easily be configured in the same way the other device settings are initialized.
The script then reads the distance value from the sensor and reports it to a USER_RAM register, accessible in many other programs, such as LabVIEW, Python, C#, or the LabJack logging software, LJLogM.
The range finder sensor is easily connected using the EB37 and CB15 Accessories.
This script measures the distance to a large, flat object up to 255 inches away (21 feet) using the I2C bus. The SRF02 Sensor uses ultrasonic pings to bounce off of large objects and detect the distance.
A register on the SRF02 must be written with the value 0x50 to initiate the ping. After a short delay, the corresponding registers can be read to obtain distance in inches or centimeters. A variety of documentation can be found online regarding the SRF02.
The data obtained from the sensor is published to USER_RAM registers, which can be accessed by any other programs connected to the T-Series device. This allows a program to be doing one task while the device simultaneously obtains the range sensor data.
In the image above, a battery pack is used to supply power to the T7-Pro, and data is acquired over WiFi, allowing the assembly to be moved anywhere within a building while operating.
This script measures temperature and barometric pressure using the BMP180 sensor. The calculations for the BMP180 to take the data and calibration constants and determine the atmospheric pressure is too large for Lua, and is completed through a python script running on a PC instead.
Below is the BMP180 as a part of the Adafruit 10DOF board. A BMP180, with the appropriate passive components, will function identically to the BMP180 on the 10DOF board.
This script operates an I/O expander over the I2C Bus. The I/O expander- the SX1509- has 16 channels, which can be configured for digital input or output (including PWM and specialized LED driver functions) and can be used to read a keypad.
The script below only uses the basic digital input and output functions of this device. This script can be modified to use other functionalities, such as the PWM driver or keypad engine.
USER_RAM registers are read by the script to write values to the digital output lines, and a separate set of USER_RAM register is written to by the script to display the digital input states.
A good understanding of the datasheet and device's functionality is important for understanding and modifying this example.
Before making the decision to use this device, keep in mind that the T7 has 23 DIO lines available.
The EB37 allows for easy prototyping of the entire circuit. The EB37 features a 3.3V regulator, which is being used to supply power to the digital I/O expander. The CB15 provides connection to the EIO lines.
A python script was used to change the USER_RAM registers to sequence through all of the digital output pins, and then write them all high at once.