2023-05-30 11:33:08 +00:00
|
|
|
module spi_slave (
|
2021-06-13 11:45:08 +00:00
|
|
|
// Control/Data Signals,
|
2023-05-30 11:33:08 +00:00
|
|
|
input i_sys_clk, // FPGA Clock
|
|
|
|
output reg o_rx_data_valid, // Data Valid pulse (1 clock cycle)
|
|
|
|
output reg [7:0] o_rx_byte, // Byte received on MOSI
|
|
|
|
input i_tx_data_valid, // Data Valid pulse to register i_tx_byte
|
|
|
|
input [7:0] i_tx_byte, // Byte to serialize to MISO.
|
2021-06-13 11:45:08 +00:00
|
|
|
|
|
|
|
// SPI Interface
|
2023-05-30 11:33:08 +00:00
|
|
|
input i_spi_sck,
|
|
|
|
output reg o_spi_miso,
|
|
|
|
input i_spi_mosi,
|
|
|
|
input i_spi_cs_b
|
|
|
|
);
|
2021-06-13 11:45:08 +00:00
|
|
|
|
|
|
|
reg [2:0] r_rx_bit_count;
|
|
|
|
reg [2:0] r_tx_bit_count;
|
|
|
|
reg [7:0] r_temp_rx_byte;
|
|
|
|
reg [7:0] r_rx_byte;
|
|
|
|
reg r_rx_done;
|
|
|
|
reg r2_rx_done;
|
|
|
|
reg r3_rx_done;
|
|
|
|
reg [7:0] r_tx_byte;
|
|
|
|
|
|
|
|
// Purpose: Recover SPI Byte in SPI Clock Domain
|
|
|
|
// Samples line on correct edge of SPI Clock
|
2023-05-30 11:33:08 +00:00
|
|
|
always @(posedge i_spi_sck /* or posedge i_spi_cs_b*/) begin
|
2021-06-13 11:45:08 +00:00
|
|
|
if (i_spi_cs_b) begin
|
|
|
|
r_rx_bit_count <= 0;
|
|
|
|
r_rx_done <= 1'b0;
|
|
|
|
end else begin
|
|
|
|
r_rx_bit_count <= r_rx_bit_count + 1;
|
|
|
|
r_temp_rx_byte <= {r_temp_rx_byte[6:0], i_spi_mosi};
|
|
|
|
|
|
|
|
if (r_rx_bit_count == 3'b111) begin
|
|
|
|
r_rx_done <= 1'b1;
|
|
|
|
r_rx_byte <= {r_temp_rx_byte[6:0], i_spi_mosi};
|
|
|
|
end else if (r_rx_bit_count == 3'b010) begin
|
|
|
|
r_rx_done <= 1'b0;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2021-09-01 21:50:13 +00:00
|
|
|
|
2023-05-30 11:33:08 +00:00
|
|
|
|
2021-06-13 11:45:08 +00:00
|
|
|
|
|
|
|
// Purpose: Cross from SPI Clock Domain to main FPGA clock domain
|
|
|
|
// Assert o_rx_data_valid for 1 clock cycle when o_rx_byte has valid data.
|
2023-05-30 11:33:08 +00:00
|
|
|
always @(posedge i_sys_clk) begin
|
2021-06-13 11:45:08 +00:00
|
|
|
// Here is where clock domains are crossed.
|
|
|
|
// This will require timing constraint created, can set up long path.
|
|
|
|
r2_rx_done <= r_rx_done;
|
|
|
|
r3_rx_done <= r2_rx_done;
|
2023-05-30 11:33:08 +00:00
|
|
|
if (r3_rx_done == 1'b0 && r2_rx_done == 1'b1) begin // rising edge
|
|
|
|
o_rx_data_valid <= 1'b1; // Pulse Data Valid 1 clock cycle
|
2021-06-13 11:45:08 +00:00
|
|
|
o_rx_byte <= r_rx_byte;
|
|
|
|
end else begin
|
|
|
|
o_rx_data_valid <= 1'b0;
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
reg [2:0] SCKr;
|
|
|
|
always @(posedge i_sys_clk) SCKr <= {SCKr[1:0], i_spi_sck};
|
2023-05-30 11:33:08 +00:00
|
|
|
wire SCK_risingedge = (SCKr[2:1] == 2'b01); // now we can detect SCK rising edges
|
2021-06-13 11:45:08 +00:00
|
|
|
|
|
|
|
// Purpose: Transmits 1 SPI Byte whenever SPI clock is toggling
|
|
|
|
// Will transmit read data back to SW over MISO line.
|
|
|
|
// Want to put data on the line immediately when CS goes low.
|
2023-05-30 11:33:08 +00:00
|
|
|
always @(posedge i_sys_clk) begin
|
2021-06-13 11:45:08 +00:00
|
|
|
if (i_spi_cs_b || i_tx_data_valid) begin
|
|
|
|
r_tx_byte <= i_tx_byte;
|
|
|
|
r_tx_bit_count <= 3'b110;
|
|
|
|
o_spi_miso <= i_tx_byte[3'b111]; // Reset to MSb
|
|
|
|
end else begin
|
|
|
|
if (SCK_risingedge) begin
|
|
|
|
r_tx_bit_count <= r_tx_bit_count - 1;
|
|
|
|
o_spi_miso <= r_tx_byte[r_tx_bit_count];
|
|
|
|
|
|
|
|
if (r_tx_bit_count == 3'b000) begin
|
|
|
|
r_tx_byte <= 8'b00000000;
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2023-05-30 11:33:08 +00:00
|
|
|
endmodule // SPI_Slave
|