cariboulabs-cariboulite/firmware/spi_slave.v

86 wiersze
2.7 KiB
Verilog

module spi_slave (
// Control/Data Signals,
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.
// SPI Interface
input i_spi_sck,
output reg o_spi_miso,
input i_spi_mosi,
input i_spi_cs_b
);
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
always @(posedge i_spi_sck /* or posedge i_spi_cs_b*/) begin
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
// 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.
always @(posedge i_sys_clk) begin
// 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;
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
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};
wire SCK_risingedge = (SCKr[2:1] == 2'b01); // now we can detect SCK rising edges
// 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.
always @(posedge i_sys_clk) begin
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
endmodule // SPI_Slave