This continues the third part of Math Talk. This page shows a master implementation of the message protocol described earlier.
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.
Registers
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 rwRegs1D
and roRegs1D
genvar nn;
wire [31:0] roRegs2D[0:nrROregs-1];
for ( nn = 0; nn < nrRWregs; nn = nn + 1)
begin :nnRW
assign rwRegs1D[32*nn+31:32*nn] = registers[nn]; // flatten
end
for ( nn = 0; nn < nrROregs; nn = nn + 1)
begin :nnRO
assign roRegs2D[nn] = roRegs1D[32*nn+31:32*nn]; // inflate
end[/code]
Inflate the vectors, rwRegs1D
and roRegs1D
, into a 2-dimensional array registers
.
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]
Timing
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.
Sources
The complete project including constraints and test bench is available through
-
SPI Slave, main module,
spi_msg.sv
on Altera (orspi_msg.v
on Xilinx)
-
SPI Slave, message interface,
spi_msg_if.sv
on Altera (orspi_msg_if.v
on Xilinx)
Verification
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.