USB-ISS Multifunction USB Communications Module
I2C Mode - Technical Specification
The USB-ISS always operates as an I2C bus master.
I2C mode has a number of commands for accessing I2C devices with 0, 1 or 2
internal address bytes, and for building your own custom I2C sequences. These
are:
Command | Value | Description |
I2C_SGL | 0x53 | Read/Write single byte for non-registered devices, such as the Philips PCF8574 I/O chip. |
I2C_AD0 | 0x54 | Read/Write multiple bytes for devices without internal address or where address does not require resetting. |
I2C_AD1 | 0x55 | Read/Write 1 byte addressed devices (the majority of devices will use this one) |
I2C_AD2 | 0x56 | Read/Write 2 byte addressed devices, eeproms from 32kbit (4kx8) and up. |
I2C_DIRECT | 0x57 | Used to build your own custom I2C sequences. |
I2C_TEST | 0x58 | Used to check for the existence of an I2C device on the bus. (V5 or later firmware only) |
The USB-ISS module takes care of all the I2C bus requirements such as start/restart/stop sequencing and handles the acknowledge cycles. You only need supply a string of bytes to tell the module what to do.
Writing a single byte to I2C devices without internally addressable
registers
These include devices such as the Philips PCF8574 I/O expander. Following the
I2C_SGL you send the devices I2C address and the data byte.
Primary USB-ISS command | Device Address + R/W bit | The data byte | |
Byte Type | I2C_SGL | Addr+R/W | Data |
Example | 0x53 | 0x40 | 0x00 |
Meaning | Direct Read/Write command | PCF8574 I2C address | Set all bits low |
This 3 byte sequence sets all bits of a PCF8574 I/O expander
chip low.
All 3 bytes should be sent to the USB-ISS in one sequence. A gap will result in the
USB-ISS re-starting its internal command synchronization loop and ignoring the
message. After all bytes have been received the USB-ISS performs the IC2 write
operation out to the PCF8574 and sends a single byte back to the PC. This returned
byte will be 0x00 (zero) if the write command failed and non-zero if the write
succeeded. The PC should wait for this byte to be returned (timing out after
500mS) before proceeding with the next transaction.
Reading a single byte from I2C devices without internally addressable registers
This is similar to writing, except that you should add 1 to the device address
to make it an odd number. To read from a PCF8574 at address 0x40, you would use
0x41 as the address. (When the address goes out on the I2C bus, its the 1 in the
lowest bit position that indicates a read cycle is happening). Here is an
example of reading the inputs on a PCF8574 I/O expander:
I2C_SGL | PCF8574 I2C address + Read bit |
0x53 | 0x41 |
The USB-ISS module will perform the read operation on the I2C bus and send a single byte (the PCF8574 inputs) back to the PC. The PC should wait for the byte to be returned (timing out after 500mS) before proceeding with the next transaction.
Writing multiple bytes to devices that do not have an
internal address register.
There are very few, if any, real devices that operate this way, however some
people have programmed uControllers to work like this. Here is an example of
sending four bytes to a device at I2C address 0x30.
I2C_AD0 | Device I2C address + Write bit | Number of bytes to write | Data 1 | Data 2 | Data 3 | Data 4 |
0x54 | 0x30 | 0x04 | 0x12 | 0x34 | 0x56 | 0x78 |
After all bytes have been received the USB-ISS performs the IC2 write operation on the I2C bus and sends a single byte back to the PC. This returned byte will be 0x00 (zero) if the write command failed and non-zero if the write succeeded. The PC should wait for this byte to be returned (timing out after 500mS) before proceeding with the next transaction.
Reading multiple bytes from I2C devices without setting a new
address
This is used for devices that do not have an internal register address but
returns multiple bytes. Examples of such devices are the Honeywell ASDX DO
series pressure sensors. This command can also be used for devices that do
have an internal address which it increments automatically between reads and
doesn't need to be set each time, such as eeproms. In this case you would use
command I2C_AD1 or I2C_AD2 for the first read, then I2C_AD0 for subsequent
reads. Here is an
example of reading the two byte pressure from the Honeywell sensor.
I2C_AD0 | ASDX I2C address + Read bit | Number of bytes to read |
0x54 | 0xF1 | 0x02 |
The USB-ISS will perform the read operation on the I2C bus and send two bytes back to the PC - high byte first in this example for the ASDX sensor. The PC should wait for both bytes to be returned (timing out after 500mS) before proceeding with the next transaction.
Writing to I2C devices with a 1 byte internal address
register
This includes almost all I2C devices. Following the I2C_AD1 command you send the device
I2C address, then the devices internal register
address you want to write to and the number of bytes you're writing. The
maximum number of data bytes should not exceed 60 so as not to overflow the USB-ISS's internal buffer.
Primary USB-ISS command | Device Address + R/W bit | Device internal register | Number of data bytes | The data bytes | |
Byte Type | I2C_AD1 | Addr+R/W | Reg | Byte Count | Data |
Example | 0x55 | 0xE0 | 0x00 | 0x01 | 0x51 |
Meaning | Primary USB-ISS command | SRF08 I2C address | SRF08 command Reg | One command byte follows | Start ranging in cm |
This 5 byte sequence starts an SRF08 at address 0xE0 ranging.
All 5 bytes should be sent to the USB-ISS in one sequence. A gap will result in the
USB-ISS re-starting its internal command synchronization loop and ignoring the
message. After all bytes have been received the USB-ISS performs the IC2 write
operation out to the SRF08 and sends a single byte back to the PC. This returned
byte will be 0x00 (zero) if the write command failed and non-zero if the write
succeeded. The PC should wait for this byte to be returned (timing out after
500mS) before proceeding with the next transaction.
Here is another write example - this time an 8 byte sequence to initialize the
MD22 motor driver:
I2C_AD1 |
MD22 Addr+R/W |
Mode Reg |
Data byte count |
MD22 mode 1 |
Left Motor Stopped |
Right Motor Stopped |
Fast acceleration |
0x55 |
0xB0 |
0x00 |
0x04 |
0x01 |
0x00 |
0x00 |
0x02 |
Again the USB-ISS will respond with non-zero if the write succeeded and zero if it failed. A failure means that no acknowledge was received from the I2C device.
Reading from I2C devices with a 1 byte internal address
register
This is similar to writing, except that you should add 1 to the device address
to make it an odd number. To read from an SRF08 at address 0xE0, you would use
0xE1 as the address. (When the address goes out on the I2C bus, its the 1 in the
lowest bit position that indicates a read cycle is happening). The maximum
number of data bytes requested should not exceed 60 so as not to overflow the USB-ISS's internal buffer. Here is an
example of reading the two byte bearing from the CMPS03 compass module:
I2C_AD1 | CPMS03 I2C address + Read bit | CMPS03 bearing register | Number of bytes to read |
0x55 | 0xC1 | 0x02 | 0x02 |
The USB-ISS will perform the read operation on the I2C bus and send two bytes back to the PC - high byte first. The PC should wait for both bytes to be returned (timing out after 500mS) before proceeding with the next transaction.
Writing to I2C devices with a 2 byte internal address
register
This is primarily for eeprom's from 24LC32 (4k x 8) to 24LC1024 (2 * 64k x 8). Following the
I2C_AD2 you send the device
I2C address, then the devices internal register
address (2 bytes, high byte first for eeprom's) and then the number of bytes you're writing. The
maximum number of data bytes should not exceed 59 so as not to overflow the USB-ISS's
64 byte internal buffer.
Primary USB-ISS command | Device Address + R/W bit | High byte of internal Address | Low byte of internal Address | Number of data bytes | The data bytes | |
Byte Type | I2C_AD2 | Addr+R/W | Address High | Address Low | Byte Count | Data |
Example | 0x56 | 0xA0 | 0x00 | 0x00 | 0x20 | 0xnn |
Meaning | Primary USB-ISS command | 24LC32 I2C address | Address 0x0000 | Address 0x0000 | One command byte follows | 32 (0x20) data bytes |
This 37 byte sequence writes the last 32 bytes to address 0x0000 in the eeprom. All 37 bytes should be sent to the USB-ISS in one sequence. A gap will result in the USB-ISS re-starting its internal command synchronization loop and ignoring the message. After all bytes have been received the USB-ISS performs the IC2 write operation out to the eeprom and sends a single byte back to the PC. This returned byte will be 0x00 (zero) if the write command failed and non-zero if the write succeeded. The PC should wait for this byte to be returned (timing out after 500mS) before proceeding with the next transaction.
Reading from I2C devices with a 2 byte internal address
register
This is similar to writing, except that you should add 1 to the device address
to make it an odd number. To read from an eeprom at address 0xA0, you would use
0xA1 as the address. (When the address goes out on the I2C bus, its the 1 in the
lowest bit position that indicates a read cycle is happening). The maximum
number of data bytes requested should not exceed 64 so as not to overflow the USB-ISS's internal buffer. Here is an
example of reading 64 (0x40) bytes from internal address 0x0000 of an eeprom at
I2C address 0xA0.
I2C_AD2 | Device I2C address + Read bit | High byte of internal Address | Low byte of internal Address | Number of bytes to read |
0x56 | 0xA1 | 0x00 | 0x00 | 0x40 |
The USB-ISS will perform the read operation on the I2C bus and send 64 bytes back to the PC. The PC should wait for all 64 bytes to be returned (timing out after 500mS) before proceeding with the next transaction.
I2C_DIRECT commands
The I2C_DIRECT commands are used to build custom I2C sequences.
You send the
I2C_DIRECT command (0x57) followed by as many sub-commands as required. These
sub-commands are:
I2C Start | 0x01 | send start sequence |
I2C Restart | 0x02 | send restart sequence |
I2C Stop | 0x03 | send stop sequence |
I2C Nack | 0x04 | send NACK after next read |
I2C Read | 0x20 - 0x2F | reads 1-16 bytes |
I2C Write | 0x30 - 0x3F | writes next 1-16 bytes |
The I2C_Read sub-commands can read up to 16 bytes. 0x20 will read 1 byte,
0x21 will read 2 bytes, 0x2F will read 16 bytes. All bytes read are buffered and
sent after all sub-commands are processed.
The I2C_Write sub-commands can write up to 16 bytes. 0x30 will write 1 byte,
0x35 will write 6 bytes, 0x3F will write 16 bytes. The bytes to be written
immediately follow the write sub-command. It is up to you to make sure you
supply the correct number of bytes as specified in the sub-command.
Here is the sequence to write 0x55 to the PCF8574 I/O expander.
I2C_DIRECT | I2C_START | I2C_WRITE2 | PCF8574 I2C write address | Data | I2C_STOP |
0x57 | 0x01 | 0x31 | 0x40 | 0x55 | 0x03 |
The following will write 4 bytes to a 24LC512 EEPROM. This uses 2 internal address bytes.
Direct | Start | Write7 | I2C Address | Address High | Address low | Data1 | Data2 | Data3 | Data4 | Stop |
0x57 | 0x01 | 0x36 | 0xA0 | 0x00 | 0x00 | 0x11 | 0x22 | 0x33 | 0x44 | 0x03 |
And this will read 4 bytes from a 24LC512 EEPROM.
Direct | Start | Write3 | I2C Address | Address High | Address low | Restart | Write1 | I2C address+RD | Read3 | Nack | Read1 | Stop |
0x57 | 0x01 | 0x32 | 0xA0 | 0x00 | 0x00 | 0x02 | 0x30 | 0xA1 | 0x22 | 0x04 | 0x20 | 0x03 |
Note that as part of the read sequence we first have to write the address that we want to read from. We read 3of the 4 bytes then set the NACK flag before reading the last byte. This is according to I2C specifications, however its not really necessary and the following will work just as well:
Direct | Start | Write3 | I2C Address | Address High | Address low | Restart | Write1 | I2C address+RD | Read4 | Stop |
0x57 | 0x01 | 0x32 | 0xA0 | 0x00 | 0x00 | 0x02 | 0x30 | 0xA1 | 0x23 | 0x03 |
The response to the I2C_DIRECT command is a variable number of
bytes, but it will always be at least two. You should read these two bytes first
as they are the status bytes. The fist byte is the ACK (0xFF) or NACK (0x00)
status.
If you get an ACK the command was successful and the second byte contains the
number of bytes to read. If you have not requested any reads then it will be
zero, otherwise you should now read the number of bytes available.
If you get a NACK the command failed and the second byte contains the reason, as
follows:
Error Type | Error Code | Comment |
Device Error | 0x01 | No ACK from device |
Buffer Overflow | 0x02 | You must limit the frame to < 60 bytes |
Buffer Underflow | 0x03 | More write data was expected than sent |
Unknown command | 0x04 | Probably your write count is wrong |
Checking for the existence of an I2C device (V5 and later firmware only)
I2C_TEST | Device I2C Address |
0x58 | 0xA0 |
This 2 byte command was added to V5 following customer requests. It checks for the ACK response to a devices address. A single byte is returned, zero if no device is detected or non-zero if the device was detected.