use SPI slave
[trilby-hat-fpga] / SPI_slave.v
1 // https://www.fpga4fun.com/SPI2.html
2
3 module SPI_slave(clk, SCK, MOSI, MISO, SSEL, LED);
4
5 input clk;
6
7 input SCK, SSEL, MOSI;
8 output MISO;
9
10 output LED;
11
12 // sync SCK to the FPGA clock using a 3-bits shift register
13 reg [2:0] SCKr;  always @(posedge clk) SCKr <= {SCKr[1:0], SCK};
14 wire SCK_risingedge = (SCKr[2:1]==2'b01);  // now we can detect SCK rising edges
15 wire SCK_fallingedge = (SCKr[2:1]==2'b10);  // and falling edges
16
17 // same thing for SSEL
18 reg [2:0] SSELr;  always @(posedge clk) SSELr <= {SSELr[1:0], SSEL};
19 wire SSEL_active = ~SSELr[1];  // SSEL is active low
20 wire SSEL_startmessage = (SSELr[2:1]==2'b10);  // message starts at falling edge
21 wire SSEL_endmessage = (SSELr[2:1]==2'b01);  // message stops at rising edge
22
23 // and for MOSI
24 reg [1:0] MOSIr;  always @(posedge clk) MOSIr <= {MOSIr[0], MOSI};
25 wire MOSI_data = MOSIr[1];
26
27 // we handle SPI in 8-bits format, so we need a 3 bits counter to count the bits as they come in
28 reg [2:0] bitcnt;
29
30 reg byte_received;  // high when a byte has been received
31 reg [7:0] byte_data_received;
32
33 always @(posedge clk)
34 begin
35   if(~SSEL_active)
36     bitcnt <= 3'b000;
37   else
38   if(SCK_risingedge)
39   begin
40     bitcnt <= bitcnt + 3'b001;
41
42     // implement a shift-left register (since we receive the data MSB first)
43     byte_data_received <= {byte_data_received[6:0], MOSI_data};
44   end
45 end
46
47 always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111);
48
49 // we use the LSB of the data received to control an LED
50 reg LED;
51 always @(posedge clk) if(byte_received) LED <= byte_data_received[0];
52
53 reg [7:0] byte_data_sent;
54
55 reg [7:0] cnt;
56 always @(posedge clk) if(SSEL_startmessage) cnt<=cnt+8'h1;  // count the messages
57
58 always @(posedge clk)
59 if(SSEL_active)
60 begin
61   if(SSEL_startmessage)
62     byte_data_sent <= cnt;  // first byte sent in a message is the message count
63   else
64   if(SCK_fallingedge)
65   begin
66     if(bitcnt==3'b000)
67       byte_data_sent <= 8'h00;  // after that, we send 0s
68     else
69       byte_data_sent <= {byte_data_sent[6:0], 1'b0};
70   end
71 end
72
73 assign MISO = byte_data_sent[7];  // send MSB first
74 // we assume that there is only one slave on the SPI bus
75 // so we don't bother with a tri-state buffer for MISO
76 // otherwise we would need to tri-state MISO when SSEL is inactive
77
78 endmodule