You are on page 1of 5

SPI Slave

In the Mojo Base Project, the file spi_slave.v contains the SPI module used to interface with the
AVR. The AVR, in this case, is the master and the FPGA is the slave. The reason the AVR is the
master is because the SPI bus is used to transfer data from the analog pins. Since the FPGA has no
way of knowing when the data would be available, the FPGA would have to keep asking the AVR if it
had any data. By making the AVR the master, it allows it to send the data right when it's ready.
module spi_slave(
1
input clk,
2
input rst,
3
input ss,
4
input mosi,
output miso,
5
input sck,
6
output done,
7
input [7:0] din,
8
output [7:0] dout
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

reg
reg
reg
reg
reg
reg
reg
reg
reg

mosi_d, mosi_q;
ss_d, ss_q;
sck_d, sck_q;
sck_old_d, sck_old_q;
[7:0] data_d, data_q;
done_d, done_q;
[2:0] bit_ct_d, bit_ct_q;
[7:0] dout_d, dout_q;
miso_d, miso_q;

assign miso = miso_q;
assign done = done_q;
assign dout = dout_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;

//seclecslave=1
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

data_q <= data_d. // output the byte done_d = 1'b1. end sck_q <= sck_d. // read in new byte end end else if (sck_old_q && !sck_q) begin // falling edge miso_d = data_q[7]. SPI Master . ss_q <= ss_d. bit_ct_q <= 3'b0. It waits for SS to go low. it shifts out the data that was provided by din at the beginning of the transmission. // set transfer done flag data_d = din. end endmodule This is module assumes CPOL = 0 and CPHA = 0. Once SS is low. // output MSB end end end always @(posedge clk) begin if (rst) begin done_q <= 1'b0. dout_q <= 8'b0. it starts shifting data into the data_d/_q register. miso_q <= 1'b1. bit_ct_q <= bit_ct_d. // increment the bit counter if (bit_ct_q == 3'b111) begin // if we are on the last bit dout_d = {data_q[6:0]. dout_q <= dout_d.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 bit_ct_d = bit_ct_q + 1'b1. end else begin done_q <= done_d. On the falling edges of the clock. mosi_q}. sck_old_q <= sck_old_d. miso_q <= miso_d. mosi_q <= mosi_d. Once eight bits have been shifted in it signals that it has new data on dout.

8 output busy. mosi_d = mosi_q. 9 output new_data ). 4 output mosi. state_q. mosi_d. [CLK_DIV-1:0] sck_d. WAIT_HALF = 2'd1. 6 input[7:0] data_in. new_data_q. // copy data to send state_d = WAIT_HALF. data_out = data_out_q. In this case. // reset clock counter ctr_d = 3'b0. reg [STATE_SIZE-1:0] state_d. // reset bit counter if (start == 1'b1) begin // if start command data_d = data_in. mosi_q. // change state end . localparam IDLE = 2'd0. new_data_d = 1'b0. always @(*) begin sck_d = sck_q.Our Clock/Visualizer Shield. 3 input miso. output sck. [2:0] ctr_d. 5 input start. the FPGA on the Mojo is the master and the RTC is the slave. case (state_q) IDLE: begin sck_d = 4'b0. data_q. TRANSFER = 2'd2. data_out_q. new_data = new_data_q. 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 localparam STATE_SIZE = 2. state_d = state_q. 2 input rst. ctr_d = ctr_q. busy = state_q != IDLE. sck = (~sck_q[CLK_DIV-1]) & (state_q == TRANSFER). 7 output[7:0] data_out. data_out_d = data_out_q. sck_q. data_d = data_q. new_data_d. assign assign assign assign assign mosi = mosi_q. uses a Real-Time Clock (RTC) device that provides the Mojo with the current time. ctr_q. module spi #(parameter CLK_DIV = 2)( 1 input clk. [7:0] data_out_d. The RTC is connected to the Mojo through an SPI bus. reg reg reg reg reg reg [7:0] data_d.

// change state data_out_d = data_q. data_out_q <= data_out_d. // reset to 0 state_d = TRANSFER. // increment bit counter if (ctr_q == 3'b111) begin // if we are on the last bit state_d = IDLE. mosi_q <= 1'b0. data_q <= 8'b0. new_data_q <= new_data_d. new_data_q <= 1'b0. // change state end end TRANSFER: begin sck_d = sck_q + 1'b1. data_q <= data_d. sck_q <= 4'b0. state_q <= IDLE.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 end WAIT_HALF: begin sck_d = sck_q + 1'b1. // increment clock counter if (sck_q == {CLK_DIV-1{1'b1}}) begin // if clock is half full (about to fall) sck_d = 1'b0. end else begin ctr_q <= ctr_d. // increment clock counter if (sck_q == 4'b0000) begin // if clock counter is 0 mosi_d = data_q[7]. state_q <= state_d. mosi_q <= mosi_d. data_out_q <= 8'b0. // output data new_data_d = 1'b1. // signal data is valid end end end endcase end always @(posedge clk) begin if (rst) begin ctr_q <= 3'b0. sck_q <= sck_d. // output the MSB of data end else if (sck_q == {CLK_DIV-1{1'b1}}) begin // else if it's half full (about data_d = {data_q[6:0]. miso}. end end endmodule . // read in data (shift in) end else if (sck_q == {CLK_DIV{1'b1}}) begin // else if it's full (about to ris ctr_d = ctr_q + 1'b1.

. The parameter CLK_DIV is used to specify how much the FPGA's clock should be divided. If CLK_DIV was set to 3. however. The overall idea is the same. which means that the frequency of SCK will be 1/4th (2^2 = 4 clock cycles) of that of the FPGA. the FPGA now needs to generate the SCK signal.91 92 93 94 95 96 97 In this case CPOL = 0 and CPHA = 1. The default value is 2. SCK would be 1/8th (2^3 = 8 clock cycles) the frequency of the FPGA's clock.