§ Команды

Активируется команда путем записи в sd_cmd значения:
00  Инициализация устройства в режим SPI (80 единиц)
01  Прием и передача данных из sd_din, в sd_out
02  Включить чип (CS=0)
03  Выключить чип (CS=1)
Активируется позитивным фронтом сигнала sd_signal, но при этом sd_busy должен быть равен 0!
При sd_timeout=1 необходимо снова выслать sd_cmd=00 (init).
Для чтения данных используется sd_din=FFh, sd_cmd=1, и позитивный фронт sd_signal.
Максимальная скорость передачи данных 12,5 мегабит (~1.5 мегабайт в сек).

§ Top-уровень

Этот код предназначен для DE0-CV.
1assign SD_DATA[0] = 1'bZ;
2
3wire [1:0]  sd_cmd;
4wire [7:0]  sd_din;
5wire [7:0]  sd_out;
6wire        sd_signal;
7wire        sd_busy;
8wire        sd_timeout;
9
10sd UnitSD
11(
12    // 50 Mhz
13    .clock50    (CLOCK_50),
14
15    // Физический интерфейс
16    .SPI_CS     (SD_DATA[3]),   // Выбор чипа
17    .SPI_SCLK   (SD_CLK),       // Тактовая частота
18    .SPI_MISO   (SD_DATA[0]),   // Входящие данные
19    .SPI_MOSI   (SD_CMD),       // Исходящие
20
21    // Интерфейс
22    .sd_signal  (sd_signal),   // In   =1 Сообщение отослано на spi
23    .sd_cmd     (sd_cmd),      // In      Команда
24    .sd_din     (sd_din),      // Out     Принятое сообщение от карты
25    .sd_out     (sd_out),      // In      Сообщение на отправку к карте
26    .sd_busy    (sd_busy),     // Out  =1 Занято
27    .sd_timeout (sd_timeout)   // Out  =1 Таймаут
28);
29

§ Код модуля

1module sd
2(
3    // 50 Mhz
4    input  wire         clock50,
5
6    // SPI
7    output reg          SPI_CS,
8    output reg          SPI_SCLK,
9    input  wire         SPI_MISO,
10    output reg          SPI_MOSI,
11
12    // Интерфейс
13    input  wire         sd_signal,  // 0->1 Команда на позитивном фронте
14    input  wire [ 1:0]  sd_cmd,     // ID команды
15    output reg  [ 7:0]  sd_din,     // Исходящие данные в процессор
16    input  wire [ 7:0]  sd_out,     // Входящие данные из процессора
17    output reg          sd_busy,    // =1 Устройство занято
18    output wire         sd_timeout  // =1 Вышел таймаут
19);
20
21`define SPI_TIMEOUT_CNT     5000000     // 0.1 s
22
23initial begin
24
25    SPI_CS   = 1'b1;
26    SPI_SCLK = 1'b0;
27    SPI_MOSI = 1'b0;
28    sd_din   = 8'h00;
29    sd_busy  = 1'b0;
30
31end
32
33// ---------------------------------------------------------------------
34// SPI SdCard
35// ---------------------------------------------------------------------
36
37// Сигналы нейтрализации (сброс активации команды)
38reg  [1:0]  spi_latch   = 2'b00;
39
40// Сигнал о том, занято ли устройство
41assign      sd_timeout = (sd_timeout_cnt == `SPI_TIMEOUT_CNT);
42
43reg  [2:0]  spi_process = 0;
44reg  [3:0]  spi_cycle   = 0;
45reg  [7:0]  spi_data_w  = 0;
46
47// INIT SPI MODE
48reg  [7:0]  spi_counter   = 0;
49reg  [7:0]  spi_slow_tick = 0;
50reg  [24:0] sd_timeout_cnt = `SPI_TIMEOUT_CNT;
51
52always @(posedge clock50) begin
53
54    // Счетчик таймаута. Дойдя для
55    if (sd_timeout_cnt < `SPI_TIMEOUT_CNT && spi_process == 0)
56        sd_timeout_cnt <= sd_timeout_cnt + 1;
57
58    case (spi_process)
59
60        // Инициировать процессинг
61        0: if (spi_latch == 2'b01) begin
62
63            spi_process <= 1 + sd_cmd;
64            spi_counter <= 0;
65            spi_cycle   <= 0;
66            spi_data_w  <= sd_out;
67            sd_busy     <= 1;
68            sd_timeout_cnt <= 0;
69
70        end
71
72        // Command-1: 80 тактов в slow-режиме
73        1: begin
74
75            SPI_CS   <= 1;
76            SPI_MOSI <= 1;
77
78            // 250*100`000
79            if (spi_slow_tick == (250 - 1)) begin
80
81                SPI_SCLK      <= ~SPI_SCLK;
82                spi_slow_tick <= 0;
83                spi_counter   <= spi_counter + 1;
84
85                // 80 ticks
86                if (spi_counter == (2*80 - 1)) begin
87
88                    SPI_SCLK    <= 0;
89                    spi_process <= 0;
90                    sd_busy     <= 0;
91
92                end
93
94            end
95            // Оттикивание таймера
96            else begin spi_slow_tick <= spi_slow_tick + 1;  end
97
98        end
99
100        // Command 1: Read/Write SPI
101        2: case (spi_cycle)
102
103            // CLK-DN
104            0: begin spi_cycle <= 1; SPI_SCLK <= 0; SPI_MOSI <= 0; end
105            1: begin spi_cycle <= 2; SPI_MOSI <= spi_data_w[7]; end
106            // CLK-UP
107            2: begin spi_cycle <= 3; SPI_SCLK <= 1; spi_counter <= spi_counter + 1; end
108            3: begin
109
110                spi_cycle  <= 0;
111                sd_din     <= {sd_din[6:0], SPI_MISO};
112                spi_data_w <= {spi_data_w[6:0], 1'b0};
113
114                if (spi_counter == 8) begin
115
116                    SPI_SCLK    <= 0;
117                    sd_busy     <= 0;
118                    spi_counter <= 0;
119                    spi_process <= 0;
120                    SPI_MOSI    <= 0;
121
122                end
123            end
124
125        endcase
126
127        // Переключиться за 2 такта, чтобы среагировал CPU
128        3: case (spi_cycle)
129
130            0: spi_cycle <= 1;
131            1: spi_cycle <= 2;
132            2: begin SPI_CS <= 1'b0; spi_process <= 0; sd_busy <= 0; end
133
134        endcase
135
136        4: case (spi_cycle)
137
138            0: spi_cycle <= 1;
139            1: spi_cycle <= 2;
140            2: begin SPI_CS <= 1'b1; spi_process <= 0; sd_busy <= 0; end
141
142        endcase
143
144    endcase
145
146    // Активизация работы устройства
147    spi_latch <= {spi_latch[0], sd_signal};
148
149end
150
151endmodule