-
Notifications
You must be signed in to change notification settings - Fork 1
/
spi_master.v
165 lines (146 loc) · 4.34 KB
/
spi_master.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/***********************************************************************
SPI Master
This file is part FPGA Libre project http://fpgalibre.sf.net/
Description:
Configurable Master Serial Protocol Interface controller.
This is different than SPI_controller:
- Modes can be configured with signals, not just generics.
- The SS logic is left to the upper level.
- We always return to IDLE before transmitting again.
- IMPORTANT! assumes that start_i resets the ena_i generator. In
this way start_i can last 1 clock cycle (no need to wait for
busy_o to become 1).
To Do:
-
Author:
- Salvador E. Tropea, salvador en inti gob ar
------------------------------------------------------------------------------
Copyright (c) 2017 Salvador E. Tropea <salvador en inti gob ar>
Copyright (c) 2017 Instituto Nacional de Tecnología Industrial
Distributed under the GPL v2 or newer license
------------------------------------------------------------------------------
Design unit: SPI_Master(RTL) (Entity and architecture)
File name: spi_master.v
Note: None
Limitations: None known
Errors: None known
Library: None
Dependencies: IEEE.std_logic_1164
IEEE.numeric_std
Target FPGA:
Language: Verilog
Wishbone: None
Synthesis tools:
Simulation tools: GHDL [Sokcho edition] (0.2x)
Text editor: SETEdit 0.5.x
***********************************************************************/
module SPI_Master
#(
parameter DATA_W=8 // Transaction data width
)
(
// System
input clk_i,
input rst_i,
input ena_i, // 2*SCK
// Interface
input start_i,
input [DATA_W-1:0] tx_i,
output [DATA_W-1:0] rx_o,
output busy_o,
output reg irq_o,
input ack_i, // IRQ Ack
// Mode options
input cpol_i, // SCK value for idle
input dord_i, // 1 LSB first
input cpha_i, // 1 Trailing sample
// SPI
output sclk_o,
input miso_i,
output mosi_en_o,
output mosi_o
);
localparam integer CNT_BITS=$clog2(DATA_W);
localparam IDLE=0, LEADING_SCLK=1, TRAILING_SCLK=2, STOP=3; // state_t
reg [DATA_W-1:0] reg_r=0;
reg sclk_r=0;
reg [CNT_BITS-1:0] bit_cnt=0;
reg [1:0] state=IDLE; // states for shifter_FSM.
reg miso_r; // Sampled MISO
always @(posedge clk_i)
begin : shifter_FSM
if (rst_i)
begin
state <= IDLE;
sclk_r <= 0;
irq_o <= 0;
end
else
begin
if (ack_i)
irq_o <= 0;
case (state)
IDLE:
if (start_i) // init transaction
begin
state <= LEADING_SCLK;
reg_r <= tx_i;
bit_cnt <= 0;
end
LEADING_SCLK:
if (ena_i)
begin
state <= TRAILING_SCLK;
sclk_r <= !sclk_r;
if (!cpha_i) // Leading sample
miso_r <= miso_i;
end
TRAILING_SCLK:
if (ena_i)
begin
sclk_r <= !sclk_r;
if (bit_cnt==DATA_W-1)
begin
state <= STOP;
bit_cnt <= 0;
end
else
begin
state <= LEADING_SCLK;
bit_cnt <= bit_cnt+1;
end
if (cpha_i) // Leading sample
miso_r <= miso_i;
end
default: // STOP
// Maintain the last bit for half the clock to finish
// If we don't do it we could violate the slave hold time
if (ena_i)
begin
irq_o <= 1;
state <= IDLE;
end
endcase
// Shift in cases
if (ena_i)
if ( (state==TRAILING_SCLK && !cpha_i) ||
(((state==LEADING_SCLK && bit_cnt) || state==STOP) && cpha_i))
begin
// Shift
if (dord_i)
// Right
reg_r <= {miso_r,reg_r[DATA_W-1:1]};
else
// Left
reg_r <= {reg_r[DATA_W-2:0],miso_r};
end
end // !rst_i
end // shifter_FSM
// The FSM generates CPOL=0, if CPOL is 1 we just invert
assign sclk_o=sclk_r^cpol_i;
// MOSI takes the LSB or MSB according to DORD
assign mosi_o=dord_i ? reg_r[0] : reg_r[DATA_W-1];
assign mosi_en_o=state!=IDLE;
assign rx_o=reg_r;
assign busy_o=state!=IDLE;
endmodule // SPI_Master