The VEX Integrated motor encoders have been available for over a year and we are still experiencing some frustrating technical issues. So that teams may understand why failures are happening, I’m going to present some information to explain how they work and what can cause software that is using them to become lost. I am not going to explain the details and differences of the ROBOTC and EasyC implementations, however, the details of the communications protocol were made public last year, and I have provided an implementation for the VEXpro controller which is open source, so none of the following is proprietary. This post will be in more than one part, part1 is covering the basics of the communication protocol.
The integrated motor encoder uses a very different connection method to the other VEX sensors that is known as Inter Integrated Circuit or I2C. Phillips invented this interface in the early 1980s as a low cost means of extending the IO capabilities of the simple microprocessors being used in consumer products at that time. The I2C bus uses synchronous serial communication with only two wires, a clock generated by the host (or master) device is used to control the transfer of bits on a data line either to or from a slave device. The two wires are typically called SCL for the clock and SDA for the data. In the four wire cables supplied by VEX, the clock is on the yellow wire and data on the white wire. The other two wires, red and black, supply power to the IME with the black wire also acting as the common ground reference for the system.
The I2C master always initiates a transaction, in our case this is the cortex, every slave device needs a unique address (think of the address of you house) so the master can talk to it. In many designs these addresses are fixed or set by configuration pins on the particular device, however, as I will explain later it works a little differently with the IMEs.
To allow bi-directional data transfer SCL and SDA are driven by open-drain drivers. The wires are pulled high (to the positive voltage) by using resistors, the master or slave device can only pull the wire low (to 0 volts). A typical I2C bus looks like this.
Data is transferred in 8 bit units called bytes, a data bit is placed on the SDA wire and the clock wire pulsed. A data bit should only change when the SCL wire is low, if SCL is high then the change on the SDA wire has a special meaning. If it changes from high to low this is called a START bit, if it changes from low to high this is called a STOP bit. Only the master device (the cortex) should create start or stop bits as they signify the start and end of a message.
So how does the master communicate with the slave? A typical sequence to send one byte to a slave would be as follows.
The master sends a START bit
The master sends the address of the slave it wishes to communicate with (normally 7 bits but it can be 10)
The master sends 1 bit indicating if data will be transferred to or from the slave.
The slave acknowledges it is ready by pulling SDA low for one clock cycle
The master sends the data byte 1 bit at a time starting with the msb (most significant bit)
The slave acknowledges it has received the data by pulling SDA low for one clock cycle.
The master sends a STOP bit.
IMEs differ from most I2C devices because the number of devices on the bus can be different for each robot. A technique called dynamic addressing is used, when IMEs are first powered on they all have the same address, the bus master (the cortex) learns how many devices are connected and assigns a new address to each one it finds before normal communication is started. Because each device has the same address when first powered on, there also needs to be a method of communicating with each IME so the new address can be assigned, this is done by disconnecting the SCL and SDA wires from the I2C bus for all but the IME nearest to the cortex. After a new address has been assigned that IME allows the next IME in the chain to be connected. Here is a high level diagram showing connections, note that the yellow (SCL) and white (SDA) wires are switched inside each IME.
Initially each IME has an address of 0x60 (“0x” signifies a hexadecimal number), after the IME chain is initialized they will typically have addresses starting at 0x20 and incrementing by 2 (0x20, 0x22, 0x24 etc.). Once initialized, a message can be sent to each IME in turn asking for the current number of encoder pulses it has counted. A typical message would send one data byte from the cortex to the IME indicating what information is required followed by the cortex reading a number of data bytes. Using an oscilloscope a single message can be captured and looks like this.
The yellow trace is the SCL wire, the blue trace is the SDA wire. This message was reading 6 bytes of data from the IME at address 0x20. A close up look at the beginning of this transaction is as follows.
I have added annotations to this capture as well as vertical lines showing where the SCL wire is changing from low to high, this is where bits on the SDA wire are valid. The transaction starts out with a START bit (indicated by the red S) followed by the address 0x20 and a write transaction bit. The slave responds with an acknowledge bit where it holds the SDA line low (indicated by the green A). The master sends one data byte, 0x40, without going into details this means it wants to read the encoder count. The master now sends another START bit (known as a repeated start, this avoids having to send STOP followed by START) followed by the IMEs address again, it then reads 6 data bytes from the IME. As the master receives each data byte it acknowledges all except the last one where a not-acknowledge is used to indicate that all data has been received. Finally the master sends a STOP bit.
With all this as background, part 2 will explain some of the things that can go wrong with this communication and possible improvements we can implement in user code.