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