I2C communications is a integral part of communicating to sensors and peripheral devices. Learning to implement I2C Communications in combination with NCD devices allows users to expand their relay controllers into sensor monitoring and control applications. One of the greatest benefits of I2C communications is the simple protocol for talking to external devices. Since many manufacturers generate sensors and chips that support I2C communications, it is possible to monitor and control thousands of different external devices by simply learning a few simple commands.
NCD is manufacturing and developing many controllers that support I2C communications. Most notably, Fusion series controllers all include at least one I2C communications port. The BridgeX5 controller gives you 5 I2C communication ports and two interface modules (such as WiFi, Bluetooth, USB, RS-232, Ethernet, or Industrial Wireless). Our upcoming line of ProXR Generation 4 controllers will all include I2C communication ports. It’s safe to say, that from now on, all of our controllers we manufacture in 2017 or later will include a I2C expansion option. Likewise, all controllers will support our standard communication protocol for talking to I2C devices. But we didn’t stop with just the port, we are also manufacturing hundreds of devices with a I2C communication port, designed to plug directly into all of our controllers. This is good news for users who need unlimited expansion. This means users will have access to every type of sensor imaginable, and just about every type of controller imaginable. At the time of writing (January 5, 2017), we have released over 750 products with I2C communications capabilities, and we have plans for hundreds more!
Select Fusion I2C capable devices support at least two I2C communication ports (Port 0 and Port 1). Port 0 has a fixed communication rate of 100 kHz and may be used by NCD devices that contain integrated sensors, I/O Expanders, or other types of I2C devices. Though we may allow access to Port 0 on select controllers, Port 0 should generally be considered for use by the NCD products and peripheral devices. For instance, we may offer expansions that offer additional features by utilizing Port 0. Port 0 is typically accessed using the FXR Relay Expansion Port. I2C Port 1 is for general use by our customers. Port 1 is available for on AD8 Port 1 (shared with UXP Port 1) using I/O Lines 1 (SDA) and 2 (SCL). I2C Port 1 can be tuned for faster or slower speeds. Slower speeds allow Fusion controllers to communicate I2C data over longer distances while faster speeds offer greater compatibility. The Up/Down Jumper for AD8 Port 1 should be set to the “UP” position when using the I2C communication features.
Fusion I2C Port 1 supports 500 Hz, 1 kHz, 10 kHz, 50 kHz, 100 kHz, and 130 kHz communication speeds (which has all been precisely timed with an oscilloscope), and supports I2C device clock stretching, as required by the I2C communication protocol (a feature often skipped by most I2C implementations). Development of the I2C communication routines were centered on a 24LC515 Non-Volatile EEPROM, and has been tested with various I2C sensors to prove functionality.
Use of I2C communication functions on Fusion series controllers require prior knowledge of I2C, as it is outside the scope of our documentation to go into a detailed explanation of the protocol. Here we will focus on the data exchange between a computer and the Fusion controller. The Fusion controller will manage the data exchange with the I2C device, greatly simplifying the amount of information that must be studied.
When working with I2C for the first time, it is helpful to use the 24LC515 EERPOM connected to a Fusion controller. The 24LC515 demonstrates 2-way communications with the device, showing you how to read and write data as shown in the sample provided in Base Station software.
To date, all I2C devices we have tested are compatible with Fusion I2C communication routines.
Overview of I2C
For complete details on the I2C protocol, there are many resources available on the internet, some of which have some very good descriptions of the protocol. Most of the detailed protocol information may be skipped when working with a Fusion controller as the difficult part of communications is completely handled by our firmware. Even so, there are a few things you need to understand before you can successfully implement communications to an I2C device:
- I2C devices need a power supply of 3.3V or 5V. Fusion controllers ONLY work with 5V I2C devices. There are many I2C level converters on the market that translate 5V data to 3.3V for lower voltage I2C devices. Do not attempt to connect a 3.3V I2C device to a Fusion controller without a level translator.
- I2C is an Open Collector Protocol. As such, all data is transferred using open collector communications, not standard TTL signals. In order to speak to an Open Collector device, the Pull Up/Down Jumper on the AD8 Port 1 MUST be set to the UP position. This will pull up the SDA and SCL lines using a 10K resistor, which is within I2C specifications. Note that communication errors will result unless this jumper is properly set.
- I2C devices NEVER send data to the controller spontaneously. You should never expect an I2C device to function in this way. Instead, Fusion controllers send a command to the I2C device and the I2C device replies with data. Put simply, an I²C device only speak when spoken to.
- Carefully study the data sheet of your I2C device. You can skip most of the information on timing requirements, as this is handled by the Fusion controller. Specifically, you need to know the following about your I2C device:
- Make sure the device supports 100 KHz communications, almost all I2C devices do.
- You will need to know the address of the device. Every I2C device has a unique address that is required to initiate communications.
- Learn the command set for your I2C device. Many I²C devices support both write and write/read operations (writing a command, reading a response). Familiarizing yourself with these commands is essential.
- Fusion controllers are limited to writing 75 characters on the I2C bus. It is not possible to read or write data to an I2C bus that exceeds the 75 character limit. This is a limitation of the I2C buffer within the Fusion controller. Most I2C exchanges are 16 bytes or less, so this should not be a problem for most applications. Base Station Software is limited to 16 bytes of communication to and from an I2C device, but this does not represent the limit of the Fusion controller.
- Fusion controllers do not support 10-Bit extended addressing.
- The wire length between a Fusion controller and I2C devices is an important consideration. The maximum capacitance on an I2C bus is 500pf. A high quality twisted pair cable should be used to maximize distance when required. Network cable is well shielded and pairs of cable are twisted together, reducing noise potential on the cable. If you choose to use network cable, always use a pair of colors that are twisted together. CAT6 Cable has a capacitance of 13.5pf per foot. CAT5 Cable has a capacitance of 17pf per foot. Stranded wire can also be used for shorter distance applications. Most I2C devices are capable of operating at lower clock frequencies below 100 KHz. Reducing the clock frequency will significantly improve communication distance. For customers who need longer distance, use the Device Configuration button in Base Station Software to set the timing of I²C Port 1 to a slower speed. Some users have reported 100 meters of distance when working with 500 Hz communication speeds. We have not attempted to verify this capability, but we believe this is possible. 500 Hz is 200 times slower than 100 KHz, but it’s still fast enough for most applications.
- I2C supports multiple devices on the same communication bus, so it is possible to have many different types I2C devices working together using the I2C bus on the Fusion controller.
NCD Fusion controllers have adopted the same loose standard as Arduino and other microcontrollers that support a 4-pin latching header with pins 1-4 offering the following interface connections:
I2C Port 1 Pin 1 on NCD Device Carries the I2C SCL Signal to Pin 4 on an I2C sensor.
I2C Port 1 Pin 2 on NCD Device Carries the I2C SDA Signal to Pin 3 on an I2C sensor.
I2C Port 1 Pin 3 on NCD Device Carries +5 Volts to Pin 2 on an I2C sensor.
I2C Port 1 Pin 4 on NCD Device Carries Ground to Pin 1 on an I2C sensor.
Port 0 is physically connected to the FXR Expansion Relay port, and is typically used by NCD devices that include integrated I2C peripheral devices. Port 0 is not generally available for direct use, but is available for direct use on select models of Fusion controllers. Integrated 10K Pull-Up resistors are wired to the I2C SCL and SDA Lines of Port 0.
Port 1 is physically connected to AD8 Port 1 (Shared with UXP Port 1). Port 1 is for customer use and may be tuned to 500 Hz to 130 KHz with a default communication speed of 100 KHz.
NCD Base Station Software includes an I2C control panel used to demonstration communications to various popular I2C devices. The control panel shown below may look a little intimidating at first, but it is about as easy as we can make I2C communications.
Choosing an I2C Communication Port
This option lets you choose the I2C communication port you will be using. Most of the time, you will be using Port 1 as shown, Port 0 is typically reserved for use by NCD devices that include integrated I2C peripheral devices. Port 0 may at times be available to the user depending on controller model.
Step 1: Choosing an I2C Address
The I2C device address is the most important byte of the I2C communications protocol. This address is always indicated in the datasheet for your I2C device. In an effort to assist customers, the I2C address of know devices is shown in the left menu tree. Simply choose the I2C device you would like to communicate with, and select the address choice indicated in Step 1 of the menu tree.
If you are setting up communications with an I2C device not shown in the left menu tree, click on the A7-A1 boxes, as well as the R/W box to set the bits. The 7-Bit Address and Final address are indicated (data sheets tend to show one or the other type of address which may or may not include the R/W bit).
Step 2: Choose How Many Bytes of Data you want to Send to the I2C Device
Keep in mind, when communicating with an I2C device, you have to send at least 1 byte of data (which includes the address shown in step 1). For this reason, the minimum number of bytes you can send to an I2C device is 1. Additional bytes are often used to indicate memory locations and data that is to be written to an I2C device.
Step 3: Sending Data
Each box should be filled with a decimal value from 0 to 255 (hex is not yet supported). The data sheet of your I2C will indicate the data that should be sent. Most I2C devices use the next few bytes to indicate register addresses inside the I2C device, and sometimes include data write to the selected address registers.
Step 4: Reading Data
This parameter is used to indicate the number of bytes to read from an I2C device. Reading data from an I2C device is optional, but this parameter must be included as part of the command, even if the number of bytes to read is zero. If data is received from an I2C device, it will appear in the “Data Read from I2C Device” frame.
Fusion I2C Command Set
There is only one Fusion command to learn for complete implementing I2C communications. There can be many variations on the use of this command, but the format is always the same. Because of the complex structure, the command will not be shown in our usual way. Instead, we will list every byte with a description of its purpose and implementation.
Fusion I2C Send Command Structure
Byte 1 188 External Device Communications Command
Byte 2 50 Communicate to Internal I2C Port 0 (NCD Hardware I2C Port)
51 Communicate to External I2C Port 1 (User I2C Port)
52 Communicate to External I2C Port 2 (User I2C Port, Not Available on All Models)
53 Communicate to External I2C Port 3 (User I2C Port, Not Available on All Models)
54 Communicate to External I2C Port 4 (User I2C Port, Not Available on All Models)
Byte 3 1-75 Number of Bytes to Send
Byte 4 0-255 Byte 4 is the beginning of all data that is sent to the I2C device. All data to be sent to the I2C must be included here. The first byte must always be the I2C Start Address (see below for a complete explanation).
Last Byte 0-75 The last byte of the command must contain the number of bytes to read from the I2C Device.
I2C Start Address and Read/Write Bit
The first byte in a communication packet must contain the I2C start address. The start address is used to choose a chip for communications on the I2C bus. As you might expect, the I2C start address is critically important. We have combined the I2C Start address and the Read/Write Bit as a single byte to improve communication efficiency. If you are familiar with I2C at the hardware level, you will better understand our reasoning for combining the I2C Start address and Read/Write bits, as this is how I2C communications works at the physical layer. Nonetheless, you will undoubtedly need some direction in understanding our implementation.
To better understand the I2C Start Address and how we have implemented it, let’s dive in to the MCP23008, a very common digital I/O chip from Microchip.com. This chip has a start address of 0x20, according to the data sheet, so now we will convert this start address to a start address that is usable for NCD devices:
Start Address for NCD Devices = (I2C Device Start Address x 2) + Read/Write Bit (0 or 1)
The MCP23008 has a start address of 0x20 (32 Decimal).
We will multiply this start address by two (this will effectively shift the data 1 bit to the left):
(Hex) 0x20 x 2 = 0x40
(Decimal) 32 x 2 = 64
Now we need to add zero to this value if we want to write data to the I2C chip, or we need to add one to this value if we want to read data from the I2C chip:
Write Mode Hex Example: 0x40 + 0x00 = ox40
Write Mode Decimal Example: 64 + 0 = 64
Read Mode Hex Example: 0x40 +0x01 = 0x41
Read Mode Decimal Example: 64 + 1 = 65
So the value we will use for the NCD controller is 64 if we want to write a decimal value to the MCP23008 at address 0 with a start address of 0x20 (as seen in the data sheet for the MCP23008).
Subsequent bytes may be sent to the MCP23008 according to the address registers as shown in the data sheet.
Response from a Fusion Controller
It is possible to receive many types of responses from NCD controllers when speaking to a I2C device. For instance, 85 will be received if the NCD controller has successfully transmitted data to an I2C device, but this response is only valid if you are NOT reading any data from an I²C device (Last byte of the transmission is Zero). If you are reading data from an I2C device, then the response should contain the data bytes you are expecting from an I2C device. If an error occurred during I2C communications, an Error Code will be returned.
NOTE: All NCD I2C Commands MUST BE API Encoded.
Please review the API Codec Quick Start Guide.
Fusion firmware tries to provide you with clues as to why your command was not accepted by an I2C device. However, it should be stated that not having a device connected, using the wrong address or port number may also trigger these error codes. Fusion firmware will return the following error codes if there is a problem communicating with an I2C device:
88 90 165 67 Error 90: Acknowledgement Not Received from I2C Device
88 91 164 67 Error 91: Device Took Too Long to Respond
88 92 163 67 Error 92: Could Not Set Address of Device
This error is generated when a I2C Device does not acknowledge a command. Typically, this error occurs later in the serial stream, and usually indicates command parameters or memory locations are not properly set.
Fusion I2C firmware supports clock stretching, which allows I2C devices to hold the clock line during the time it takes to measure sensor data. This error code is generated of an I2C device takes too long to respond (1 or 2 seconds is too long for an I2C device).
The first byte of data sent to an I2C device is always its address. This error code is generated if an I²C device fails to respond to this address. This error typically occurs early in the serial stream, and indicates the address byte is wrong or the device is not properly connected.
The following examples will demonstrate a successful transmission to a MCP23008, controlling most of it’s various operations. This is a ideal learning chip for I2C communications, as it is low cost and easy to understand.
The following packet will set all I/O lines of a MCP23008 to Output Mode: 170 7 188 50 3 64 0 0 0 226 (Decimal Values Shown)
170 is the API Header
7 is the total number of bytes in the API Packet
188 is the I2C Communications Command Header
50 is Port 0 (Use 51 for Port 1, etc…)
3 is the number of bytes to be written to the I2C Port
64 is the I2C Start address of the MCP23008 when all of the address lines are pulled low
0 set to output mode
0 set to output mode
0 do not read any bytes back from the I2C chip
226 is the checksum. The checksum is the 8-bit truncated sum of the following bytes: (170+7+188+50+3+64+0+0+0)
Note the actual sum of the above bytes (170+7+188+50+3+64+0+0+0) is 482. To compute the 8-Bit truncated sum, we use the AND math operation (also known as Bitwise AND), available in most programming languages:
482 AND 255 = 226
NOTE: We have many more examples available, please see Software Tools below.
We have developed two software tools to help users get started using all kinds of I2C devices. The first tool we created was Base Station software, available from ncd.io/start. Base Station works with all of our devices, and makes it easy to control our products including a few I2C devices. Base Station may be installed on Windows 8 or later computers. Base Station is a good starting point, but it does not demonstrate too many I2C devices.
A more focused tool called AnyI2C is in constant development, focusing solely on I2C peripheral devices. AnyI2C has a log window, which clearly demonstrates the API Packet Structure, I2C Command Set, and actual I2C communication bytes (payload). AnyI2C is available from our GitHub repository: http://github.com/ControlEverythingCom/AnyI2C. AnyI2C runs under Microsoft Visual Studio Express, the complete source code is included in the GitHub archive.
Version 3 Upgrade Notes
As of 5/9/2018, there have been a few updates to NCD USB to I2C conversion devices. The following update information applies to the devices shown below ONLY:
Version 3 Enhancements
- I2C Communications now Supports a Hardware I2C Converter instead of a Firmware Based Converter
- 3x Improvement in I2C Data Transfer Speed
- Bug Repaired that Affected Reliability of Some I2C Chips
- Two new commands were added to greatly simplify I2C Communications (see below)
Please note that NCD offers Free firmware upgrades, simply return your device to us and we will program it with the latest firmware.
Optionally, you may purchase new controllers and return your old controllers to us for a credit.
PLEASE NOTE THAT ALL COMMANDS SHOWN BELOW MUST BE WRAPPED IN NCD API PACKET STRUCTURE!
Sending I2C Data (New Command)
Send the following byte structure to the controller to easily send data to the I2C Port:
190, <7-Bit Start Address>, <Data 1>, <Data 2>, <Data 3>, etc
The following I2C Bytes can be used to control a PCA9536. In this example, we will use the NCD I2C Buzzer Mini Module to turn the buzzer on and off.
65 03 00 (PCA9536 Set to Output)
65 01 08 (PCA9536 Turn on Buzzer)
65 01 00 (PCA9536 Turn Off Buzzer)
The above commands are found in the PCA9536 datasheet, and are frequently shown in Hex Notation
0x41 0x03 0x00 (PCA9536 Set to Output)
0x41 0x01 0x08 (PCA9536 Turn on Buzzer)
0x41 0x01 0x00 (PCA9536 Turn Off Buzzer)
Now we need to translate the I2C Commands for use with NCD USB to I2C Converters
0xAA Byte 1 of NCD API Packet Header Byte
0x04 Byte 2 of NCD API Packet Indicates the Number of Bytes in the Payload
oxBE Byte 3 of NCD API Packet is Payload Byte 1, Indicating NCD I2C Write Function 0xBE = 190 Command Header
0x41 Byte 4 of NCD API Packet is Payload Byte 2, Indicating 7-Bit Start Address of the PCA9536
0x03 Byte 5 of NCD API Packet is Payload Byte 3, Indicating to the Port Direction of the PCA9536
0x00 Byte 6 of NCD API Packet is Payload Byte 4, Indicating to set the Port Direction to Outputs (0 = Output in PCA9536 datasheet)
0xB0 Byte 7 of NCD API Packet is a Checksum Equal to the 8-Bit Sum of Payload Bytes 1 through 4 above.
In a more simplified format, sending the following data will control a Buzzer connected to the PCAp536. The first command is used to set the Port direction of the PCA9536 to Output Mode.
Send:AA 04 BE 41 03 00 B0
Rec:AA 01 55 00
The following command will turn on the Output of the PCA9536.
Send:AA 04 BE 41 01 08 B6
Rec:AA 01 55 00
The following command will turn off the Output of the PCA9536.
Send:AA 04 BE 41 01 00 AE
Rec:AA 01 55 00
Receiving I2C Data (New Command)
Receiving data from I2C Devices works in exactly the same way as sending data, except the command header has changed and the number of bytes you would like to read must be specified in a parameter. If it is necessary to set a pointer before a read operation, please use the I2C write command above to move the pointer, then use the I2C read command to read data from the I2C device.
191, <7-Bit Start Address>, <1-30 Number of Bytes you Want to Read from the I2C Chip>