基于FPGA的信号发生器的设计

基于FPGA的信号发生器的设计

首先先要介绍的是本设计的主芯片是ALTERA的一款芯片,芯片名称是EP2C5T144C8N。该芯片的LE单元有4608个,PLL锁相环具有2个,IO口管脚具有142个,差分通道55个,嵌入式乘法器26个,RAM的存储容量大小是119808bits.该FPGA芯片的功耗也比较低。对于信号发生器的设计,不论芯片的类型,只要所设计的逻辑单元够用即可,还有就是内存要够。好了,话不多说。直接来开始FPGA的信号发生器设计吧。

我当时用的是Quartus-II是13.0的版本作为开发环境,设计的通信方式是最常见的SPI通信方式,该方式通信比较简单。当时我为了调这个通信的时序也花了一天时间才搞定,哎!自认为还是比较笨了。

直接上图:

基于FPGA的信号发生器的设计_第1张图片

    该图是quartus的开发环境,大家看下,感觉和你们的也不会有太大的区别。尽管软件的版本一直在升级,可是感觉变化也不会太大。

    继续上图:

基于FPGA的信号发生器的设计_第2张图片

    这个是我所建立的文件,大概看了一下,其中.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是和频率有关的参数,可以先进行求解:

根据要求可以列出以下不等式:

基于FPGA的信号发生器的设计_第3张图片

基于FPGA的信号发生器的设计_第4张图片

基于FPGA的信号发生器的设计_第5张图片

基于FPGA的信号发生器的设计_第6张图片


好了,我们继续:

module div_clk

#(

parameter div =2//设置分频系数

)

(

input clk,

output signal_clk

);

/*reg [8:0] flag;

reg clk_flag;

/*always @(posedge clk)

begin

flag<=flag+1'd1;

if(flag==div)

         begin

         clk_flag<=~clk_flag;

         flag<=0;

         end

end*/

assign signal_clk=clk;

endmodule

这个是用来提供时钟分频的,分频大小可以自行设置。这里的时钟主要是用来提供给DA芯片的时钟,我用的是50M的时钟所以就没有分频了。

基于FPGA的信号发生器的设计_第7张图片

这个是顶层文件的设计图。

下面来让我们看看仿真图:注意,仿真时只能是针对某个模块设计进行仿真,用软件仿真时,要用tesbench文件和一个.v的实例文件。硬件仿真时,主要是用到下载器里的逻辑分析仪对数据的抓取。

硬件仿真

基于FPGA的信号发生器的设计_第8张图片

这个是我之前仿真的时序,记录被保存了,现在拿出来,可以看到右上角有未连接硬件的显示提醒。

软件仿真时序:

基于FPGA的信号发生器的设计_第9张图片

在这里说以下,用外部modlsim仿真时,注意输入信号的时序要自己给出。如果对以上仿真软件不太会使用时可以自己百度以下,相信会有大把的视频或者论坛或者文本资料的,总有一款适合你的。好了,不过多介绍了。今天就到这里吧!

希望对你们有用!再多说一句,注意时序分析。

你可能感兴趣的:(硬件电路分析)