1 /***********************************************************************************************
2 * SPI MASTER
3 * January 2007
4 ************************************************************************************************/
5 `timescale 10ns/
1ns
6 module SPI_Master ( miso, mosi, sclk, ss, data_bus, CS, addr, pro_clk, WR, RD);
7
8 inout [
7:
0] data_bus;
// 8 bit bidirectional data bus
9 input pro_clk;
// Host Processor clock
10 input miso;
// Master in slave out
11 input [
1:
0] addr;
// A1 and A0, lower bits of address bus
12 input CS;
// Chip Select
13 input WR, RD;
// Write and read enables
14
15 output mosi;
// Master out slave in
16 output sclk;
// SPI clock
17 output [
7:
0] ss;
// 8 slave select lines
18
19 reg [
7:
0] shift_register;
// Shift register
20 reg [
7:
0] txdata;
// Transmit buffer
21 reg [
7:
0] rxdata;
// Receive buffer
22 reg [
7:
0] data_out;
// Data output register
23 reg [
7:
0] data_out_en;
// Data output enable
24 reg [
7:
0] control, status;
// Control Register COntrols things like ss, CPOL, CPHA, clock divider
25 // Status Register is a dummy register never used.
26
27 reg [
7:
0] clk_divide;
// Clock divide counter
28 reg [
3:
0] count;
// SPI word length counter
29 reg sclk;
30 reg slave_cs;
// Slave cs flag
31 reg mosi;
// Master out slave in
32 reg spi_word_send;
// Will send a new spi word.
33
34 wire [
7:
0] data_bus;
35 wire [
7:
0] data_in =
data_bus;
36 wire spi_clk_gen;
37 wire [
2:
0] divide_factor = control[
2:
0];
38 wire CPOL = control[
3];
39 wire CPHA = control[
4];
40 wire [
7:
0]ss;
41
42
43 /* Slave Select lines */
44 assign ss[
7] = ~( control[
7] & control[
6] & control[
5] & (~
slave_cs));
45 assign ss[
6] = ~( control[
7] & control[
6] & ~control[
5] & (~
slave_cs));
46 assign ss[
5] = ~( control[
7] & ~control[
6] & control[
5] & (~
slave_cs));
47 assign ss[
4] = ~( control[
7] & ~control[
6] & ~control[
5] & (~
slave_cs));
48 assign ss[
3] = ~(~control[
7] & control[
6] & control[
5] & (~
slave_cs));
49 assign ss[
2] = ~(~control[
7] & control[
6] & ~control[
5] & (~
slave_cs));
50 assign ss[
1] = ~(~control[
7] & ~control[
6] & control[
5] & (~
slave_cs));
51 assign ss[
0] = ~(~control[
7] & ~control[
6] & ~control[
5] & (~
slave_cs));
52
53 /* clock divide */
54 assign spi_clk_gen =
clk_divide[divide_factor];
55
56 /* Clock Divider */
57 always @ (
negedge pro_clk)
begin
58 clk_divide = clk_divide +
1;
59 end
60
61 /* Reading the miso line and shifting */
62 always @ (
posedge (sclk ^ (CPHA ^ CPOL))
or posedge spi_word_send)
begin
63 if (spi_word_send)
begin
64 shift_register[
7:
0] =
txdata;
65 end else begin
66 shift_register = shift_register <<
1;
67 shift_register[
0] <=
miso;
68 end
69 end
70
71 /* Writing the mosi */
72 always @ (
negedge (sclk ^ (CPHA ^ CPOL))
or posedge spi_word_send)
begin
73 if (spi_word_send)
begin
74 mosi = txdata[
7];
75 end else begin
76 mosi = shift_register[
7];
77 end
78 end
79
80 /* Contolling the interrupt bit in the status bit */
81 always @ (
posedge slave_cs
or posedge spi_word_send)
begin
82 if (spi_word_send)
begin
83 status[
0] =
0;
84 end else begin
85 status =
8'h01;
86 rxdata = shift_register;
// updating read buffer
87 end
88 end
89
90 /* New SPI wrod starts when the transmit buffer is updated */
91 always @ (
posedge pro_clk)
begin
92 if (spi_word_send)
begin
93 slave_cs <=
0;
94 end else if ((count ==
8) & ~(sclk ^ CPOL))
begin
95 slave_cs <=
1;
96 end
97 end
98
99 /* New Spi word is intiated when transmit buffer is updated */
100 always @ (
posedge pro_clk)
begin
101 if (CS & WR & addr[
1] & ~addr[
0])
begin
102 spi_word_send <=
1;
103 end else begin
104 spi_word_send <=
0;
105 end
106 end
107
108 /* Generating the SPI clock */
109 always @ (
posedge spi_clk_gen)
begin
110 if (~slave_cs)
begin
111 sclk = ~
sclk;
112 end else if (~CPOL)
begin
113 sclk =
0;
114 end else begin
115 sclk =
1;
116 end
117 end
118
119 /* Counting SPI word length */
120 always @ (
posedge sclk
or posedge slave_cs)
begin
121 if (slave_cs)
begin
122 count =
0;
123 end else begin
124 count = count +
1;
125 end
126 end
127
128 /* Reading, writing SPI registers */
129 always @ (
posedge pro_clk)
begin
130 if (CS)
begin
131 case (addr)
132 2'b00 : if (WR) control <= data_in;
133 2'b01 : if (RD) data_out <= status; // Void
134 2'b10 : if (WR) txdata <= data_in;
135 2'b11 : if (RD) data_out <= rxdata;
136 endcase
137 end
138 end
139
140 /* Controlling the data out enable */
141 always @ (RD
or data_out)
begin
142 if (RD)
143 data_out_en =
data_out;
144 else
145 data_out_en =
8'bz;
146 end
147
148 assign data_bus =
data_out_en;
149
150 initial
151 begin
152 mosi =
0;
153 //sclk = 0;
154 control =
0;
155 count =
0;
156 slave_cs =
1;
157 txdata =
0;
158 rxdata =
0;
159 clk_divide =
0;
160 data_out =
0;
161 end
162
163 endmodule
164
165 /********************************************** END ******************************************************************/
/******************************************************************************************
* Test Bench for SPI Master
* January 2007
*******************************************************************************************/
`timescale 10ns/
1ns
module SPI_master_test;
wire [
7:
0] data_bus;
// Bidirectional
wire mosi;
// Output from main module
wire sclk;
// Output from main module
wire [
7:
0] ss;
// Output from main module
/* Inputs to main module */
reg miso;
reg CS;
reg [
1:
0] addr;
reg pro_clk;
reg WR,RD;
SPI_Master tb ( miso, mosi, sclk, ss, data_bus, CS, addr, pro_clk, WR, RD);
/* Internal registers defined for TB */
reg [
7:
0] data_send;
reg [
7:
0] transmit_store;
reg [
7:
0] data_receive;
reg [
7:
0] miso_data;
reg [
7:
0] mosi_data;
assign data_bus =
data_send;
initial // Generates serial clock of time period 10
begin
pro_clk =
0;
forever #
5 pro_clk = !
pro_clk;
end
initial
begin
CS =
0;
RD =
0;
WR =
0;
data_send =
0;
addr =
0;
miso =
0;
#20
/* Updating Control register */
@ (negedge pro_clk)
CS =
1;
WR =
1;
data_send =
0;
addr =
0;
/* Updating Transmit buffer */
@ (negedge pro_clk)
CS =
1;
WR =
1;
data_send =
$random;
addr =
2'b10;
#
1 transmit_store =
data_send;
@ (negedge pro_clk)
$display ("Transmit Buffer loaded");
$display ("SS[0] = 0, CPHA = 0, CPOL = 0 at time:",$
time);
$display ("Observe Waveform for spi clock frequency, spi data changing at falling egde, valid at rising edge");
CS =
0;
WR =
0;
data_send =
8'bz;
@ (posedge ss[
0])
#20
/* Checking Status */
@ (negedge pro_clk)
CS =
1;
RD =
1;
addr =
2'b01;
@ (
negedge pro_clk)
data_receive =
data_bus;
@ (negedge pro_clk)
if (data_receive[
0])
begin
$display("Interrupt detected at time:", $
time);
addr =
2'b11;
end else begin
$display("Interrupt detect failed at time:", $
time);
end
@ (negedge pro_clk)
data_receive =
data_bus;
if (data_bus == miso_data)
begin
$display("Data received from spi slave verified", $
time);
end else begin
$display("Data receive failed",$
time);
end
/* Writing new control word */
@ (negedge pro_clk)
CS =
1;
WR =
1;
RD =
0;
data_send =
8'b10001001;
addr =
0;
@ (negedge pro_clk)
CS =
1;
WR =
1;
data_send =
$random;
addr =
2'b10;
#
1 transmit_store =
data_send;
@ (negedge pro_clk)
$display ("\n Transmit Buffer reloaded");
$display ("Observe Waveform for spi clock frequency, spi data changing at rising edge and valid at falling edge");
$display ("SS[4] = 0, CPHA = 0, CPOL = 1 at time:",$
time);
CS =
0;
RD =
0;
WR =
0;
data_send =
8'bz;
@ (posedge ss[
4])
#20
/* Checking Status */
@ (negedge pro_clk)
CS =
1;
RD =
1;
addr =
2'b01;
@ (
negedge pro_clk)
data_receive =
data_bus;
@ (negedge pro_clk)
if (data_receive[
0])
begin
$display("Interrupt detected at time:", $
time);
addr =
2'b11;
end else begin
$display("Interrupt detect failed at time:", $
time);
end
@ (negedge pro_clk)
data_receive =
data_bus;
if (data_bus == miso_data)
begin
$display("Data received from spi slave verified", $
time);
end else begin
$display("Data receive failed",$
time);
end
/* Writing new control word */
@ (negedge pro_clk)
CS =
1;
WR =
1;
RD =
0;
data_send =
8'b11110010;
addr =
0;
@ (negedge pro_clk)
CS =
1;
WR =
1;
data_send =
$random;
addr =
2'b10;
#
1 transmit_store =
data_send;
@ (negedge pro_clk)
$display ("\n Transmit Buffer reloaded");
$display ("Observe Waveform for spi clock frequency, spi data changing at rising edge and valid at falling edge");
$display ("SS[7] = 0, CPHA = 1, CPOL = 0 at time:",$
time);
CS =
0;
RD =
0;
WR =
0;
data_send =
8'bz;
@ (posedge ss[
7])
#20
/* Checking Status */
@ (negedge pro_clk)
CS =
1;
RD =
1;
addr =
2'b01;
@ (
negedge pro_clk)
data_receive =
data_bus;
@ (negedge pro_clk)
if (data_receive[
0])
begin
$display("interrupt detected at time:", $
time);
addr =
2'b11;
end else begin
$display("interrupt detect failed at time:", $
time);
end
@ (negedge pro_clk)
data_receive =
data_bus;
if (data_bus == miso_data)
begin
$display("Data received from spi slave verified", $
time);
end else begin
$display("Data receive failed",$
time);
end
/* Writing new control word */
@ (negedge pro_clk)
CS =
1;
WR =
1;
RD =
0;
data_send =
8'b01111100;
addr =
0;
@ (negedge pro_clk)
CS =
1;
WR =
1;
data_send =
$random;
addr =
2'b10;
#
1 transmit_store =
data_send;
@ (negedge pro_clk)
$display ("\n Transmit Buffer reloaded");
$display ("Observe Waveform for spi clock frequency, spi data changing at falling edge and valid at rising edge");
$display ("SS[3] = 0, CPHA = 1, CPOL = 1 at time:",$
time);
CS =
0;
RD =
0;
WR =
0;
data_send =
8'bz;
@ (posedge ss[
3])
#20
/* Checking Status */
@ (negedge pro_clk)
CS =
1;
RD =
1;
addr =
2'b01;
@ (
negedge pro_clk)
data_receive =
data_bus;
@ (negedge pro_clk)
if (data_receive[
0])
begin
$display("Interrupt detected at time:", $
time);
addr =
2'b11;
end else begin
$display("Interrupt detect failed at time:", $
time);
end
@ (negedge pro_clk)
data_receive =
data_bus;
if (data_bus == miso_data)
begin
$display("Data received from spi slave verified", $
time);
end else begin
$display("Data receive failed",$
time);
end
@ (negedge pro_clk)
$display ("\n PASS: hit break to stop simulation");
end
initial
begin
/* Writing MISO / Reading MOSI for random values */
#20
miso_data =
$random;
@ (negedge ss[
0])
miso = miso_data[
7];
@ (posedge sclk)
mosi_data[7] =
mosi;
@ (negedge sclk)
miso = miso_data[
6];
@ (posedge sclk)
mosi_data[6] =
mosi;
@ (negedge sclk)
miso = miso_data[
5];
@ (posedge sclk)
mosi_data[5] =
mosi;
@ (negedge sclk)
miso = miso_data[
4];
@ (posedge sclk)
mosi_data[4] =
mosi;
@ (negedge sclk)
miso = miso_data[
3];
@ (posedge sclk)
mosi_data[3] =
mosi;
@ (negedge sclk)
miso = miso_data[
2];
@ (posedge sclk)
mosi_data[2] =
mosi;
@ (negedge sclk)
miso = miso_data[
1];
@ (posedge sclk)
mosi_data[1] =
mosi;
@ (negedge sclk)
miso = miso_data[
0];
@ (posedge sclk)
mosi_data[0] =
mosi;
#5
if(mosi_data == transmit_store)
begin
$display("Data transmitted to spi slave verified", $
time );
end else begin
$display("Data Transmit to spi slave failed !", $
time );
end
/* Next set : CPOL = 1, CPHA = 0 */
@ (negedge ss[
4])
miso_data =
$random;
miso = miso_data[
7];
@ (negedge sclk)
mosi_data[7] =
mosi;
@ (posedge sclk)
miso = miso_data[
6];
@ (negedge sclk)
mosi_data[6] =
mosi;
@ (posedge sclk)
miso = miso_data[
5];
@ (negedge sclk)
mosi_data[5] =
mosi;
@ (posedge sclk)
miso = miso_data[
4];
@ (negedge sclk)
mosi_data[4] =
mosi;
@ (posedge sclk)
miso = miso_data[
3];
@ (negedge sclk)
mosi_data[3] =
mosi;
@ (posedge sclk)
miso = miso_data[
2];
@ (negedge sclk)
mosi_data[2] =
mosi;
@ (posedge sclk)
miso = miso_data[
1];
@ (negedge sclk)
mosi_data[1] =
mosi;
@ (posedge sclk)
miso = miso_data[
0];
@ (negedge sclk)
mosi_data[0] =
mosi;
#5
if(mosi_data == transmit_store)
begin
$display("Data transmitted to spi slave verified", $
time );
end else begin
$display("Data Transmit to spi slave failed !", $
time );
end
/* Next set : CPOL = 0, CPHA = 1 */
@ (negedge ss[
7])
miso_data =
$random;
@ (posedge sclk)
miso = miso_data[
7];
@ (negedge sclk)
mosi_data[7] =
mosi;
@ (posedge sclk)
miso = miso_data[
6];
@ (negedge sclk)
mosi_data[6] =
mosi;
@ (posedge sclk)
miso = miso_data[
5];
@ (negedge sclk)
mosi_data[5] =
mosi;
@ (posedge sclk)
miso = miso_data[
4];
@ (negedge sclk)
mosi_data[4] =
mosi;
@ (posedge sclk)
miso = miso_data[
3];
@ (negedge sclk)
mosi_data[3] =
mosi;
@ (posedge sclk)
miso = miso_data[
2];
@ (negedge sclk)
mosi_data[2] =
mosi;
@ (posedge sclk)
miso = miso_data[
1];
@ (negedge sclk)
mosi_data[1] =
mosi;
@ (posedge sclk)
miso = miso_data[
0];
@ (negedge sclk)
mosi_data[0] =
mosi;
#5
if(mosi_data == transmit_store)
begin
$display("Data transmitted to spi slave verified", $
time );
end else begin
$display("Data Transmit to spi slave failed !", $
time );
end
/* Next set : CPOL = 1, CPHA = 1 */
@ (negedge ss[
3])
miso_data =
$random;
@ (negedge sclk)
miso = miso_data[
7];
@ (posedge sclk)
mosi_data[7] =
mosi;
@ (negedge sclk)
miso = miso_data[
6];
@ (posedge sclk)
mosi_data[6] =
mosi;
@ (negedge sclk)
miso = miso_data[
5];
@ (posedge sclk)
mosi_data[5] =
mosi;
@ (negedge sclk)
miso = miso_data[
4];
@ (posedge sclk)
mosi_data[4] =
mosi;
@ (negedge sclk)
miso = miso_data[
3];
@ (posedge sclk)
mosi_data[3] =
mosi;
@ (negedge sclk)
miso = miso_data[
2];
@ (posedge sclk)
mosi_data[2] =
mosi;
@ (negedge sclk)
miso = miso_data[
1];
@ (posedge sclk)
mosi_data[1] =
mosi;
@ (negedge sclk)
miso = miso_data[
0];
@ (posedge sclk)
mosi_data[0] =
mosi;
#5
if(mosi_data == transmit_store)
begin
$display("Data transmitted to spi slave verified", $
time );
end else begin
$display("Data Transmit to spi slave failed !", $
time );
end
end
endmodule
/*************************************** END OF TB ***********************************************************************/
转载于:https://www.cnblogs.com/shangdawei/archive/2012/05/16/2503511.html
相关资源:数据结构—成绩单生成器