-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspi.v
103 lines (94 loc) · 2.98 KB
/
spi.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
//
// LED Suit FPGA Implementation - Multi-output addressable LED driver HDL
// implementation for Kevin's LED suit controller.
// Copyright (C) 2019-2020 Kevin Balke
//
// This file is part of LED Suit FPGA Implementation.
//
// LED Suit FPGA Implementation is free software: you can redistribute it and/or
// modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// LED Suit FPGA Implementation is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with LED Suit FPGA Implementation. If not, see
// <http://www.gnu.org/licenses/>.
//
module spi_slave(
input clk,
input rst,
input ss,
input mosi,
output miso,
input sck,
output done,
input [7:0] din,
output [7:0] dout,
output selected
);
reg mosi_d, mosi_q;
reg ss_d, ss_q;
reg sck_d, sck_q;
reg sck_old_d, sck_old_q;
reg [7:0] data_d, data_q;
reg done_d, done_q;
reg [2:0] bit_ct_d, bit_ct_q;
reg [7:0] dout_d, dout_q;
reg miso_d, miso_q;
assign miso = miso_q;
assign done = done_q;
assign dout = dout_q;
assign selected = ~ss_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[7]; // output MSB
end else begin // else slave select is low (selected)
if (!sck_old_q && sck_q) begin // rising edge
data_d = {data_q[6:0], 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[6:0], 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[7]; // 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