Verilog Inter-FPGA SPI Communication

2.8k views Asked by At

I am trying to communicate between two Xilinx Spartan 3e FPGAs using SPI communication and GPIO pins. The goal is to have a master-slave communication working but for now I am just sending data from Master to Slave and trying to see if the data received is correct.

This is the Master code that sends 16 bits of data to Slave in serial format. After checking on the scope numerous times it seems correct.

 module SPI_MASTER_SEND(
    input CLK_50MHZ,
    input [1:0] ID_user,
    input [15:0] DATA_TO_SEND,
    output reg SData,
    output SCLK,
    output notCS
    );
parameter max = 20; // max-counter size
reg [6:0]div_counter;
wire [6:0] data_count;
assign data_count[6:0] = div_counter[6:0];
reg CLOCK;
reg Clk_out;
reg CompleteB;

//have the notCS be low for 20 pulses, and hi for 20 pulses.
//sends 16 bits of data during low pulse

always@(posedge CLOCK) begin
   if (div_counter == max-1)
     begin
     div_counter <= 0;
     Clk_out <= ~Clk_out;
     end
   else
     begin
     div_counter <= div_counter + 1;
     end
end
assign notCS = Clk_out;
reg flag;
assign SCLK = flag&&CLOCK;   //Clock when notCS is down for 16 pulses

always @(posedge CLOCK) // Parallel to Serial
begin
if (data_count >= 7'd3 && data_count < 7'd18 && notCS ==0)
    begin

        SData <= DATA_TO_SEND[18-data_count];
        flag <=1;
        CompleteB<=0;

    end
else if (data_count == 7'd18 && notCS ==0)
    begin
        flag <=1;
        SData<=DATA_TO_SEND[0];
        CompleteB<=1;
    end

else


    begin
        CompleteB<=0;
        flag<=0;
        SData <= 0;
    end
end

endmodule

This is the code on the Slave receiving end, I check the data on the falling edge of the clock (have tried posedge too) to avoid any timing conflicts. The Clock,notCS, and SI (serial in) are all coming from the master via gpio pins

module SPI_COMM_SLAVE(CLK,SI,notCS,outputPO,ID_user);

input  CLK,SI,notCS; 
input [1:0] ID_user;
reg [15:0] PO;
output reg [15:0] outputPO;
reg CompleteB;
reg C;

reg [5:0] cnt;
initial cnt[5:0] = 6'b000000;


always@(negedge CLK) 

begin

if (cnt < 6'd15)
begin
PO[15-cnt] <= SI;
cnt <= cnt + 1'b1;
CompleteB<=0;
end
else if (cnt == 6'd15)
begin
    PO[0] <= SI;
    cnt<=6'b000000;
    CompleteB <=1;


end
else
begin
cnt <= cnt;
CompleteB<=0;
end
end

always@(*)begin
    if(CompleteB == 1)
    outputPO[15:0] <= PO[15:0];
    else
    outputPO[15:0]<=outputPO[15:0];
end

endmodule 

After outputting the "outputPO" to the DAC it gives a bunch of garbage and is clearly not a single value. Thank you

1

There are 1 answers

0
davidd On

To debug an FPGA problem like this you should absolutely simulate the design. If you have not already, create a testbench to initiate a write in the master module and connect the slave module as it would be in the system. Check the wave forms match the behavior you expect. It is not effective debugging in hardware until this simulation is working. If you do not have access to a paid simulator there are free verilog simulators available. One suggestion is to build this simulation environment in EDA Playground and then you can share it here as part of the problem description.

Secondly I noticed a number of things that could be improved the quality and readability of your code which does make debugging easier:

  1. Indent code inside blocks (begin/end pairs, etc).
  2. Always use non-blocking assignments inside clocked processes and blocking assignments in combinatorial blocks. For example the non-blocking statements in your combinatorial process assigning outputPO in SPI_COMM_SLAVE are wrong. This can lead to simulation not matching synthesized results.
  3. Latches are not recommended for fpga designs. SPI_COMM_SLAVE will synthesize a 16bit latch for outputPO. Consider making this signal a register.
  4. Your master architecture looks more complex than it needs to be. Consider separating the functionality that initiates the spi transactions (div_counter) from the logic that does the actual spi transaction.