From: Dobrica Pavlinusic Date: Thu, 6 Jan 2022 12:26:13 +0000 (+0100) Subject: SPI slave from https://www.fpga4fun.com/SPI2.html X-Git-Url: http://git.rot13.org/?p=trilby-hat-fpga;a=commitdiff_plain;h=0b38475814a5581fa5317ad9a919105d6ce6940c;ds=sidebyside SPI slave from https://www.fpga4fun.com/SPI2.html --- diff --git a/SPI_slave.v b/SPI_slave.v new file mode 100644 index 0000000..fab5b0a --- /dev/null +++ b/SPI_slave.v @@ -0,0 +1,78 @@ +// https://www.fpga4fun.com/SPI2.html + +module SPI_slave(clk, SCK, MOSI, MISO, SSEL, LED); + +input clk; + +input SCK, SSEL, MOSI; +output MISO; + +output LED; + +// sync SCK to the FPGA clock using a 3-bits shift register +reg [2:0] SCKr; always @(posedge clk) SCKr <= {SCKr[1:0], SCK}; +wire SCK_risingedge = (SCKr[2:1]==2'b01); // now we can detect SCK rising edges +wire SCK_fallingedge = (SCKr[2:1]==2'b10); // and falling edges + +// same thing for SSEL +reg [2:0] SSELr; always @(posedge clk) SSELr <= {SSELr[1:0], SSEL}; +wire SSEL_active = ~SSELr[1]; // SSEL is active low +wire SSEL_startmessage = (SSELr[2:1]==2'b10); // message starts at falling edge +wire SSEL_endmessage = (SSELr[2:1]==2'b01); // message stops at rising edge + +// and for MOSI +reg [1:0] MOSIr; always @(posedge clk) MOSIr <= {MOSIr[0], MOSI}; +wire MOSI_data = MOSIr[1]; + +// we handle SPI in 8-bits format, so we need a 3 bits counter to count the bits as they come in +reg [2:0] bitcnt; + +reg byte_received; // high when a byte has been received +reg [7:0] byte_data_received; + +always @(posedge clk) +begin + if(~SSEL_active) + bitcnt <= 3'b000; + else + if(SCK_risingedge) + begin + bitcnt <= bitcnt + 3'b001; + + // implement a shift-left register (since we receive the data MSB first) + byte_data_received <= {byte_data_received[6:0], MOSI_data}; + end +end + +always @(posedge clk) byte_received <= SSEL_active && SCK_risingedge && (bitcnt==3'b111); + +// we use the LSB of the data received to control an LED +reg LED; +always @(posedge clk) if(byte_received) LED <= byte_data_received[0]; + +reg [7:0] byte_data_sent; + +reg [7:0] cnt; +always @(posedge clk) if(SSEL_startmessage) cnt<=cnt+8'h1; // count the messages + +always @(posedge clk) +if(SSEL_active) +begin + if(SSEL_startmessage) + byte_data_sent <= cnt; // first byte sent in a message is the message count + else + if(SCK_fallingedge) + begin + if(bitcnt==3'b000) + byte_data_sent <= 8'h00; // after that, we send 0s + else + byte_data_sent <= {byte_data_sent[6:0], 1'b0}; + end +end + +assign MISO = byte_data_sent[7]; // send MSB first +// we assume that there is only one slave on the SPI bus +// so we don't bother with a tri-state buffer for MISO +// otherwise we would need to tri-state MISO when SSEL is inactive + +endmodule