Messages Exchange with FPGA as Slave
The implementation builds onto the Byte Module code shown earlier. We will start by explaining how to pass multidimensional arrays through ports.
On Altera, we can the multidimensional arrays available in system verilog HDL
wire [nrRWregs+nrROregs-1:0] [31:0] registers;
The implementation is slightly more complicated on Xilinx, because Verilog 2001 doesn’t allow multidimensional arrays to be used as inputs or outputs. Instead, we work around this by flatten the 2D registers array into two vectors. One for input, and one for the output ports as shown in the code fragments below.
Flatten the 2-dimensional array,
registers, into vectors
wire [31:0] roRegs2D[0:nrROregs-1];
for ( nn = 0; nn < nrRWregs; nn = nn + 1)
assign rwRegs1D[32*nn+31:32*nn] = registers[nn]; // flatten
for ( nn = 0; nn < nrROregs; nn = nn + 1)
assign roRegs2D[nn] = roRegs1D[32*nn+31:32*nn]; // inflate
Inflate the vectors,
roRegs1D, into a 2-dimensional array
wire [0:31] registers[0:nrRWregs+nrROregs-1]; genvar nn; for ( nn = 0; nn < nrRWregs; nn = nn + 1 ) begin :nnRW assign registers[nn] = rwRegs1D[32*nn+31:32*nn]; end for ( nn = 0; nn < nrROregs; nn = nn + 1 ) begin :nnRO assign roRegs1D[32*nn+31:32*nn] = registers[nn+nrRWregs]; end[/code]
The timing diagram below shows the relation between the different signals at the message level on Xilinx.
The Altera implementation is more optimized, as it needs to run at 200 MHz. The gate level simulation is shown below;
Finite State Machine
This message module converts the bytes into messages and visa versa. The protocol is implemented using a state machine with 4 states:
- Idle (0)
- Transmit status (1), transmits 8-bit status to master
- Transmit register value (2) , transmits a 32-bit register value to the master
- Receive register value (3), receives a 32-bit register value from the master
An additional state-like variable,
byteId, is used to keeps track of what byte to transmit or receive.
The complete project including constraints and test bench is available through
SPI Slave, main module,
spi_msg.svon Altera (or
SPI Slave, message interface,
spi_msg_if.svon Altera (or
To verify the implementation, run the test bench (
spi_msg_tb.v) using gate level simulation. This test bench will monitor the communication and report errors when found. In the real world, we connect the Arduino SPI Master that acts just like the test bench.
This article introduced SPI as a protocol and expanded it to exchange messages.