82 lines
1.9 KiB
Verilog
82 lines
1.9 KiB
Verilog
module spi_master (
|
|
input wire clk,
|
|
|
|
output reg spi_clk = 0,
|
|
|
|
input wire start, // Pulse high to begin transfer
|
|
input reg [7:0] data_out = 8'd0,
|
|
output reg spi_mosi = 0,
|
|
|
|
output wire [7:0] data_in,
|
|
input wire spi_miso,
|
|
|
|
output reg busy = 0,
|
|
output reg spi_cs = 1 // Active low
|
|
);
|
|
// SPI Mode 0: CPOL = 0, CPHA = 0 (drive on falling, sample on rising)
|
|
reg [3:0] bit_cnt = 0;
|
|
reg [7:0] shift_reg_in = 0;
|
|
reg [7:0] shift_reg_out = 0;
|
|
|
|
typedef enum logic [1:0] {
|
|
IDLE,
|
|
CHIP_SEL,
|
|
BUSY,
|
|
DONE
|
|
} state_t;
|
|
|
|
state_t state = IDLE;
|
|
|
|
always @(posedge clk) begin
|
|
case (state)
|
|
IDLE: begin
|
|
spi_cs <= 1;
|
|
spi_clk <= 0;
|
|
busy <= 0;
|
|
|
|
if (start) begin
|
|
state <= CHIP_SEL;
|
|
shift_reg_out <= data_out;
|
|
bit_cnt <= 0;
|
|
end
|
|
end
|
|
|
|
// data is one cycle after CS is brought low
|
|
CHIP_SEL: begin
|
|
spi_cs <= 0;
|
|
busy <= 1;
|
|
state <= BUSY;
|
|
end
|
|
|
|
BUSY: begin
|
|
if (clk) begin
|
|
spi_clk <= ~spi_clk;
|
|
|
|
// Falling, drive data
|
|
if (!spi_clk) begin
|
|
spi_mosi <= shift_reg_out[7];
|
|
shift_reg_out <= {shift_reg_out[6:0], 1'b0};
|
|
|
|
end else begin
|
|
// Rising, sample data
|
|
shift_reg_in <= {shift_reg_in[6:0], spi_miso};
|
|
bit_cnt <= bit_cnt + 1;
|
|
|
|
if (bit_cnt == 7) begin
|
|
state <= DONE;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
DONE: begin
|
|
spi_cs <= 1;
|
|
data_in <= {shift_reg_in[6:0], spi_miso};
|
|
state <= IDLE;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule
|
|
|