KEMBAR78
SPI Module | PDF | Computer Engineering | Computer Data
0% found this document useful (0 votes)
145 views5 pages

SPI Module

The spi_slave module defines an SPI slave module for an FPGA to interface with an AVR microcontroller master. It uses registers to synchronize the SPI signals and shifts data in on rising SCK edges and out on falling edges. The spi module defines an SPI master module for an FPGA to interface with an RTC slave device. It generates the SCK clock divided from the FPGA clock and shifts data out on the initial SCK pulse and in on subsequent pulses to transfer data frames.

Uploaded by

leduclebk93
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
145 views5 pages

SPI Module

The spi_slave module defines an SPI slave module for an FPGA to interface with an AVR microcontroller master. It uses registers to synchronize the SPI signals and shifts data in on rising SCK edges and out on falling edges. The spi module defines an SPI master module for an FPGA to interface with an RTC slave device. It generates the SCK clock divided from the FPGA clock and shifts data out on the initial SCK pulse and in on subsequent pulses to transfer data frames.

Uploaded by

leduclebk93
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 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

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;


// 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

This is module assumes CPOL = 0 and CPHA = 0.


It waits for SS to go low. Once SS is low, it starts shifting data into the data_d/_q register. Once
eight bits have been shifted in it signals that it has new data on dout. On the falling edges of the
clock, it shifts out the data that was provided by din at the beginning of the transmission.

SPI Master

Our Clock/Visualizer Shield, uses a Real-Time Clock (RTC) device that provides the Mojo with the
current time. The RTC is connected to the Mojo through an SPI bus. In this case, the FPGA on the
Mojo is the master and the RTC is the slave.
module spi #(parameter CLK_DIV = 2)(
1
input clk,
2
input rst,
3
input miso,
4
output mosi,
output sck,
5
input start,
6
input[7:0] data_in,
7
output[7:0] data_out,
8
output busy,
9
output new_data
);
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;
localparam IDLE = 2'd0,
WAIT_HALF = 2'd1,
TRANSFER = 2'd2;
reg [STATE_SIZE-1:0] state_d, state_q;
reg
reg
reg
reg
reg
reg

[7:0] data_d, data_q;


[CLK_DIV-1:0] sck_d, sck_q;
mosi_d, mosi_q;
[2:0] ctr_d, ctr_q;
new_data_d, new_data_q;
[7:0] data_out_d, data_out_q;

assign
assign
assign
assign
assign

mosi = mosi_q;
sck = (~sck_q[CLK_DIV-1]) & (state_q == TRANSFER);
busy = state_q != IDLE;
data_out = data_out_q;
new_data = new_data_q;

always @(*) begin


sck_d = sck_q;
data_d = data_q;
mosi_d = mosi_q;
ctr_d = ctr_q;
new_data_d = 1'b0;
data_out_d = data_out_q;
state_d = state_q;
case (state_q)
IDLE: begin
sck_d = 4'b0;
// reset clock counter
ctr_d = 3'b0;
// reset bit counter
if (start == 1'b1) begin // if start command
data_d = data_in;
// copy data to send
state_d = WAIT_HALF;
// change state
end

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;
// reset to 0
state_d = TRANSFER;
// change state
end
end
TRANSFER: begin
sck_d = sck_q + 1'b1;
// increment clock counter
if (sck_q == 4'b0000) begin
// if clock counter is 0
mosi_d = data_q[7];
// 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};
// 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;
// increment bit counter
if (ctr_q == 3'b111) begin
// if we are on the last bit
state_d = IDLE;
// change state
data_out_d = data_q;
// 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;
data_q <= 8'b0;
sck_q <= 4'b0;
mosi_q <= 1'b0;
state_q <= IDLE;
data_out_q <= 8'b0;
new_data_q <= 1'b0;
end else begin
ctr_q <= ctr_d;
data_q <= data_d;
sck_q <= sck_d;
mosi_q <= mosi_d;
state_q <= state_d;
data_out_q <= data_out_d;
new_data_q <= new_data_d;
end
end
endmodule

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

You might also like