0

I have wasted far too much time on this.

So here goes. Started off coding up a basic SPI slave device, to work with a Raspberry Pi as SPI master. Using a Xilinx XC6SLX16 as the slave. Using a logic analyzer in parallel with the FPGA and the RPi. Garbage read back to the RPi. So I have whittled the code down to simply triggering on the SPI clock positive edge, incrementing a 3-bit counter to then write out the counter bits on three general purpose I/O lines for the logic analyzer to display. I have reduced the RPi SPI clock to 25khz (SPI divider of 10,000).

    module laser1(
    input sclk,
         output miso,
         output [2:0] out
);
reg miso_r;
reg [2:0] count;
reg [7:0] data1;

initial begin
   data1 = 8'b11000101;
        count = 3'b000;
end

assign miso = miso_r;
assign out = count;

always @(posedge sclk) begin
   case (count)
           0: miso_r <= data1[0];
                1: miso_r <= data1[1];
                2: miso_r <= data1[2];
                3: miso_r <= data1[3];
                4: miso_r <= data1[4];
                5: miso_r <= data1[5];
                6: miso_r <= data1[6];
                7: miso_r <= data1[7];
        endcase
        count <= count + 1'b1;
        if (count == 3'b111)
           count <= 3'b000;
end
endmodule

I have ended up using a case statement but it still acts idiotic. I used to have:

miso_r <= data1[count];

On the logic analyzer, the 3 bits of 'count' are channels 4,5,6:

enter image description here

With each triggering from the SPI clock, we see 'count' take on these values:

0,1,2,3,5,6,7,0,1,3,5,6,7,0,1,3

If I change the index into data1 to be a constant, 'count' increments normally. The very act of using it as a bit-select totally wrecks its value.

This is beyond weird. Any insights are appreciated...

This is the contents of the constraints file, showing the label for each pin out of the package file:

NET miso LOC="F9"; // IO_L40P_0
NET sclk LOC="A9"; // IO_L34N_GCLK18_0
NET out<2> LOC="F7"; // IO_L5P_0
NET out<1> LOC="D6"; // IO_L7P_0
NET out<0> LOC="P9"; // IO_L14N_D12_2
  • I suspect your FPGA is seeing more clock edges than you think you are sending it. Can you add ~100 ohms in series with the RPi clock output to slow down the clock edges? – The Photon Feb 04 '20 at 22:16
  • OK, I was wondering if it might be that too, which is why I slowed it from (approx) 1MHz to 25KHz. Also note that if I use a constant inside the square brackets (i.e. data1[3]) the count goes perfectly. – Keith E. Fleming Feb 04 '20 at 22:31
  • Just changing the clock frequency doesn't (usually) change the dv/dt of the clock edges, so even though your clock period is 40 us, you could have some little 100 ns glitches in your edges that you can't see with your logic analyzer, but still cause the CPLD to think a whole clock cycle is intended. – The Photon Feb 04 '20 at 22:35

2 Answers2

0

I'm not sure if this is your problem, but I don't think you are handling the increment of count correctly. This variable can have exactly 8 values (in hardware) and you use all 8 of those values. So, there is no need to explicitly reset count when it reaches 111...just increment it and let it roll over to zero.

I am also suspicious of the logic that you use. You increment count using a non-blocking assignment and then immediately try to do something with its current value. I've never tried this but I'm not sure that it would synthesize reliable hardware...you may have a race between the increment and the check. I would do something like this:

if (count == last_value)
  count <= 0;
else
  count <= count+1;
Elliot Alderson
  • 31,192
  • 5
  • 29
  • 67
0

Thank you fellas for your insights. Turns out, registering the SPI CLK is what got it done. I first had to bring back the FPGA clock as an input, then created a one-bit register 'sclk_r', then a new 'always' block which registered the wire input 'sclk' with the new register 'sclk_r'. The 'Pi SPI clock is about 1MHz. So, the FPGA is oversampling it at 50:1 because the board I am using has a 50MHz clock. Posting this in case any other new (like me) FPGA designers run into something similar. Basically, 'register' your noisy inputs :)

module laser1(
    input sclk, clk,
     output miso,
     output [2:0] out
);

reg miso_r;
reg sclk_r;
reg [2:0] count;
reg [7:0] data1;

initial begin
    count = 3'b000;
    data1 = 8'b11000101;
end

assign miso = miso_r;
assign out = count;

always @(posedge clk)      <--- new!
   sclk_r <= sclk;

always @(posedge sclk_r) begin   <--- trigger on the registered SPI clock!!!
    count = count + 1'b1;
   case (count)
       0: miso_r = data1[7];
        1: miso_r = data1[6];
        2: miso_r = data1[5];
        3: miso_r = data1[4];
        4: miso_r = data1[3];
        5: miso_r = data1[2];
        6: miso_r = data1[1];
        7: miso_r = data1[0];
    endcase 
end
endmodule
  • Might want to have a look at [this](https://electronics.stackexchange.com/a/653452/53368) recent answer regarding detecting rising edges. You're best of using an edge detector on sclk rather than trying to look for the posedge of sclk itself. – Tom Carpenter Feb 12 '23 at 15:01
  • You can also replace your case statement with just `miso_r = data1[3'd7 - count]`. – Tom Carpenter Feb 12 '23 at 15:03