Sunday, October 20, 2013

Week 9: NXT-Arduino I2C Interface Protocols

Now that I2C is working and we are capable of bidirectional data transfer at the behest of the master device, it makes sense for there to be some standardized protocol in play to govern communications.

 To recap the working model I'm going with, the NXT is the bus master and will initiate communication with a sensor when polling it. This data transaction will first involve the NXT transmitting a "register selection" packet to the sensor, the payload of which will contain the address of the sensor register to retrieve. The sensor will, upon receipt, switch to the proper register. In my Arduino-side code, this is emulated with a state variable. It is important to note that the register selection packet does not instruct the sensor to do anything other than select a register. It is not until the NXT runs readI2CReply that a "data request" packet is send over I2C to the sensor, upon which the sensor replies with the data requested. At this point all communication should cease (maybe barring an ACK packet), and the bus will lie dormant until another poll begins.

Fig 1. Diagram showing data transaction and change of register selection.
Another critical piece of the data transfer process that I've been somewhat glossing over is the actual format of the I2C packet. While the Arduino's Wire library will handle most of the I2C nuts and bolts, abstracting the user from having to program it all, RobotC makes no such allowance. In RobotC the sendI2CMsg function accepts a ubyte pointer to an array containing entries which constitute an I2C packet. Like all packets this one consists of a header, and a payload. The header contains entries for message size and address, while the payload contains the packet's data.

Fig 2. General packet structure of a RobotC packet, to be transmitted by the NXT.

An important note on the Arduino's Wire library, the transmission of data using the Wire.send() method will transmit whatever I2C bytes are passed to it. This is done with 1-byte payload packets for all data given; passing in an integer will result in data loss as it will overflow the 1-byte payload allocated for it. This can be overcome by splitting transmission data into multiple pieces, and then passing the send() method an array of bytes, this will be realized as a series of 1-byte packet transmissions back to the NXT. RobotC's readI2CReply() must have the size of this reply packet provided as an argument to ensure that all the sensor data is received properly.