Skip to content

Communications

In order to interface with the generated core, we need some method to get data on and off the FPGA itself. It was decided that SPI would be a good fit - it's fairly common, especially on micrcontrollers, and relatively easy to use.

SPI connects with a hardware module on the FPGA that is waiting for an instruction & the relevant data to arrive, so that it can set the appropriate buses and coordinate data.

An Arduino library (provided by this project) can be used to abstract the communication away into a few simple function calls, helping to improve accessibility. Currently it has been tested on a Teensy 3.2 and the Raspberry Pi Pico.

Short introduction into SPI

Serial Protocol Interface (SPI) is a protocol that allows devices to communicate in a synchronous, full-duplex manner. It has 4 pins: clock (CLK), chip select (CS), controller-out-peripheral-in (COPI) and peripheral-out-controller-in (POCI).

Three wires are handled by the controller (CLK, CS, COPI) and one by the peripheral (POCI). CLK and CS coordinate the communication, whilst COPI and POCI contain the data which is being transferred across the devices.

Custom Protocol

Since SPI does not directly define a communications protocol, instead only how it works electrically, it is necessary to outline a protocol that will allow us to communicate with the FPGA.

Packets of information can only be 8 bytes long at maximum, being segmented into 1 byte increments.

The first byte must be a valid instruction (READ, WRITE, STREAM, BIND_WRITE_ADDRESS, BIND_READ_ADDRESS, TRANSFER, REPEAT), followed up by additional information if required. For example, if you are executing a WRITE instruction, you need to provide a 3-byte address and a 4-byte value which gets written to the address; whilst a READ instruction only requires the 3-byte address as additional data.

In theory any device which implements this protocol will be able to communicate with the FPGA, so it isn't limited to only microcontrollers. This could be done on a PC which bit-bangs the wires, though its unlikely to be useful in that context.

Protocol Reference

Mnemonic Instruction Fields Format Action
NOP 0x00 No fields NOP No operation
WRITE 0x01 ADDRESS (3 bytes),
VALUE (4 bytes)
WRITE ADDRESS VALUE Write VALUE to ADDRESS
READ 0x02 ADDRESS (3 bytes) READ ADDRESS Read a value from ADDRESS
(This only places the value in an internal register.)
STREAM 0x03 VALUE (4 bytes) STREAM VALUE Stream a VALUE to a pre-determined address, and recieve a value simultaneously
RESERVED 0x04 - - Reserved
BIND_READ_ADDRESS 0x05 ADDRESS (3 bytes) BIND_READ_ADDRESS ADDRESS Bind to an address to read from when running a STREAM instruction
BIND_WRITE_ADDRESS 0x06 ADDRESS (3 bytes) BIND_WRITE_ADDRESS ADDRESS Bind to an address to write a value to when running a STREAM instruction
TRANSFER 0x07 No fields TRANSFER Transfer 1 byte across SPI, advancing the internal data pointer by 1
REPEAT 0x08 No fields REPEAT Reset the internal data pointer
N/A 0x09 - 0xFE No fields No format Unused range
RESERVED 0xFF - - Reserved

Arduino Library

Info

The library is currently on the dev branch, under titan/titan/comms/TitanComms

A very simple Arduino library is provided for use on the Pico or Teensy 3.2 microcontrollers. It provides functionality for reading, writing and streaming to the core.

However, it is not necessary to use this library. Any device with an SPI connection that implements the protocol is able to communicate to the core.


Last update: 2024-04-24