-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathspi_module.v
144 lines (92 loc) · 3.44 KB
/
spi_module.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
`default_nettype none
`timescale 1ns/1ps
`define SPI_MODULE_COMMAND_LEN 3
`define SPI_STATUS_IDLE 'b000
`define SPI_STATUS_CYCLE_BITS 'b111
module spi_module
#( parameter CPOL = 1'b0,
parameter CPHA = 1'b0,
parameter INVERT_DATA_ORDER = 1'b0,
parameter SPI_MASTER = 1'b1,
parameter SPI_WORD_LEN = 8 )
( input wire master_clock,
output wire SCLK_OUT,
input wire SCLK_IN,
output wire SS_OUT,
input wire SS_IN,
output wire OUTPUT_SIGNAL,
output wire processing_word,
input wire process_next_word,
input wire [SPI_WORD_LEN - 1:0] data_word_send,
input wire INPUT_SIGNAL,
output wire [SPI_WORD_LEN - 1:0] data_word_recv,
input wire do_reset,
output wire is_ready );
//Local registers and wires
reg is_ready_reg;
reg activate_ss;
reg activate_sclk;
reg status_ignore_first_edge;
wire rising_sclk_edge;
wire falling_sclk_edge;
reg [SPI_WORD_LEN - 1:0] data_word_recv_reg;
reg [SPI_WORD_LEN - 1:1] bit_counter;
reg [`SPI_MODULE_COMMAND_LEN - 1:0]spi_status;
assign is_ready = is_ready_reg;
assign data_word_recv = data_word_recv_reg;
assign processing_word = (spi_status == `SPI_STATUS_IDLE) ? 1'b0 : 1'b1;
generate
if(SPI_MASTER) begin
assign SCLK_OUT = (activate_sclk) ? SCLK_IN : (CPOL);
assign SS_OUT = (activate_ss) ? 1'b0 : 1'b1;
end
endgenerate
//Edge detector modules
pos_edge_det spi_edge_pos( .sig(SCLK_IN), .clk(master_clock), .pe(rising_sclk_edge));
neg_edge_det spi_edge_neg( .sig(SCLK_IN), .clk(master_clock), .ne(falling_sclk_edge));
wire delay_pol = (CPHA) ? ( (CPOL) ? (rising_sclk_edge) : (falling_sclk_edge) ) : ( (CPOL) ? (SCLK_IN) : (!SCLK_IN) );
wire get_number_edge = (CPHA) ? ( (CPOL) ? (rising_sclk_edge) : (falling_sclk_edge) ) : ( (CPOL) ? (falling_sclk_edge) : (rising_sclk_edge) );
wire switch_number_edge = (CPHA) ? ( (CPOL) ? (falling_sclk_edge) : (rising_sclk_edge) ) : ( (CPOL) ? (rising_sclk_edge) : (falling_sclk_edge) );
wire SS = (SPI_MASTER) ? SS_OUT : SS_IN;
assign OUTPUT_SIGNAL = (activate_ss) ? data_word_send[bit_counter] : 1'b0;
always @(posedge master_clock) begin
if (do_reset) begin
//do reset stuff
activate_ss <= 1'b0;
activate_sclk <= 1'b0;
bit_counter <= (INVERT_DATA_ORDER) ? (0) : (SPI_WORD_LEN - 1);
status_ignore_first_edge <= 1'b0;
spi_status <= `SPI_STATUS_IDLE;
is_ready_reg <= 1'b1;
end
else begin
case(spi_status)
`SPI_STATUS_IDLE: begin
if(process_next_word && delay_pol) begin
status_ignore_first_edge <= 1'b0;
activate_ss <= 1'b1;
activate_sclk <= 1'b1;
spi_status <= `SPI_STATUS_CYCLE_BITS;
end
end
`SPI_STATUS_CYCLE_BITS: begin
if(!SS) begin
if(get_number_edge) data_word_recv_reg[bit_counter] <= INPUT_SIGNAL;
if(switch_number_edge) begin
if(CPHA && !status_ignore_first_edge) status_ignore_first_edge <= 1'b1;
else begin
if(bit_counter == ((INVERT_DATA_ORDER) ? (SPI_WORD_LEN -1) : ('sd0)) ) begin //Word processed, reset
activate_ss <= 1'b0;
activate_sclk <= 1'b0;
bit_counter <= (INVERT_DATA_ORDER) ? (0) : (SPI_WORD_LEN - 1);
spi_status <= `SPI_STATUS_IDLE;
end
else bit_counter <= (INVERT_DATA_ORDER) ? (bit_counter + 1) : (bit_counter - 1);
end
end
end
end
endcase
end
end
endmodule