-
Notifications
You must be signed in to change notification settings - Fork 55
/
sd_controller.v
321 lines (309 loc) · 12.4 KB
/
sd_controller.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* SD Card controller module. Allows reading from and writing to a microSD card
through SPI mode. */
// http://web.mit.edu/6.111/www/f2017/tools/sd_controller.v
// ref:
// https://stackoverflow.com/questions/8080718/sdhc-microsd-card-and-spi-initialization
// https://electronics.stackexchange.com/questions/321491/why-i-cant-issue-commands-after-cmd8-to-an-sdhc-card-in-spi-mode
// http://chlazza.nfshost.com/sdcardinfo.html
// (chinese) https://blog.csdn.net/ming1006/article/details/7281597
`timescale 1ns / 1ps
module sd_controller(
output reg cs, // Connect to SD_DAT[3].
output mosi, // Connect to SD_CMD.
input miso, // Connect to SD_DAT[0].
output sclk, // Connect to SD_SCK.
// For SPI mode, SD_DAT[2] and SD_DAT[1] should be held HIGH.
// SD_RESET should be held LOW.
input rd, // Read-enable. When [ready] is HIGH, asseting [rd] will
// begin a 512-byte READ operation at [address].
// [byte_available] will transition HIGH as a new byte has been
// read from the SD card. The byte is presented on [dout].
output reg [7:0] dout, // Data output for READ operation.
output reg byte_available, // A new byte has been presented on [dout].
input wr, // Write-enable. When [ready] is HIGH, asserting [wr] will
// begin a 512-byte WRITE operation at [address].
// [ready_for_next_byte] will transition HIGH to request that
// the next byte to be written should be presentaed on [din].
input [7:0] din, // Data input for WRITE operation.
output reg ready_for_next_byte, // A new byte should be presented on [din].
input reset, // Resets controller on assertion.
output ready, // HIGH if the SD card is ready for a read or write operation.
input [31:0] address, // Memory address for read/write operation. This MUST
// be a multiple of 512 bytes, due to SD sectoring.
input clk, // normal speed clock
input clk_pulse_slow, // pulsed slow clock
output [4:0] status, // For debug purposes: Current state of controller.
output reg [7:0] recv_data
);
parameter RST = 0;
parameter INIT = 1;
parameter CMD0 = 2;
parameter CMD8 = 20;
parameter CMD55 = 3;
parameter CMD41 = 4;
parameter POLL_CMD = 5;
parameter IDLE = 6;
parameter READ_BLOCK = 7;
parameter READ_BLOCK_WAIT = 8;
parameter READ_BLOCK_DATA = 9;
parameter READ_BLOCK_CRC = 10;
parameter SEND_CMD = 11;
parameter RECEIVE_BYTE_WAIT = 12;
parameter RECEIVE_BYTE = 13;
parameter WRITE_BLOCK_CMD = 14;
parameter WRITE_BLOCK_INIT = 15;
parameter WRITE_BLOCK_DATA = 16;
parameter WRITE_BLOCK_BYTE = 17;
parameter WRITE_BLOCK_WAIT = 18;
parameter WRITE_DATA_SIZE = 515;
(*mark_debug = "true"*) reg [4:0] state = RST;
assign status = state;
reg [4:0] return_state;
reg sclk_sig = 0;
reg [55:0] cmd_out = {56{1'b1}};
reg cmd_mode = 1;
reg [7:0] data_sig = 8'hFF;
reg [2:0] response_type = 3'b1;
reg [9:0] byte_counter;
reg [9:0] bit_counter;
reg [26:0] boot_counter = 27'd050_000;
reg [7:0] reset_counter = 0;
always @(posedge clk) begin
if(reset == 1) begin
state <= RST;
sclk_sig <= 0;
boot_counter <= 27'd002_500;
//boot_counter <= 27'd080_000;
cmd_mode <= 1;
cs <= 1;
cmd_out <= {56{1'b1}};
data_sig <= 8'hFF;
if (clk_pulse_slow) begin // startup init even when reseting
reset_counter <= reset_counter + 1;
if (reset_counter[6]) sclk_sig <= ~sclk_sig;
end
end
else begin
if (clk_pulse_slow) begin
case(state)
RST: begin
if(boot_counter == 0) begin
sclk_sig <= 0;
cmd_out <= {56{1'b1}};
byte_counter <= 0;
byte_available <= 0;
ready_for_next_byte <= 0;
cmd_mode <= 1;
bit_counter <= 160;
cs <= 1;
state <= INIT;
end
else begin
// <400KHz startup init
boot_counter <= boot_counter - 1;
if (boot_counter[6]) sclk_sig <= ~sclk_sig;
//sclk_sig <= ~sclk_sig; // I added this
end
end
INIT: begin
if(bit_counter == 0) begin
cs <= 0;
state <= CMD0;
end
else begin
bit_counter <= bit_counter - 1;
sclk_sig <= ~sclk_sig;
end
end
CMD0: begin
// cmd format: 01 ...... .*32 ....... 1
// command bit argument CRC7
cmd_out <= 56'hFF_40_00_00_00_00_95;
bit_counter <= 55;
response_type <= 3'b1;
return_state <= CMD8;
state <= SEND_CMD;
end
CMD8: begin
// this CMD8 has R7 response (CMD0 and CMD55 has R1)
// so take special care, or SDHC card may deadlock
cmd_out <= 56'hFF_48_00_00_01_AA_87;
bit_counter <= 55;
response_type <= 3'b111;
return_state <= CMD55;
state <= SEND_CMD;
end
CMD55: begin
cmd_out <= 56'hFF_77_00_00_00_00_01;
bit_counter <= 55;
response_type <= 3'b1;
return_state <= CMD41;
state <= SEND_CMD;
end
CMD41: begin
cmd_out <= 56'hFF_69_40_00_00_00_01;
bit_counter <= 55;
response_type <= 3'b1;
return_state <= POLL_CMD;
state <= SEND_CMD;
end
POLL_CMD: begin
if(recv_data[0] == 0) begin
state <= IDLE; // response 0x0, OK
end
else begin
state <= CMD55; // response 0x1, again
end
end
IDLE: begin
if(rd == 1) begin
state <= READ_BLOCK;
end
else if(wr == 1) begin
state <= WRITE_BLOCK_CMD;
end
else begin
state <= IDLE;
end
end
READ_BLOCK: begin
cmd_out <= {16'hFF_51, address, 8'hFF};
bit_counter <= 55;
response_type <= 3'b1;
return_state <= READ_BLOCK_WAIT;
state <= SEND_CMD;
end
READ_BLOCK_WAIT: begin
if(sclk_sig == 1 && miso == 0) begin
byte_counter <= 511;
bit_counter <= 7;
return_state <= READ_BLOCK_DATA;
state <= RECEIVE_BYTE;
end
sclk_sig <= ~sclk_sig;
end
READ_BLOCK_DATA: begin
dout <= recv_data;
byte_available <= 1;
if (byte_counter == 0) begin
bit_counter <= 7;
return_state <= READ_BLOCK_CRC;
state <= RECEIVE_BYTE;
end
else begin
byte_counter <= byte_counter - 1;
return_state <= READ_BLOCK_DATA;
bit_counter <= 7;
state <= RECEIVE_BYTE;
end
end
READ_BLOCK_CRC: begin
bit_counter <= 7;
return_state <= IDLE;
state <= RECEIVE_BYTE;
end
SEND_CMD: begin
if (sclk_sig == 1) begin
if (bit_counter == 0) begin
state <= RECEIVE_BYTE_WAIT;
end
else begin
bit_counter <= bit_counter - 1;
cmd_out <= {cmd_out[54:0], 1'b1};
end
end
sclk_sig <= ~sclk_sig;
end
RECEIVE_BYTE_WAIT: begin
if (sclk_sig == 1) begin
if (miso == 0) begin
recv_data <= 0;
case (response_type)
1: bit_counter <= 6;
7: bit_counter <= 38;
// in R7 most bits will LOST, but don't care
default: bit_counter <= 6;
endcase
state <= RECEIVE_BYTE;
end
end
sclk_sig <= ~sclk_sig;
end
RECEIVE_BYTE: begin
byte_available <= 0;
if (sclk_sig == 1) begin
recv_data <= {recv_data[6:0], miso};
if (bit_counter == 0) begin
state <= return_state;
end
else begin
bit_counter <= bit_counter - 1;
end
end
sclk_sig <= ~sclk_sig;
end
WRITE_BLOCK_CMD: begin
cmd_out <= {16'hFF_58, address, 8'hFF};
bit_counter <= 55;
return_state <= WRITE_BLOCK_INIT;
response_type <= 1;
state <= SEND_CMD;
ready_for_next_byte <= 1;
end
WRITE_BLOCK_INIT: begin
cmd_mode <= 0;
byte_counter <= WRITE_DATA_SIZE;
state <= WRITE_BLOCK_DATA;
ready_for_next_byte <= 0;
end
WRITE_BLOCK_DATA: begin
if (byte_counter == 0) begin
state <= RECEIVE_BYTE_WAIT;
return_state <= WRITE_BLOCK_WAIT;
end
else begin
if ((byte_counter == 2) || (byte_counter == 1)) begin
data_sig <= 8'hFF;
end
else if (byte_counter == WRITE_DATA_SIZE) begin
data_sig <= 8'hFE;
end
else begin
data_sig <= din;
ready_for_next_byte <= 1;
end
bit_counter <= 7;
state <= WRITE_BLOCK_BYTE;
byte_counter <= byte_counter - 1;
end
end
WRITE_BLOCK_BYTE: begin
if (sclk_sig == 1) begin
if (bit_counter == 0) begin
state <= WRITE_BLOCK_DATA;
ready_for_next_byte <= 0;
end
else begin
data_sig <= {data_sig[6:0], 1'b1};
bit_counter <= bit_counter - 1;
end;
end;
sclk_sig <= ~sclk_sig;
end
WRITE_BLOCK_WAIT: begin
if (sclk_sig == 1) begin
if (miso == 1) begin
state <= IDLE;
cmd_mode <= 1;
end
end
sclk_sig <= ~sclk_sig;
end
endcase
end
end
end
assign sclk = sclk_sig;
assign mosi = cmd_mode ? cmd_out[55] : data_sig[7];
assign ready = (state == IDLE);
endmodule