import spi v0.2
This commit is contained in:
parent
50ea679e02
commit
0907a76c22
|
@ -1,5 +1,12 @@
|
|||
/* SPI master.
|
||||
* Written by Peter McGoron, 2022.
|
||||
/* (c) Peter McGoron 2022 v0.2
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v.2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* CYCLE_HALF_WAIT should take into account the setup time of the slave
|
||||
* device, and also master buffering (MISO is one cycle off to stabilize
|
||||
* the input).
|
||||
*/
|
||||
|
||||
module
|
||||
|
@ -12,11 +19,11 @@ spi_master_no_write
|
|||
spi_master
|
||||
`endif
|
||||
`endif
|
||||
|
||||
#(
|
||||
parameter WID = 24, // Width of bits per transaction.
|
||||
parameter WID_LEN = 5, // Length in bits required to store WID
|
||||
parameter CYCLE_HALF_WAIT = 1, // Half of the wait time of a cycle
|
||||
parameter CYCLE_HALF_WAIT = 1, // Half of the wait time of a cycle minus 1.
|
||||
// One SCK cycle is 2*(CYCLE_HALF_WAIT + 1) clock cycles.
|
||||
parameter TIMER_LEN = 3, // Length in bits required to store CYCLE_HALF_WAIT
|
||||
parameter POLARITY = 0, // 0 = sck idle low, 1 = sck idle high
|
||||
parameter PHASE = 0 // 0 = rising-read falling-write, 1 = rising-write falling-read.
|
||||
|
@ -29,13 +36,30 @@ spi_master
|
|||
`endif
|
||||
`ifndef SPI_MASTER_NO_WRITE
|
||||
input [WID-1:0] to_slave,
|
||||
output mosi,
|
||||
output reg mosi,
|
||||
`endif
|
||||
output sck_wire,
|
||||
output finished,
|
||||
output reg sck_wire,
|
||||
output reg finished,
|
||||
input arm
|
||||
);
|
||||
|
||||
`ifndef SPI_MASTER_NO_READ
|
||||
/* MISO is almost always an external wire, so buffer it.
|
||||
* This might not be necessary, since the master and slave do not respond
|
||||
* immediately to changes in the wires, but this is just to be safe.
|
||||
* It is trivial to change, just do
|
||||
* wire read_miso = miso;
|
||||
*/
|
||||
|
||||
reg miso_hot = 0;
|
||||
reg read_miso = 0;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
read_miso <= miso_hot;
|
||||
miso_hot <= miso;
|
||||
end
|
||||
`endif
|
||||
|
||||
parameter WAIT_ON_ARM = 0;
|
||||
parameter ON_CYCLE = 1;
|
||||
parameter CYCLE_WAIT = 2;
|
||||
|
@ -68,7 +92,7 @@ endtask
|
|||
task read_data();
|
||||
`ifndef SPI_MASTER_NO_READ
|
||||
from_slave <= from_slave << 1;
|
||||
from_slave[0] <= miso;
|
||||
from_slave[0] <= read_miso;
|
||||
`endif
|
||||
endtask
|
||||
|
||||
|
@ -100,6 +124,16 @@ task setup_bits();
|
|||
end
|
||||
endtask
|
||||
|
||||
task cycle_change();
|
||||
// Stop transfer when the clock returns to its original polarity.
|
||||
if (bit_counter == WID[WID_LEN-1:0] && sck == POLARITY[0]) begin
|
||||
state <= WAIT_FINISHED;
|
||||
end else begin
|
||||
sck <= !sck;
|
||||
state <= ON_CYCLE;
|
||||
end
|
||||
endtask
|
||||
|
||||
always @ (posedge clk) begin
|
||||
case (state)
|
||||
WAIT_ON_ARM: begin
|
||||
|
@ -132,19 +166,17 @@ always @ (posedge clk) begin
|
|||
bit_counter <= bit_counter + 1;
|
||||
end
|
||||
end
|
||||
|
||||
if (CYCLE_HALF_WAIT == 0) begin
|
||||
cycle_change();
|
||||
end else begin
|
||||
state <= CYCLE_WAIT;
|
||||
end
|
||||
end
|
||||
CYCLE_WAIT: begin
|
||||
if (timer == CYCLE_HALF_WAIT) begin
|
||||
timer <= 0;
|
||||
// Stop transfer when the clock returns
|
||||
// to its original polarity.
|
||||
if (bit_counter == WID && sck == POLARITY) begin
|
||||
state <= WAIT_FINISHED;
|
||||
end else begin
|
||||
state <= ON_CYCLE;
|
||||
sck <= !sck;
|
||||
end
|
||||
timer <= 1;
|
||||
cycle_change();
|
||||
end else begin
|
||||
timer <= timer + 1;
|
||||
end
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
`define SPI_MASTER_SS_NAME spi_master_ss
|
||||
`define SPI_MASTER_NAME spi_master
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
`include "spi_master_ss_template.v"
|
|
@ -0,0 +1,5 @@
|
|||
`define SPI_MASTER_SS_NAME spi_master_ss_no_read
|
||||
`define SPI_MASTER_NAME spi_master_no_read
|
||||
`define SPI_MASTER_NO_READ
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
`include "spi_master_ss_template.v"
|
|
@ -0,0 +1,5 @@
|
|||
`define SPI_MASTER_SS_NAME spi_master_ss_no_write
|
||||
`define SPI_MASTER_NAME spi_master_no_write
|
||||
`define SPI_MASTER_NO_WRITE
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
`include "spi_master_ss_template.v"
|
|
@ -0,0 +1,108 @@
|
|||
/* spi master with integrated ability to wait a certain amount of cycles
|
||||
* after activating SS.
|
||||
*/
|
||||
|
||||
module `SPI_MASTER_SS_NAME
|
||||
#(
|
||||
parameter WID = 24,
|
||||
parameter WID_LEN = 5,
|
||||
parameter CYCLE_HALF_WAIT = 1,
|
||||
parameter TIMER_LEN = 3,
|
||||
|
||||
parameter SS_WAIT = 1,
|
||||
parameter SS_WAIT_TIMER_LEN = 2,
|
||||
|
||||
parameter POLARITY = 0,
|
||||
parameter PHASE = 0
|
||||
)
|
||||
(
|
||||
input clk,
|
||||
`ifndef SPI_MASTER_NO_READ
|
||||
output [WID-1:0] from_slave,
|
||||
input miso,
|
||||
`endif
|
||||
`ifndef SPI_MASTER_NO_WRITE
|
||||
input [WID-1:0] to_slave,
|
||||
output reg mosi,
|
||||
`endif
|
||||
output sck_wire,
|
||||
output finished,
|
||||
output ss_L,
|
||||
input arm
|
||||
);
|
||||
|
||||
reg ss = 0;
|
||||
reg arm_master = 0;
|
||||
assign ss_L = !ss;
|
||||
|
||||
`SPI_MASTER_NAME #(
|
||||
.WID(WID),
|
||||
.WID_LEN(WID_LEN),
|
||||
.CYCLE_HALF_WAIT(CYCLE_HALF_WAIT),
|
||||
.TIMER_LEN(TIMER_LEN),
|
||||
.POLARITY(POLARITY),
|
||||
.PHASE(PHASE)
|
||||
) master (
|
||||
.clk(clk),
|
||||
`ifndef SPI_MASTER_NO_READ
|
||||
.from_slave(from_slave),
|
||||
.miso(miso),
|
||||
`endif
|
||||
`ifndef SPI_MASTER_NO_WRITE
|
||||
.to_slave(to_slave),
|
||||
.mosi(mosi),
|
||||
`endif
|
||||
.sck_wire(sck_wire),
|
||||
.finished(finished),
|
||||
.arm(arm_master)
|
||||
);
|
||||
|
||||
localparam WAIT_ON_ARM = 0;
|
||||
localparam WAIT_ON_SS = 1;
|
||||
localparam WAIT_ON_MASTER = 2;
|
||||
localparam WAIT_ON_ARM_DEASSERT = 3;
|
||||
reg [2:0] state = WAIT_ON_ARM;
|
||||
reg [SS_WAIT_TIMER_LEN-1:0] timer = 0;
|
||||
|
||||
task master_arm();
|
||||
arm_master <= 1;
|
||||
state <= WAIT_ON_MASTER;
|
||||
endtask
|
||||
|
||||
always @ (posedge clk) begin
|
||||
case (state)
|
||||
WAIT_ON_ARM: begin
|
||||
if (arm) begin
|
||||
timer <= 1;
|
||||
if (SS_WAIT == 0) begin
|
||||
master_arm();
|
||||
end else begin
|
||||
timer <= 1;
|
||||
state <= WAIT_ON_SS;
|
||||
end
|
||||
ss <= 1;
|
||||
end
|
||||
end
|
||||
WAIT_ON_SS: begin
|
||||
if (timer == SS_WAIT) begin
|
||||
master_arm();
|
||||
end else begin
|
||||
timer <= timer + 1;
|
||||
end
|
||||
end
|
||||
WAIT_ON_MASTER: begin
|
||||
if (finished) begin
|
||||
state <= WAIT_ON_ARM_DEASSERT;
|
||||
ss <= 0;
|
||||
end
|
||||
end
|
||||
WAIT_ON_ARM_DEASSERT: begin
|
||||
if (!arm) begin
|
||||
state <= WAIT_ON_ARM;
|
||||
arm_master <= 0;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
|
@ -1,4 +1,4 @@
|
|||
/* (c) Peter McGoron 2022 v0.1
|
||||
/* (c) Peter McGoron 2022 v0.2
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v.2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
@ -24,7 +24,7 @@ spi_slave
|
|||
input ss_L,
|
||||
`ifndef SPI_SLAVE_NO_READ
|
||||
output reg [WID-1:0] from_master,
|
||||
input reg mosi,
|
||||
input mosi,
|
||||
`endif
|
||||
`ifndef SPI_SLAVE_NO_WRITE
|
||||
input [WID-1:0] to_master,
|
||||
|
@ -35,6 +35,17 @@ spi_slave
|
|||
output reg err
|
||||
);
|
||||
|
||||
`ifndef SPI_SLAVE_NO_READ
|
||||
/* MOSI is almost always an external wire, so buffer it. */
|
||||
reg mosi_hot = 0;
|
||||
reg read_mosi = 0;
|
||||
|
||||
always @ (posedge clk) begin
|
||||
read_mosi <= mosi_hot;
|
||||
mosi_hot <= mosi;
|
||||
end
|
||||
`endif
|
||||
|
||||
wire ss = !ss_L;
|
||||
reg sck_delay = 0;
|
||||
reg [WID_LEN-1:0] bit_counter = 0;
|
||||
|
@ -48,7 +59,7 @@ reg [WID-1:0] send_buf = 0;
|
|||
task read_data();
|
||||
`ifndef SPI_SLAVE_NO_READ
|
||||
from_master <= from_master << 1;
|
||||
from_master[0] <= mosi;
|
||||
from_master[0] <= read_mosi;
|
||||
`endif
|
||||
endtask
|
||||
|
||||
|
@ -77,7 +88,7 @@ task setup_bits();
|
|||
endtask
|
||||
|
||||
task check_counter();
|
||||
if (bit_counter == WID) begin
|
||||
if (bit_counter == WID[WID_LEN-1:0]) begin
|
||||
err <= ready_at_start;
|
||||
end else begin
|
||||
bit_counter <= bit_counter + 1;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
`define SPI_SLAVE_NO_READ
|
||||
/* verilator lint_off DECLFILENAME */
|
||||
`include "spi_slave.v"
|
Loading…
Reference in New Issue