这个是我所建立的文件,大概看了一下,其中.v文件是我建立的一些verilog文件,有几个特殊的文件,比如.bdf文件是顶层文件。因为采用的思想是自顶向下的设计思想。先模块化,然后顶层直接调用即可。.qip文件是调用的是quatus自带的IP核,主要是用来存放波形数据的。.stp文件是signaltep文件,主要是用来硬件仿真观察数据用的,这个很有用哦,和modelsim差不多的功能,主要区别是,一个是硬件仿真,一个是软件仿真。都可以用来分析时序。
直接上代码:
module SPI_SLAVE
#(
parameterrom_len_width=9,//ROM标的深度,同时也代表了相位控制字的位数
parameterftw_width=21,//频率控制字的位数
parameter N=8
)
(
input rst, //复位端口
input [N-1:0] txdata, //N位发送数据,CS下降沿把数据存入模块
input sclk, //spi时钟
input cs, //spi片选
input mosi, //从接收端
input ftw_en, //频率输入控制端使能
input ptw_en, //相位控制端口使能
input clk, //频率>>sclk
output reg miso, //从输出端
output [ftw_width-1:0] ftw_out, //频率控制字的位数
output [rom_len_width-1:0] ptw_out//相位控制字输出
//output [5:0] count,//测试用
//output [23:0] data_temp_done //测试用
);
reg [9-1:0] temp_rx,temp_tx;
reg negedge_cs,temp_cs;
reg data_done;
reg [5:0] count_spi;
reg [24-1:0] data_temp;//24位数据暂存寄存器
reg [ftw_width-1:0] ftw_last;
reg [rom_len_width-1:0] ptw_last;
reg [4:0] i;
always @(negedge rst or posedge sclk)//mosi receive logic
begin
if(!rst)
begin
count_spi<=0;
temp_rx<=8'd0;
data_temp<=0;
ftw_last<=0;
ptw_last<=0;
i<=0;
end
else if(cs==0)
begin
case(i)
5'd0:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d1
end
5'd1:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d2
end
5'd2:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d3
end
5'd3:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d4
end
5'd4:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d5
end
5'd5:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d6
end
5'd6:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d7
end
5'd7:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d8
end
5'd8:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d9
end
5'd9:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d10
end
5'd10:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d11
end
5'd11:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d12
end
5'd12:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d13
end
5'd13:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d14
end
5'd14:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d15
end
5'd15:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d16
end
5'd16:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d17
end
5'd17:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d18
end
5'd18:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d19
end
5'd19:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d20
end
5'd20:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d21
end
5'd21:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d22
end
5'd22:
begin
data_temp[24-1:0]<={data_temp[24-2:0],mosi};//串行数据左移输入
i<=i+1'b1;//翻转到下一个状态5’d23
end
5'd23:
begin
data_temp[24-1:0]={data_temp[24-2:0],mosi};//串行数据左移输入
if(!ftw_en)
begin
ftw_last[21-1:0]<=data_temp[24-4:0];
data_temp<=24'd0;
end
else if(!ptw_en)
begin
ptw_last<=data_temp[8:0];
data_temp<=24'd0;
end
i<=0;//翻转到下一个状态5’d0
end
endcase
end
/*if(flag==0)
begin
count_spi<=0;
temp_rx<=8'd0;
data_temp<=0;
ftw_last<=0;
ptw_last<=0;
flag<=1;
end
else if(cs==0&&flag==1)
begin
count_spi<=count_spi+1'd1;
temp_rx[N-1:0]<={temp_rx[N-2:0],mosi};//串行数据左移输入
case(count_spi)
6'd8:
begin
data_temp[24-1:16]<=temp_rx[7:0];//高位在前
//temp_rx=0;
end
6'd16:
begin
data_temp[16-1:8]<=temp_rx[7:0];
//temp_rx=0;
end
6'd24:
begin
data_temp[7:0]<=temp_rx[7:0];
//temp_rx=0;
if(!ftw_en)
begin
ftw_last[21-1:0]<=data_temp[24-1:3];
data_temp<=24'd0;
count_spi<=0;
end
if(!ptw_en)
begin
ptw_last<=data_temp[8:0];
data_temp<=24'd0;
end
flag<=0;
end
endcase
end*/
end
/*always @(posedge clk)//cs negedge test
begin
if((cs==0)&&(temp_cs==1))
negedge_cs<=1;
else
negedge_cs<=0;
temp_cs<=cs;
end*/
/*always @(negedge sclk or posedge negedge_cs)//miso transmitlogic
begin
if(negedge_cs==1)
temp_tx<=txdata;
else
temp_tx[N-2:0]<=temp_tx[N-1:1];
miso<=temp_tx[0];
end*/
assign ftw_out=ftw_last;
assign ptw_out=ptw_last;
//assign count=count_spi;//测试用
//assign data_temp_done=data_temp;//测试用
Endmodule
上面的模块代码是用来完成SPI数据的接收,接收数据长度是24位的,这个可以根据自己的需要进行必要的调整。
module phase_accumulator
#(
parameterrom_len_width=9,//ROM标的深度
parameterphase_acc_width=26,//相位累加器的位数
parameterftw_width=21//频率控制字的位数
)
(
input rst,
input [ftw_width-1:0] ftw,
input [rom_len_width-1:0] ptw,
input clk,
output[rom_len_width-1:0] q
);
`define ptw_enable 1
`ifdef ptw_enable
reg [rom_len_width-1:0] phase;
reg [phase_acc_width-1:0] phase1;
always @(negedge rst or posedge clk)
begin
if(!rst)
begin
phase=1'd0;
phase1=1'd0;
end
else
begin
phase1<=phase1+ftw;
phase<=phase1[phase_acc_width-1:phase_acc_width-rom_len_width]+ptw;
end
end
`else
`endif
assign q = phase;
endmodule
这部分的模块是完成相位累加器的设计,采用的是当今比较流行的DDS设计原理,
输出的q是rom表的地址,该地址根据相位累加器的累加来驱动地址的递增。不同DDS的建议可以去看下DDS的设计原理。在此,我也不嫌麻烦,将它给贴出来给你们看看。如下:
令DDS时钟为,相位累加器位数为n,频率控制字的位数为m,ROM表的深度的位宽为D,相位控制字的位数为p。
再令,,。
当要设计一个DDS时,应该根据具体的性能指标来设计,从而避免不必要的资源浪费,一般设计给出的具体指标如下:
指标:频率分辨率为,相位分辨率为,要求产生信号的最高频率为,且最高相位为,每个周期点数不少于N个。
根据上面的指标,我们要求得具体的DDS时钟为,相位累加器位数为n,频率控制字的位数为m,ROM表的深度的位宽为d。
(1)其中、n、m是和频率有关的参数,可以先进行求解:
1 根据要求可以列出以下不等式:
好了,我们继续:
assign signal_clk=clk;
endmodule
下面来让我们看看仿真图:注意,仿真时只能是针对某个模块设计进行仿真,用软件仿真时,要用te***ench文件和一个.v的实例文件。硬件仿真时,主要是用到下载器里的逻辑分析仪对数据的抓取。
这个是我之前仿真的时序,记录被保存了,现在拿出来,可以看到右上角有未连接硬件的显示提醒。
希望对你们有用!再多说一句,注意时序分析。
`