Verilog SPI Master和Slave
https://alchitry.com/blogs/tutorials/serial-peripheral-interface-spislave
module spi_slave(
input clk,
input rst,
input ss,
input mosi,
output miso,
input sck,
output done,
input din,
output dout
);
reg mosi_d, mosi_q;
reg ss_d, ss_q;
reg sck_d, sck_q;
reg sck_old_d, sck_old_q;
reg data_d, data_q;
reg done_d, done_q;
reg bit_ct_d, bit_ct_q;
reg dout_d, dout_q;
reg miso_d, miso_q;
assign miso = miso_q;
assign done = done_q;
assign dout = dout_q;
always @(*) begin
ss_d = ss;
mosi_d = mosi;
miso_d = miso_q;
sck_d = sck;
sck_old_d = sck_q;
data_d = data_q;
done_d = 1'b0;
bit_ct_d = bit_ct_q;
dout_d = dout_q;
if (ss_q) begin // if slave select is high (deselcted)
bit_ct_d = 3'b0; // reset bit counter
data_d = din; // read in data
miso_d = data_q; // output MSB
end else begin // else slave select is low (selected)
if (!sck_old_q && sck_q) begin // rising edge
data_d = {data_q, mosi_q}; // read data in and shift
bit_ct_d = bit_ct_q + 1'b1; // increment the bit counter
if (bit_ct_q == 3'b111) begin // if we are on the last bit
dout_d = {data_q, mosi_q}; // output the byte
done_d = 1'b1; // set transfer done flag
data_d = din; // read in new byte
end
end else if (sck_old_q && !sck_q) begin // falling edge
miso_d = data_q; // output MSB
end
end
end
always @(posedge clk) begin
if (rst) begin
done_q <= 1'b0;
bit_ct_q <= 3'b0;
dout_q <= 8'b0;
miso_q <= 1'b1;
end else begin
done_q <= done_d;
bit_ct_q <= bit_ct_d;
dout_q <= dout_d;
miso_q <= miso_d;
end
sck_q <= sck_d;
mosi_q <= mosi_d;
ss_q <= ss_d;
data_q <= data_d;
sck_old_q <= sck_old_d;
end
endmodule
Master
module spi #(parameter CLK_DIV = 2)(
input clk,
input rst,
input miso,
output mosi,
output sck,
input start,
input data_in,
output data_out,
output busy,
output new_data
);
localparam STATE_SIZE = 2;
localparam IDLE = 2'd0,
WAIT_HALF = 2'd1,
TRANSFER = 2'd2;
reg state_d, state_q;
reg data_d, data_q;
reg sck_d, sck_q;
reg mosi_d, mosi_q;
reg ctr_d, ctr_q;
reg new_data_d, new_data_q;
reg data_out_d, data_out_q;
assign mosi = mosi_q;
assign sck = (~sck_q) & (state_q == TRANSFER);
assign busy = state_q != IDLE;
assign data_out = data_out_q;
assign new_data = new_data_q;
always @(*) begin
sck_d = sck_q;
data_d = data_q;
mosi_d = mosi_q;
ctr_d = ctr_q;
new_data_d = 1'b0;
data_out_d = data_out_q;
state_d = state_q;
case (state_q)
IDLE: begin
sck_d = 4'b0; // reset clock counter
ctr_d = 3'b0; // reset bit counter
if (start == 1'b1) begin // if start command
data_d = data_in; // copy data to send
state_d = WAIT_HALF; // change state
end
end
WAIT_HALF: begin
sck_d = sck_q + 1'b1; // increment clock counter
if (sck_q == {CLK_DIV-1{1'b1}}) begin// if clock is half full (about to fall)
sck_d = 1'b0; // reset to 0
state_d = TRANSFER; // change state
end
end
TRANSFER: begin
sck_d = sck_q + 1'b1; // increment clock counter
if (sck_q == 4'b0000) begin // if clock counter is 0
mosi_d = data_q; // output the MSB of data
end else if (sck_q == {CLK_DIV-1{1'b1}}) begin// else if it's half full (about to fall)
data_d = {data_q, miso}; // read in data (shift in)
end else if (sck_q == {CLK_DIV{1'b1}}) begin // else if it's full (about to rise)
ctr_d = ctr_q + 1'b1; // increment bit counter
if (ctr_q == 3'b111) begin // if we are on the last bit
state_d = IDLE; // change state
data_out_d = data_q; // output data
new_data_d = 1'b1; // signal data is valid
end
end
end
endcase
end
always @(posedge clk) begin
if (rst) begin
ctr_q <= 3'b0;
data_q <= 8'b0;
sck_q <= 4'b0;
mosi_q <= 1'b0;
state_q <= IDLE;
data_out_q <= 8'b0;
new_data_q <= 1'b0;
end else begin
ctr_q <= ctr_d;
data_q <= data_d;
sck_q <= sck_d;
mosi_q <= mosi_d;
state_q <= state_d;
data_out_q <= data_out_d;
new_data_q <= new_data_d;
end
end
endmodule
:lol✌,太好了,我正在发愁CPLD上的SPI呢!
页:
[1]