Files
2026-05-22 10:02:42 +08:00

101 lines
2.8 KiB
Verilog

`timescale 1ns/1ps
module spi_controller_simple (
input clk,
input rst_n,
input [7:0] data_in,
input start,
output reg [7:0] data_out,
output reg busy,
output reg spi_clk,
output reg mosi,
input miso
);
// Simplified FSM: IDLE -> SEND -> SAMPLE -> DONE -> IDLE
localparam IDLE = 2'd0;
localparam SEND = 2'd1;
localparam SAMPLE = 2'd2;
localparam DONE = 2'd3;
reg [1:0] state;
reg [2:0] bit_count;
reg [7:0] shift_reg;
reg spi_clk_en;
// SPI clock generation: derived from main FSM state
// spi_clk toggles when in SEND state
wire spi_clk_next = spi_clk_en ? ~spi_clk : 1'b0;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
spi_clk <= 1'b0;
end else begin
spi_clk <= spi_clk_next;
end
end
// Main FSM - single always block drives all registers
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
bit_count <= 3'd0;
shift_reg <= 8'd0;
data_out <= 8'd0;
busy <= 1'b0;
mosi <= 1'b0;
spi_clk_en <= 1'b0;
end else begin
case (state)
IDLE: begin
busy <= 1'b0;
mosi <= 1'b0;
spi_clk_en <= 1'b0;
if (start) begin
busy <= 1'b1;
shift_reg <= data_in;
bit_count <= 3'd7;
state <= SEND;
spi_clk_en <= 1'b1;
end
end
SEND: begin
busy <= 1'b1;
mosi <= shift_reg[7];
// Check if spi_clk just transitioned (rising edge detection)
if (spi_clk == 1'b0) begin
state <= SAMPLE;
end
end
SAMPLE: begin
busy <= 1'b1;
// Shift in miso
shift_reg <= {shift_reg[6:0], miso};
if (bit_count == 3'd0) begin
data_out <= {shift_reg[6:0], miso};
state <= DONE;
spi_clk_en <= 1'b0;
end else begin
bit_count <= bit_count - 1'b1;
state <= SEND;
end
end
DONE: begin
busy <= 1'b0;
mosi <= 1'b0;
state <= IDLE;
spi_clk_en <= 1'b0;
end
default: begin
state <= IDLE;
spi_clk_en <= 1'b0;
end
endcase
end
end
endmodule