Overview

We looked at using one of three communications protocols for formalizing communications between our "master controller" PIC and our "rocket controller" PIC: SPI, I2C, and UART. Each would need to be bidirectional, use as few pins as possible, and ideally have some measure of hardware support on our PIC microcontrollers.

SPI

Serial Peripheral Interface [SPI] uses at least 4 wires to communicate between devices. SPI is fairly straightforward, holding a significant speed advantage over the other considered protocols. SPI typically follows a single-master, multiple-slave topology, which means that any communication from a slave device to the master device must be initiated by the master device.

Our PIC microcontrollers have a native SPI module which supports both master and slave operation. From a software perspective, in order to use SPI, we would need to modify our existing SPI module wrapper library to support configuration and operation in slave mode.

I2C

The Inter-Integrated Circuit [I2C] protocol communicates from a master device to a large number of addressed slave devices. I2C is generally slower and more complicated than either SPI or UART. It, however, uses only two communication wires—a clock line and a data line—to communicate with hundreds of slave devices. I2C also specifies bits for acknowledging and not acknowledging transmissions and indicating the read/write nature of transmitted operations.

Similar to SPI, the master device controls the clock, and any data transmission from a slave device to a master device must be initiated by the master device. Also, our PIC microcontrollers have a native I2C module which supports both master and slave operation. From a software perspective, in order to use this, we would need to modify our existing I2C module wrapper library to support configuration and operation of a PIC in slave mode.

We used I2C to send commands from a PIC, configured as an I2C master, to our servo controller. Due to complications which arose when configuring a PIC as an I2C slave and the limitations of a master-slave topology, we ultimately decided against using I2C as our main communications protocol.

UART

Universal Asynchronous Receiver Transmitter [UART], like I2C, is often a two-wire protocol. Unlike I2C, however, there is no formal master-slave relationship among devices, no transmitted clock signal, nor a formalized data transmission "packet" structure. UART sends and receives data bytes serially at a predetermined rate. A device receives bytes through its "RX" and sends bytes through its "TX" pin. When connecting two devices, the "TX" of the first device is connected to the "RX" of the second device, and vice versa.

Our PIC microcontrollers have a native UART module and an accompanying software library which supports writing and reading from the appropriate UART transmit and receive buffers.

Implementation

We began by implementing a single UART connection between the "master controller" PIC and the "rocket controller" PIC. To conserve digital I/O pins in the main section of the PIC, this UART used pins 4 and 5 (see diagram at right) on the board's ICD3 header.

We showed that we could use this system to send and request data between two PICs. This worked for small demonstrations, but became an issue as our project scaled up. Central to this issue was the blocking nature of the UART software library's function for reading from a software buffer uart_gets().

As data is read in from a PIC's hardware UART buffers, interrupts handle the transfer of data into larger software buffers. Calling uart_gets() will read from