1 //testbench
2 `timescale 1ns/1ns
3 module lcd_spi_m_tb();
4 reg rst_n_i;
5 reg spi_clkx_i;
6 reg [31:0] spi_data_i;
7 reg spi_start;
8 reg spi_miso_r1,spi_miso_r2;
9 wire spi_miso_i;
10 wire [0:0] spi_done;
11 wire [0:0] spi_busy;
12 wire [0:0] spi_cs_o;
13 wire [0:0] spi_scl_o;
14 wire [0:0] spi_mosi_o;
15 wire [31:0] spi_data_o;
16
17 localparam CPOL=1'B0 ;
18 localparam CPHA=1'B1 ;
19
20
21
22 always #50 spi_clkx_i<=~spi_clkx_i;
23 initial begin
24 rst_n_i=0;
25 spi_clkx_i=0;
26 #200;
27 spi_start=0;
28 rst_n_i=1;
29 @(posedge spi_clkx_i)
30 spi_data_i=16'h8121;
31 spi_start=1;
32 @(posedge spi_clkx_i)
33 spi_start=0;
34 @(posedge spi_done)
35 #200;
36 @(posedge spi_clkx_i)
37 spi_data_i=16'h0003;
38 spi_start=1;
39 @(posedge spi_clkx_i)
40 spi_start=0;
41 @(posedge spi_done)
42 #200;
43 @(posedge spi_clkx_i)
44 spi_data_i=16'hF227;
45 spi_start=1;
46 @(posedge spi_clkx_i)
47 spi_start=0;
48 @(posedge spi_done)
49 #200;
50 @(posedge spi_clkx_i)
51 spi_data_i=16'hA31B;
52 spi_start=1;
53 @(posedge spi_clkx_i)
54 spi_start=0;
55 @(posedge spi_done)
56 $stop;
57 end
58
59 always @(negedge spi_scl_o or negedge rst_n_i )//要根据CPOL CPHA配置 spi_scl_o采样极性
60 begin
61 if(rst_n_i==1'b0)
62 spi_miso_r1<=1'b1;
63 else if (spi_cs_o==1'b0 )
64 spi_miso_r1<=~spi_miso_r1;
65 else
66 spi_miso_r1<=1'b0;
67 end
68
69 always @(posedge spi_scl_o or negedge rst_n_i )//要根据CPOL CPHA配置 spi_scl_o采样极性
70 begin
71 if(rst_n_i==1'b0)
72 spi_miso_r2<=1'b1;
73 else if (spi_cs_o==1'b0 )
74 spi_miso_r2<=~spi_miso_r2;
75 else
76 spi_miso_r2<=1'b0;
77 end
78 assign spi_miso_i =(CPOL==1'B0 && CPHA==1'B0 || CPOL==1'B1 && CPHA==1'B1)? spi_miso_r1 :spi_miso_r2;
79
80 lcd_spi_m
81 #(
82 .SPI_IN_WIDTH(6'd16),//spi 输入位数
83 .SPI_OUT_WIDTH(6'd16),//SPI 输出位数
84 .SPI_CPOL(CPOL),
85 .SPI_CPHA(CPHA),
86 .CLK_DIV(6'D5),
87 .CS_F_DELAY(6'd3),
88 .CS_B_DELAY(6'd3)
89
90
91
92 )
93 lcd_spi_m_inst
94 (
95 .rst_n_i (rst_n_i ) ,
96 .spi_clkx_i (spi_clkx_i ) ,
97 .spi_data_i (spi_data_i ) ,
98 .spi_start (spi_start ) ,
99 .spi_miso_i (spi_miso_i ) ,
100 .spi_done (spi_done ) ,
101 .spi_busy (spi_busy ) ,
102 .spi_cs_o (spi_cs_o ) ,
103 .spi_scl_o (spi_scl_o ) ,
104 .spi_mosi_o (spi_mosi_o ) ,
105 .spi_data_o (spi_data_o )
106
107 );
108
109 endmodule
1 //SPI主程序
2 //功能:完成32位以内SPI接口的数据双向通信
3 module lcd_spi_m
4 #(
5 parameter [5:0]SPI_IN_WIDTH =6'd16,//spi 输入位数
6 parameter [5:0]SPI_OUT_WIDTH =6'd16,//SPI 输出位数
7 parameter [0:0]SPI_CPOL=1'b0,//空闲状态SCL电平 0:SCL=0 1:SCL=1
8 parameter [0:0]SPI_CPHA=1'b0, //SPI数据在哪个SCL边沿有效 0:数据在SCL第一个边沿有效,1:数据在SCL第二个边沿有效,
9 parameter [5:0]CLK_DIV =6'D3, //设定SPI_SCL半个周期所占的spi_clkx_i时钟个数
10 parameter [5:0]CS_F_DELAY=6'D1, //CS前延时,相对于spi_scl_o时钟个数
11 parameter [5:0]CS_B_DELAY=6'D1 //CS后延时,相对于spi_scl_o时钟个数
12
13
14 )
15 (
16 input wire [0:0] rst_n_i, //复位输入,低电平复位
17 input wire [0:0] spi_clkx_i,//SPI系统时钟 为SCL输出时钟的倍数 spi_clkx_i=spi_scl_o*2(高电平+低电平)*CLK_DIV
18 input wire [31:0] spi_data_i,//输入32位要从MOSI发送出去的数据
19 input wire [0:0] spi_start, //单次发送开始,把数据送到spi_data_i 并把spi_start维技一个周期的高电平
20 input wire [0:0] spi_miso_i,//主机接收从机输出引脚
21 output reg [0:0] spi_done,//SPI完成一次传输并从spi_data_o输出读到的数???
22 output reg [0:0] spi_busy,//SPI忙信号输出,在忙状态时不接收外部数据,高表示忙
23 output reg [0:0] spi_cs_o,//SPI片选信号输出低有效
24 output wire [0:0] spi_scl_o,//SPI 时钟信号输出,请结合CPOL CPHA分析有效???
25 output reg [0:0] spi_mosi_o,//SPI主机输出从机输入接口
26 output reg [31:0] spi_data_o//从从机读到的数据在SPI_DONE为高时为有效数据
27
28
29 );
30 localparam [5:0]CS_F_CNT=CS_F_DELAY-6'D1; //CS前面延时
31 localparam [5:0]CS_B_CNT=CS_B_DELAY-6'D1; //CS前面延时
32 localparam [5:0] WIDTH_MAX=(SPI_IN_WIDTH>SPI_OUT_WIDTH)? SPI_IN_WIDTH :SPI_OUT_WIDTH;//16
33 localparam [7:0] SPI_MAX =WIDTH_MAX+CS_F_DELAY+CS_B_DELAY-1'D1;//17
34
35
36 reg [7:0] spi_scl_cnt;
37 reg [7:0 ] clk_cnt;
38 reg [1:0] pol_cnt;
39 reg [0:0] spi_sclk_r;
40 wire [0:0] spi_flag;
41 wire [0:0] pol_flag;
42 //产生时钟计数
43 always @(posedge spi_clkx_i or negedge rst_n_i)
44 begin
45 if(rst_n_i==1'b0)
46 clk_cnt<=8'd0;
47 else if(spi_busy==1'b1 )
48 begin
49 if(clk_cnt>=CLK_DIV-1'd1)
50 clk_cnt<=8'd0;
51 else
52 clk_cnt<=clk_cnt+1'd1;
53 end
54 else
55 clk_cnt<=8'd0;
56 end
57
58
59
60 //产生SPI_SCL极性计数
61 always @(posedge spi_clkx_i or negedge rst_n_i)
62 begin
63 if(rst_n_i==1'b0)
64 pol_cnt<=2'd0;
65 else if(pol_cnt>=2'd1 && clk_cnt>=CLK_DIV-1'd1)
66 pol_cnt<=2'd0;
67 else if(clk_cnt>=CLK_DIV-1'd1)
68 pol_cnt<=pol_cnt+1'd1;
69 else
70 pol_cnt<=pol_cnt;
71 end
72
73 assign pol_flag= (clk_cnt>=CLK_DIV-1'd1)? 1'b1:1'b0;
74
75 //产生spi_scl时钟计数
76 always @(posedge spi_clkx_i or negedge rst_n_i)
77 begin
78 if(rst_n_i==1'b0)
79 spi_scl_cnt<=15'd0;
80 else if((spi_scl_cnt>=SPI_MAX) &&(spi_flag==1'b1))
81 spi_scl_cnt<=8'd0;
82 else if(spi_flag==1'b1)
83 spi_scl_cnt<=spi_scl_cnt+1'd1;
84 else
85
86 spi_scl_cnt<=spi_scl_cnt;
87
88 end
89 assign spi_flag=(clk_cnt>=CLK_DIV-1'd1 && pol_cnt>=1'd1)? 1'b1:1'b0;
90
91 //输出SPI_CS信号
92 always @(posedge spi_clkx_i or negedge rst_n_i)
93 begin
94 if(rst_n_i==1'b0)
95 spi_cs_o<=1'b1;
96 else if(spi_start==1'b1 && spi_busy==1'b0)
97 spi_cs_o<=1'b0;
98 else if((spi_scl_cnt>=SPI_MAX) &&(spi_flag==1'b1))
99 spi_cs_o<=1'b1;
100 else
101 spi_cs_o<=spi_cs_o;
102 end
103
104 //输出SPI_DONE信号
105 always @(posedge spi_clkx_i or negedge rst_n_i)
106 begin
107 if(rst_n_i==1'b0)
108 spi_done<=1'b0;
109 else if((spi_scl_cnt>=SPI_MAX) &&(spi_flag==1'b1))
110 spi_done<=1'b1;
111 else
112 spi_done<=1'b0;
113 end
114
115
116 //输出spi_scl信号
117 always @(posedge spi_clkx_i or negedge rst_n_i)
118 begin
119 if(rst_n_i==1'b0)
120 begin
121 spi_sclk_r<=1'b0;
122 end
123 else if(pol_flag==1'b1)
124 spi_sclk_r<=~spi_sclk_r;
125 else
126 begin
127 spi_sclk_r<=spi_sclk_r;
128 end
129 end
130 assign spi_scl_o =((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)))?((SPI_CPOL)? ~spi_sclk_r:spi_sclk_r):((SPI_CPOL==1'B1)? 1'B1:1'B0);
131
132
133 //在spi_start???时捕获数???
134 reg [31:0] temp_data_i;
135 //输出SPI_MOSI信号
136 always @(posedge spi_clkx_i or negedge rst_n_i)
137 begin
138 if(rst_n_i==1'b0)
139 begin
140 spi_mosi_o<=1'b0;
141 spi_busy<=1'b0;
142 temp_data_i<=32'b0;
143 end
144 else if(spi_start==1'b1 && spi_busy==1'b0) //在spi_start???时捕获数???
145 begin
146 temp_data_i<=spi_data_i;
147 spi_busy<=1'b1;
148 end
149 else if(spi_done==1'b1)
150 spi_busy<=1'b0;
151 else if(SPI_CPHA==1'b0)
152 begin
153 if((spi_scl_cnt>=CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)) &&(spi_flag==1'b1) && (pol_flag==1'b1) )
154 begin
155 spi_mosi_o<=temp_data_i[SPI_OUT_WIDTH-1'd1];
156 temp_data_i<={temp_data_i[(SPI_OUT_WIDTH-2'd2):0],temp_data_i[SPI_OUT_WIDTH-1'd1]};
157 end
158 else
159 begin
160 spi_mosi_o<=spi_mosi_o;
161 end
162
163 end
164 else
165 begin
166 if((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT))&& (spi_flag==1'b0) && (pol_flag==1'b1))//CPOL=0 CPHA=1->NG
167 begin
168 spi_mosi_o<=temp_data_i[SPI_OUT_WIDTH-1'd1];
169 temp_data_i<={temp_data_i[SPI_OUT_WIDTH-2'd2:0],temp_data_i[SPI_OUT_WIDTH-1'd0]};
170 end
171 else
172 begin
173 spi_mosi_o<=spi_mosi_o;
174 end
175 end
176
177
178
179 end
180
181 //接收SPI_MISO信号
182 always @(posedge spi_clkx_i or negedge rst_n_i)
183 begin
184 if(rst_n_i==1'b0)
185 spi_data_o<=32'b0;
186 else if(SPI_CPHA==1'b0)
187 begin
188 if((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)) &&(pol_flag==1'b1)&& (spi_flag==1'b0) )
189 begin
190 spi_data_o<={spi_data_o[30:0],spi_miso_i};
191 end
192 else
193 begin
194 spi_data_o<=spi_data_o;
195 end
196 end
197 else if(SPI_CPHA==1'b1)
198 begin
199 if((spi_scl_cnt>CS_F_CNT) && (spi_scl_cnt<(SPI_MAX-CS_B_CNT)) &&(pol_flag==1'b1)&& (spi_flag==1'b1) )
200 begin
201 spi_data_o<={spi_data_o[30:0],spi_miso_i};
202 end
203 else
204 begin
205 spi_data_o<=spi_data_o;
206 end
207 end
208 else
209 begin
210 spi_data_o<=spi_data_o;
211 end
212
213 end
214
215
216 endmodule
![]()
![]()
![]()
![]()