首先简单的想一下这个模块应该怎么设计。
拿到这个小题目你的思路是怎么样的呢?很多时候靠经验设计,并没有一个顺序的思路。
第二步:画出计数器结构(搞清楚数的是什么东西)
cnt表示上一个时钟数到的结果。数x下,通用表达式:add_cnt&&cnt==x-1;
第三步:确认计数器加1条件(数什么)和结束条件(数多少个),注意先考虑加1,在考虑结束条件;
我们计数器cnt数的是什么呢?dout==1的时钟个数,cnt要数10个(10是功能要求来的)
第四步:确认其他信号的变化条件(dout 变化点,即0变1,1为0的条件)
dout由0变1 的条件是什么?是en1;
dout由1变0的条件是? dout1的时钟个数为10
cnt add_cnt:dout ==1
cnt 数多少:10个
// 计数器模板
always@(posedge clk or negedge rst_n) begin
if(!rst_n) begin
cnt <= 0;
end
else if(add_cnt) begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1;
end
end
assign add_cnt = dout == 1; // 加1的条件
assign end_cnt = add_cnt && cnt == 10-1; // 数10下
dout == 1 : en == 1
dout == 0 : 数到10个
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0) begin
dout <= 0;
end
else if(en == 1) begin // dout什么时候拉高
dout <= 1;
end
else if (end_cnt) begin //(add_cnt && cnt == 10-1) begin // 数10下之后dout拉低
dout <= 0;
end
end
第五步:写出计数器代码(always除了名字外不能改变,加1条件即是要数什么东西,结束条件要记住格式后)
对于这种状态还是数cnt, 可以这种思考。
也可以这样计数。这是正确的计数方式
第一步:画出输入输出波形
第二步:画出计数器结构
cnt0的加1条件: flag == 1 ,加一个信号把flag
cnt0 要数多少:3个
cnt1的加1条件:end_cnt0 //
cnt1 要数多少个:3个
flag >1: en == 1
flag >0: end_cnt1
dout>1: add_cnt0 && cnt0 == 1-1 // 当cnt0 数一个的时候拉高
dout>0: end_cnt0 (add_cnt0 && cnt0 == 3-1)
然后就填填空啦!!!!!!
CS 选择工作模式
DIN选择通道地址
DOUT 输出给FPGA
module SPI(
input clk,
input rst_n,
input start,
input [2:0]channel,
// ADC128s022
input DOUT,
output reg SCLK,
output reg DIN,
output reg CS_N,
output reg done,
output [11:0] data.
);
reg en;
reg [2:0] r_channel;
// r_channel 使channel的信号稳定
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
r_channel <= 'd0;
else if(start)
r_channel <= channel;
else
r_channel <= r_channel;
end
// 转换使能信号
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
en <= 1'b0;
else if(start)
en <= 1'b1;
else if(done)
en <= 1'b0;
else
en <= en;
end
reg [4:0] cnt;
reg cnt_flag;
reg [5:0]SCLK_CNT;
// cnt 的变化
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt <= 'd0;
else if(en) begin
if(cnt == 'd10)
cnt <= 'd0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= 'd0;
end
// cnt flag
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
cnt_flag <= 1'b0;
else if(cnt == 'd10)
cnt_flag <= 1'b1;
else
cnt_flag <= 1'b0;
end
// sclk_cnt
always@ (posedge clk or negedge rst_n) begin
if(!rst_n)
sclk_CNT <= 'd0;
else if(en) begin
if(SCLK_CNT == 'd33)
SCLK_CNT <= 'd0;
else if(cnt_flag)
SCLK_CNT <= SCLK + 1'b1;
else
SCLK_CNT <= SCLK_CNT;
end
else
SCLK_CNT <= 'd0;
end
reg [11:0] r_data;
// ============================================
always@(posedge clk negedge rst_n) begin
if(!rst_n) begin
SCLK <= 1'b1;
CS_N <= 1'b1;
DIN <= 1'b1;
end
else if(en) begin
case(SCLK_CNT)
6'd0:begin CS_N <= 1'b0; end
6'd1:begin SCLK <= 1'b0;DIN <= 1'b0; end
6'd2:begin SCLK <= 1'b1; end
6'd3:begin SCLK <= 1'b0; end
6'd4:begin SCLK <= 1'b1; end
6'd5:begin SCLK <= 1'b0; DIN <= r_channel[2];end
6'd6:begin SCLK <= 1'b1; end
6'd7:begin SCLK <= 1'b0; DIN <= r_channel[1];end
6'd8:begin SCLK <= 1'b1; end
6'd9:begin SCLK <= 1'b0; DIN <= r_channel[0];end
6'd10,6'd12,6'd14,6'd16,6'd18,6'd20,6d'22,6d'24,6'd26,6'd28,6'd30,6'd32:
begin SCLK <= 1'b1; r_data <= {r_data[10:0], DOUT}; end
6'd11,6'd13,6'd15,6'd17,6'd19,6'd21,6d'23,6d'25,6'd27,6'd29,6'd31,6'd33:
begin SCLK <= 1'b0;end
6'd33:begin CS_N <= 1'b1;end
default: begin CS_N <= 1'b1;end
endcase
end
else begin
SCLK <= 1'b1;
CS_N <= 1'b1;
DIN <= 1'b1;
end
end
// done 信号
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
done <= 1'b0;
else if(SCLK_CNT == 'd33)
done <= 1'b1;
else
done <= 1'b0;
end
// data 信号
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
data <= 'd0;
else if(SCLK_CNT == 'd33)
data <= r_data;
else
data <= data;
end
endmodule
`timescale 1ns/1ns
module SPI_tb;
reg clk;
reg rst_n;
reg start;
reg [2:0] channel;
wire SCLK;
DIN;
CS_N;
DOUT;
wire done;
wire [11:0]data;
SPI SPI_inst(
.clk(clk),
.rst_n(rst_n),
.start(start),
.channel(channel),
.SCLK(SCLK),
.DIN(DIN),
.CS_N(CS_N),
.DOUT(DOUT),
.done(done),
.data(data)
);
initial clk = 1'b1;
alwayss#10 clk = ~clk;
initial begin
rst_n = 1'b0;
channel = 'd0;
start = 1'b0;
DOUT = 1'b0;
end
endmodule
SPI是微控制器和外围IC 如传感器 adc 和dac 移位寄存器、SRAM等。之间使用最广泛的接口之一。SPI是一种同步、全双工、主从式接口。来自主机或从机的数据在时钟上升沿或下降沿同步。主机和从机可以同时传输数据。SPI接口可以是三线式或四线。
CS 低电平有效
SPI的环形数据收发模式,SPI在收发数据的原理很简单,就是两个移位寄存器,待发送的数据首先写入din_buf 中缓存,需要发送的时候输入进data_shift 中,通过移位的方式发送高位数据,同时接受到的数据存入低位,写满时存入到dout_buf 中,再由dout_buf 写入内部总线。
代码放到:https://download.csdn.net/download/qq_30093417/86757879