十一、四通道幅频相可调DDS信号发生器

本文由山东大学研友袁卓贡献,特此感谢

实验目标

实现多通道可调信号发生器

实验平台

芯航线FPGA核心板、ADDA模块

实验现象

实现基于FPGA的多通道可调信号发生器,其中频率、相位以及幅值均可通过PC端串口发送数据对应调节,并可实现4路信号的同步。

实验原理及设计过程

经过前面小梅哥基础课程的学习,相信已经对FPGA的设计有了一定程度的了解,现在提出一个相对综合的工程应用来深入了解FPGA的设计思路以及工程思想等。

针对以上预期实验现象可以分析出最少需要DDS模块、TLC5620控制模块、串口接收模块以及控制模块。

DDS原理与实现

DDS(Direct Digital Synthesizer)即数字合成器,是一种新型的频率合成技术,具有相对带宽大,频率转换时间短、分辨率高和相位连续性好等优点。较容易实现频率、相位以及幅度的数控调制,广泛应用于通信领域。

DDS 的基本结构图如图1所示。

图1 DDS基本结构图

由图1可以看出,DDS主要由相位累加器、相位调制器、波形数据表以及 D/A 转换器构成。

其中相位累加器由 N位加法器与N位寄存器构成。每来一个时钟,加法器就将频率控制字与累加寄存器输出的相位数据相加,相加的结果又反馈至累加寄存器的数据输入端,以使加法器在下一个时钟脉冲的作用下继续与频率控制字相加。这样,相位累加器在时钟作用下,不断对频率控制字进行线性相位累加。即在每一个时钟脉冲输入时,相位累加器便把频率控制字累加一次。

相位累加器输出的数据就是合成信号的相位。相位累加器的溢出频率,就是 DDS输出的信号频率。用相位累加器输出的数据,作为波形存储器的相位采样地址,这样就可以把存储在波形存储器里的波形采样值经查表找出,完成相位到幅度的转换。波形存储器的输出送到 D/A 转换器,由 D/A 转换器将数字信号转换成模拟信号输出。

DDS信号流程示意图如图2所示。

图2 DDS原理流程图

这里相位累加器位数为N位(N的取值范围实际应用中一般为24~32),相当于把正弦信号在相位上的精度定义为N位,所以其分辨率为

若DDS的时钟频率为,频率控制字fword为 1,则输出频率为,这个频率相当于“基频”。若fword为 B,则输出频率为

因此理论上由以上三个参数就可以得出任意的输出频率。且可得出频率分辨率由时钟频率和累加器的位数决定。当参考时钟频率越高,累加器位数越高,输出频率分辨率就越高。

从上式分析可得,当系统输入时钟频率不变时,输出信号频率由频率控制字M所决定,由上式可得:。其中B为频率字且只能取整数。为了合理控制ROM的容量此处选取ROM查询的地址时,可以采用截断式,即只取32位累加器的高M位。这里相位寄存器输出的位数一般取10~16位。

在本设计中参考时钟频率为50 MHz,相位累加器位数N取32位,频率控制字位数M 取12位。

经过以上的分析,可以得出DDS模块的端口模块图如图3所示。

图3 DDS模块接口示意图

其中,每个端口的功能描述如表1所示。

表1 DDS模块功能描述

新建DDS_Module.v保存至rtl文件夹下。从图3以及表1就得到了端口列表:

    input Clk;input Rst_n;input EN;input [31:0]Fword;input [11:0]Pword;output DA_Clk;output [9:0]DA_Data;

以下只需按照图1进行编写。相位累加器此处即为一个32bit的加法器。

    reg [31:0]Fre_acc;  always @(posedge Clk or negedge Rst_n)if(!Rst_n)Fre_acc <= 32'd0;else if(!EN)Fre_acc <= 32'd0;   else Fre_acc <= Fre_acc + Fword;

查找表地址生成,此处即为12bit的加法器。这里直接截取32位累加器结果中的高12位作为ROM的查询地址,这样产生的误差会对频谱纯度有影响,但是对波形的精度的影响是可以忽略的。

    reg [11:0]Rom_Addr;always @(posedge Clk or negedge Rst_n)if(!Rst_n)Rom_Addr <= 12'd0;else if(!EN)Rom_Addr <= 12'd0;elseRom_Addr <= Fre_acc[31:20] + Pword; 

DA数据输出时钟模块使能,通过选择器来进行控制。

    assign DA_Clk = (EN)?Clk:1'b1;

现在只需要例化存有波形文件的ROM即可。其中单端口的ROM主要配置数据如图4所示,其初始化文件选为已经生成的正弦mif文件。此处mif位宽为10,深度为4096。

图4 ROM主要配置参数

这样例化到DDS_Module中即为如下内容。

    ddsrom ddsrom(.address(Rom_Addr),.clock(Clk),.q(DA_Data));

本模块编译无误后,点击RTL Viewer后可以看到如图5所示的模块逻辑电路图,可与DDS原理图对比。这里有两个选择器的原因是加了使能端的缘故,如果将使能端去掉即可看到如图6所示的电路图

图5 DDS模块设计逻辑电路图

图6 DDS模块简化逻辑电路图

设置此文件为顶层进行功能仿真。激励文件中除了产生正常的时钟以及模块例化调用,还需使能模块以及设置自加字。此处简化将Fword设置为固定值’d5000,。

initial beginRst_n = 1'b0;EN = 1'b0;Fword = 32'd0;Pword = 12'd0;
    #(`clk_period*20)Rst_n = 1'b1;#(`clk_period*20)EN = 1'b1;Fword = 32'd5000;
#(`clk_period*2000000)$stop;
end 

编译无误后设置好仿真脚本并进行仿真,可以看到如图7所示的功能仿真波形文件,可以看出波形数据正常。放大仿真开始位置,可以看出输出DA时钟使能设计也正常。初始值为’d511也就是’h1ff,与初始化mif文件一致。

图7 DDS模块功能仿真波形

图8 DDS模块部分放大波形文件

这样一个DDS模块即设计完成,这里可以自行修改Pword的值进行观察波形相位是否发生相应变化。

数模转换器(DAC)控制模块设计

这里采用DAC芯片为芯航线AD/DA模块上的TLC5620。其中TLC5620模块的设计与实现在基础课第17讲已经详细阐述,此处不再对本部分进行解释。其模块接口示意图9所示,其接口对应的功能描述如表2所示。

图9 DA模块端口接口示意图

表2 DA模块接口功能描述

多通道数据输出实现

本节需实现的是多通道的信号发生器。而此处的ADDA模块最多支持四通道,这里就要轮询控制各个通道并输入相应的控制字。将此模块命名为DAC_4CH,其模块接口示意图如图10所示。

图10 DAC通道选择模块接口示意图

其每个接口功能描述如表3所示。

表3 DAC通道选择模块接口功能描述

由以上表分析可知其端口列表如下:

    input Clk;input Rst_n;input [7:0]DATA_A,DATA_B,DATA_C,DATA_D;input [1:0]CH_SUM;  output TLC5620_CLK;     output TLC5620_DATA;    output TLC5620_LOAD;    output TLC5620_LDAC;

这里在调用TLC5620时,直接将其转换使能信号UpdateDone信号置1来简化控制。

    TLC5620_CTRL TLC5620_CTRL0(.Clk(Clk),.Rst_n(Rst_n),.UpdateReq(1'b1),
        .CtrlWord(CtrlWord),.UpdateDone(UpdateDone),.TLC5620_CLK(TLC5620_CLK),.TLC5620_DATA(TLC5620_DATA),.TLC5620_LOAD(TLC5620_LOAD),.TLC5620_LDAC(TLC5620_LDAC));

实现轮询,就是在时钟上升沿到来时,每当一次TLC5620转换完成后,就开始选通下一个通道。

    wire UpdateDone; always@(posedge Clk or negedge Rst_n)if(!Rst_n)Current_CH <= 0;else if(UpdateDone)beginif(Current_CH < CH_SUM)Current_CH <= Current_CH + 1'b1;elseCurrent_CH <= 0;endelseCurrent_CH <= Current_CH;

在选通对应通道后,DDS产生的数据只需给控制字即可。

reg [7:0]DATA;      always@(*)begincase(Current_CH)0: DATA = DATA_A;1: DATA = DATA_B;2: DATA = DATA_C;3: DATA = DATA_D;default:DATA = DATA_A;endcase end

由基础课程可知TLC5620控制字的构成是两位的通道选择字、电压增益选择字以及八位数据位。因此直接采取位拼接方式即可。

wire [10:0]CtrlWord;  assign CtrlWord = {Current_CH,1'b0,DATA};

串口命令接收与解析

这里使用的串口接收模块波特率为9600,具体实现方式在基础课程的第12讲已经阐述,此处不再详细解释。其模块接口示意图如图11所示,接口对应功能描述如表4所示。

图11 串口接收模块接口示意图

表4 串口接收模块接口功能描述

信号发生器之自定义帧

由前面的实验目的可知,要实现利用串口来控制波形的参数。一般来讲当然可以通过一次发送一个数据来进行控制,但是由于这里需要的数据量太多因而这不是一个很好的解决办法。

在通信行业,存在各种符合一定标准的通信协议,里面会定义数据传输的帧格式以及时许要求。有时候也会有自己定义的一些数据帧格式。

这里采用自定义帧的方式来进行数据传输。其中串口发送数据的格式如表5所示。其中一帧数据为8个字节,整体数据由帧头+地址+数据+帧尾的格式组成。这样就可以实现对固定的寄存器地址写入不同的数据。

表5 自定义帧数据格式

不同的寄存器地址对应不同通道的不同的被控制数。系统设计了12个实体寄存器分别存储每个通道的相关控制参数。12个寄存器分为4组,分别对应了4个通道。每组包含3个寄存器,频率控制字寄存器,相位控制字寄存器以及幅度控制字寄存器。具体的各实体控制寄存器地址与对应功能如表6所示。当想控制某个通道的信号参数时,直接写实体寄存器,数据就会立即更新的控制参数到对应通道上

表6 实体寄存器地址与功能对应表

现在举例说明如何使用实体寄存器控制对应控制字。

1.使用实体寄存器控制某通道信号频率:

例如:设置通道0的频率为100Hz

地址:0x10

控制字:

8590换算成16进制就是0x218E。因此数据段为8E 21 00 00

这样最终发送的指令为:

2.使用实体寄存器控制某通道信号相位:

例如:设置通道1的相位为90度

地址:0x15

控制字:

1024换算成16进制就是0x400。因此数据段为00 04 00 00

这样最终发送的指令为:

3.使用实体寄存器控制某通道信号幅度:

系统设置支持8级信号幅度调节,此8级幅度的信号控制字与满幅的对应关系如下表7所示。

表7 控制字与幅度关系

需要注意的是,虽然系统设计支持8级调幅,然而缩减越大,则信号失真越严重,实际有效的缩减建议不超过1/8。

例如:设置通道2的幅度为半幅

地址:0x1a

控制字:01 因此数据段为01 00 00 00

这样最终发送的指令为

另外,为了实现同时控制所有通道同时更新,特为以上所有实体寄存器设置了影子寄存器。当需要设置某通道的数据,但并不立即执行时,可使用影子寄存器功能。影子寄存器会预先存储所有的设置数据,但并不立即更新到每个模块,而是在发出更新指令后,系统同时更新所有的通道。在操作时只需要先将要更新的数据逐次写入每个通道需要更新的寄存器中的影子寄存器中,然后发出更新指令,则系统会自动将影子寄存器中的数据同时更到实体寄存器。更新指令由更新寄存器完成,更新寄存器是一个特殊的寄存器,占一个地址,对该地址写任意数据都能执行更新影子寄存器中的数据到对应实体寄存器中。影子寄存器地址、名称与功能对应表如表8所示。

表8 影子寄存器名称与功能对应表

更新寄存器以及通道控制地址与功能对应关系,如表9所示

表9 更新寄存器以及通道控制地址与功能对应表

在使用影子寄存器更新多个通道多个寄存器的操作顺序如下:

1. 写一个或多个通道中一个或多个影子寄存器的值

2. 发出更新指令

例如,需要设置通道0的频率为100Hz,相位为90度,幅度为满幅、设置通道1的频率为100Hz,相位为180度,幅度为半幅。则可按照如下指令顺序进行发送:

1. AA 03 00 8E 21 00 00 88 (设置通道0的频率为100Hz)

2. AA 03 04 00 04 00 00 88 (设置通道0的相位为90度)

3. AA 03 08 00 00 00 00 88 (设置通道0的幅度为满幅)

4. AA 03 01 8E 21 00 00 88 (设置通道1的频率为100Hz)

5. AA 03 05 00 08 00 00 88 (设置通道1的相位为180度)

6. AA 03 09 01 00 00 00 88 (设置通道1的幅度为半幅)

7. AA 03 0d 00 00 00 00 88 (更新所有影子寄存器中的数据到实体寄存器)

地址0c为控制4个通道的运行和停止的寄存器。该寄存器占4位,每一位对应一个通道的开关。当需要同步某几个通道时,也可使用这个寄存器来实现,实现方式为首先设置这几个通道的寄存器对应的控制位为0,然后重新设置这几个通道的寄存器位为1,即可实现同步。

串口数据帧接收

使用前面定义的数据帧格式,就需要一次发送多个字节的数据,这样就不排除多个字节发送错误或者多发、少发。因此就需要除了判断每一帧中的数据个数以及帧头、帧尾与定义一致以外还需检查每一字节数据间隔,是否间隔太久,如果间隔太久就说明这帧数据结束。

这里新建uart_rx_frameend.v,来进行帧格式判断。其模块接口示意图如图12所示。

图12 帧判断模块接口示意图

帧判断模块的接口功能描述如表10所示。

表10 帧判断模块接口功能描述

为了实现对一帧数据的判断,首先产生内部参考时钟。这里为了扩展模块的使用范围,增加了mode信号来选择参考时钟是内部产生的1K频率还是其他频率。此处的频率需要根据数据的传输速率进行相对应设置。

    reg [15:0]internal_base_cnt;reg internal_base_clk;wire base_clk;always@(posedge Clk or negedge Rst_n)if(!Rst_n)internal_base_cnt <= 16'd0;else if(internal_base_cnt == 49_999)internal_base_cnt <= 16'd0;elseinternal_base_cnt <= internal_base_cnt + 1'd1;assign base_clk = mode?clk_cnt_base:internal_base_clk;always@(posedge Clk or negedge Rst_n)if(!Rst_n)internal_base_clk <= 1'd0;else if(internal_base_cnt == 49_999)internal_base_clk <= 1'd1;elseinternal_base_clk <= 1'd0; 

串口数据标志接收部分,每当接收到一字节的数据后均会产生一个时钟周期的高电平标志信号。此处以cnt_state为标志来定义状态进而使能计数器。每当接收到1字节数据即开始计数,当帧超时则停止计数。

    always@(posedge Clk or negedge Rst_n)if(!Rst_n)cnt_state <= 1'b0;else if(Rx_int)cnt_state <= 1'd1;else if(frameend)cnt_state <= 1'b0;

计数器使能时每当到来一个参考时钟就将计数器加一。当接收到新的字节数据时或者当达到预设的帧结束判定时间就将计数器清零。且当到达帧结束判定时间时产生一帧数据接收完成标志信号。

    always@(posedge Clk or negedge Rst_n)if(!Rst_n)cnt <= 16'd0;else if(Rx_int || (base_clk && (cnt == endtimeset)))cnt <= 16'd0;else if(base_clk && cnt_state)cnt <= cnt + 16'd1;        always@(posedge Clk or negedge Rst_n)if(!Rst_n)frameend <= 1'b0;else if(base_clk && (cnt == endtimeset))frameend <= 1'b1;elseframeend <= 1'b0;

为了简化测试激励,这里先使用外部时钟进行功能仿真。因此在激励文件中例化待测试文件如下所示。

    uart_rx_frameend uart_rx_frameend(.Clk(Clk),.Rst_n(Rst_n),.clk_cnt_base(clk_cnt_base),    .mode(1),.Rx_int(Rx_int),    .endtimeset(endtimeset), .frameend(frameend) );

激励文件中除产生正常的系统时钟50MHz以外,还产生了4.5MHz的外部时钟。

    initial clk_cnt_base = 0;always beginclk_cnt_base = 1;#20;clk_cnt_base = 0;#200;end

循环产生接收到的数据标志信号36次,且最后一个个延迟足够长的时间。这里也就是用时钟clk_cnt_base计数20以上即可(大约5000ns)。

    integer i;initial beginRst_n = 0;endtimeset = 19;Rx_int = 0;#201;Rst_n = 1;#200;for(i=0;i<36;i=i+1)beginRx_int = 1;#20;Rx_int = 0;#2000;end#200000;for(i=0;i<36;i=i+1)beginRx_int = 1;#20;Rx_int = 0;#2000;end#200000;$stop;    end

设置好仿真脚本以后,开始运行,大致在图13-1可以看出Rx_int信号产生正常,且计数使能信号正常,在一次帧数据传输结束后经过一定时间后frameend有一个标志信号。现在放大部分数据,在图13-2查看此时的cnt信号可以看出 19时产生信号,符合预期设计。

图13-1 帧判断模块功能仿真波形

图13-2 帧判断模块部分波形

串口数据解析

由上面自定义了数据格式,总共为8个8位数据,因此先用移位寄存器把八个数据移入进来。串口数据解析模块接口示意图如图14所示。

图14 CMD模块接口示意图

因此其端口名称及功能描述如表11所示。

表9 模块接口及功能描述

首先利用移位寄存器将接收到的数据放到一个寄存器中。这里定义了一个清零端,其作用是在一帧数据接收完成后将计数器以及移位寄存器数据清零。

    reg [63:0]shift_data;reg clr;always@(posedge Clk or negedge Rst_n)if(!Rst_n)shift_data <= 64'd0;else if(clr)shift_data <= 64'd0;else if(Rx_Int)shift_data <= {Rx_Byte,shift_data[63:8]};

对接收到的数据个数进行计数,直到产生清零信号。

    reg [3:0]data_cnt;always@(posedge Clk or negedge Rst_n)if(!Rst_n)data_cnt <= 4'd0;else if(clr)data_cnt <= 4'd0;else if(Rx_Int)data_cnt <= data_cnt + 1'b1;

进行数据接收解析,即把对应位送给对应的控制字。

    always@(posedge Clk or negedge Rst_n)if(!Rst_n)begin Fword0 <= 0; Fword1 <= 0; Fword2 <= 0; Fword3 <= 0;     Pword0 <= 0; Pword1 <= 0; Pword2 <= 0; Pword3 <= 0;Aword0 <= 0; Aword1 <= 0; Aword2 <= 0; Aword3 <= 0;s_Fword0 <= 0; s_Fword1 <= 0; s_Fword2 <= 0; s_Fword3 <= 0;s_Pword0 <= 0; s_Pword1 <= 0; s_Pword2 <= 0; s_Pword3 <= 0;s_Aword0 <= 0; s_Aword1 <= 0; s_Aword2 <= 0; s_Aword3 <= 0;CH_Sync <= 4'b0000;clr <= 1'b0;
end
else if(frameend)begin
。。。。。。。。。。。。。。。endelseclr <= 1'b0;       

每当frameend变为高电平,即代表一次数据传输结束。注意此处一次数据传输结束,可能是正常的一帧数据,也可能是不正常的数据接收。这样就需要对此次接受的数据进行判断是否为正常的一帧数据。这里定义的正常一帧数据如表5所示,数据个数为8且帧头为’haa、’h03,帧尾分别为’h88。这样判断正确后才认为是正常的数据,这样即可以根据寄存器地址来进行相对应的操作。一次传输结束后就将计数器清零等待下一次传输。

    else if(frameend)beginclr <= 1'b1;if(data_cnt == 8 && shift_data[7:0] == Header0 && shift_data[15:8] == Header1 && shift_data[63:56] == Tail)begincase(shift_data[23:16])8'h10:Fword0 <= shift_data[55:24];8'h11:Fword1 <= shift_data[55:24];8'h12:Fword2 <= shift_data[55:24];8'h13:Fword3 <= shift_data[55:24];8'h14:Pword0 <= shift_data[35:24];8'h15:Pword1 <= shift_data[35:24];8'h16:Pword2 <= shift_data[35:24];8'h17:Pword3 <= shift_data[35:24];8'h18:Aword0 <= shift_data[27:24];8'h19:Aword1 <= shift_data[27:24];8'h1a:Aword2 <= shift_data[27:24];8'h1b:Aword3 <= shift_data[27:24];8'h00:s_Fword0 <= shift_data[55:24];8'h01:s_Fword1 <= shift_data[55:24];8'h02:s_Fword2 <= shift_data[55:24];8'h03:s_Fword3 <= shift_data[55:24];8'h04:s_Pword0 <= shift_data[35:24];8'h05:s_Pword1 <= shift_data[35:24];8'h06:s_Pword2 <= shift_data[35:24];8'h07:s_Pword3 <= shift_data[35:24];8'h08:s_Aword0 <= shift_data[27:24];8'h09:s_Aword1 <= shift_data[27:24];8'h0a:s_Aword2 <= shift_data[27:24];8'h0b:s_Aword3 <= shift_data[27:24];8'h0c:CH_Sync <= shift_data[27:24];8'h0d:begin             Fword0 <= s_Fword0;  Fword1 <= s_Fword1;Fword2 <= s_Fword2;  Fword3 <= s_Fword3;Pword0 <= s_Pword0;  Pword1 <= s_Pword1;Pword2 <= s_Pword2;  Pword3 <= s_Pword3;Aword0 <= s_Aword0;  Aword1 <= s_Aword1;Aword2 <= s_Aword2;  Aword3 <= s_Aword3;             enddefault:;endcaseendend

在调用写好的一次数据传输结束模块时,使用内部的1K时钟,且将帧结束判定时间设置为9。这里的时钟速度选择以及判定时间设置需根据不同的情况采用不同的设置。

    uart_rx_frameend uart_rx_frameend(.Clk(Clk),.Rst_n(Rst_n),.clk_cnt_base(1'b0),    .mode(1'b0),
        .Rx_int(Rx_Int),    .endtimeset(4'd9),
        .frameend(frameend));

由待测试文件可以看出如果产生帧结束标志信号会至少经过9/1000s,这里激励文件发送一次正常的数据为AA 03 10 8E 21 00 00 88然后延时0.01s,这样0.01s大于0.009s,再发送83 00数据后再延迟0.01s。具体实现如下所示。这里也故意使每一次数据持续时间不同。

    initial beginRst_n = 1'b0;Rx_Byte = 8'd0;Rx_Int = 1'b0;#(`clk_period*20 + 1 )Rst_n = 1'b1;
        #(`clk_period*50);Rx_Byte = 8'haa;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*5000);Rx_Byte = 8'h03;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*1500);Rx_Byte = 8'h10;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500);Rx_Byte = 8'h8e;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500);Rx_Byte = 8'h21;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500);Rx_Byte = 8'h00;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500);Rx_Byte = 8'h00;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500);Rx_Byte = 8'h88;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500000);//  #(`clk_period*1000);Rx_Byte = 8'h83;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*15000);Rx_Byte = 8'h00;
        #`clk_period;Rx_Int = 1'b1;
        #`clk_period;Rx_Int = 1'd0;
        #(`clk_period*500000);$stop;  end

编译无误后设置好仿真脚本,可以看到如图15所示的现象,每当接收一个字节数据时Rx_Int信号均会有一个系统周期的高电平,且数据计数器cnt能够正常的自加及清零。8byte数据接收过程中移位寄存器shift_data工作正常,且当完成后会控制字Fword0操作正常。当一帧数据接收完成后,再次发送一字节数据时cnt又开始重新计数。

图15 串口接收即命令解析模块功能仿真波形

如果想看到一次数据发送中data_cnt以及shift_data细节,则可以增加base_clk频率以及修改计数器,可以看到如图16的结果,可以自行分析。这里修改频率的同时也修改了计数器值,从仿真波形中看出同样可以进行帧结束位的判定。

图16 模块部分仿真波形

信号发生器顶层设计

综合以上的分析,可以得出其中模块顶层如下图17所示。将内部信号全部定义为wire即可,其接口功能描述如表10所示。

图18 顶层模块接口示意图

表10 顶层模块接口及功能描述

其输入输出端口定义如下所示。

    input Clk;input Rst_n;input Rs232_Rx;output TLC5620_CLK;output TLC5620_DATA;output TLC5620_LOAD;output TLC5620_LDAC;

将DA通道全部选通,并进行幅度调制的运算。

 wire [2:0]CH_SUM;    assign CH_SUM = 4-1;wire [3:0]Aword0,Aword1,Aword2,Aword3;  wire [9:0]DA_Data0,DA_Data1,DA_Data2,DA_Data3;
wire [7:0]DATA_A,DATA_B,DATA_C,DATA_D; assign DATA_A = DA_Data0[9:2] >> Aword0;assign DATA_B = DA_Data1[9:2] >> Aword1;assign DATA_C = DA_Data2[9:2] >> Aword2;assign DATA_D = DA_Data3[9:2] >> Aword3;

根据实际使用情况将各个模块例化进来,例化后的顶层应为如图19所示。

图19 顶层文件RTL Viewer视图

如有更多问题,欢迎加入芯航线 FPGA 技术支持群交流学习:472607506

小梅哥

芯航线电子工作室

关于学习资料,小梅哥系列所有能够开放的资料和更新(包括视频教程,程序代码,教程文档,工具软件,开发板资料)都会发布在我的云分享。(记得订阅)链接:http://yun.baidu.com/share/home?uk=402885837&view=share#category/type=0

赠送芯航线AC6102型开发板配套资料预览版下载链接:链接:http://pan.baidu.com/s/1slW2Ojj 密码:9fn3

赠送SOPC公开课链接和FPGA进阶视频教程。链接:http://pan.baidu.com/s/1bEzaFW 密码:rsyh

转载于:https://www.cnblogs.com/xiaomeige/p/6418761.html

【小梅哥FPGA进阶教程】第十一章 四通道幅频相可调DDS信号发生器相关推荐

  1. 【小梅哥FPGA进阶教程】第九章 基于串口猎人软件的串口示波器

    九.基于串口猎人软件的串口示波器 1.实验介绍 本实验,为芯航线开发板的综合实验,该实验利用芯航线开发板上的ADC.独立按键.UART等外设,搭建了一个具备丰富功能的数据采集卡,芯航线开发板负责进行数 ...

  2. 基于FPGA的波、幅、频、相可调DDS信号发生器的设计

    声明:本文只对设计原理和过程作粗略的阐述,详细可以研究我贴出来的完整源代码,也可以私信交流. 若干略缩语解释: FPGA(Field Programmable Gate Array):现场可编程逻辑门 ...

  3. 小梅哥FPGA:基于线性序列机的TLC5620型DAC驱动设计

    小梅哥FPGA:基于线性序列机的TLC5620型DAC驱动设计 目标:学会使用线性序列机的思想设计常见的有串行执行特征的时序逻辑 实验现象:在QuartusⅡ软件中,使用ISSP工具,输入希望输出的电 ...

  4. 小梅哥FPGA学习笔记

    小梅哥FPGA学习笔记 一.38译码器 功能: 译码器其任一时刻的稳态输出,仅仅与该时刻的输入变量的取值有关,它是一种多输入多输出的组合逻辑电路,负责将二进制代码翻译为特定的对象(如逻辑电平等).38 ...

  5. 2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(二) controller

    原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第二十一章-授予身份与切换身份(二) 1.回顾 ...

  6. 小梅哥FPGA时序分析和约束实例演练课程

    看过了他的nios课程,对他的能力很认同 只有前5讲是开源的,后面需要在淘宝上购买,暂时用不到,我就没有买课程,只看了前5讲感觉还挺有用,需要的时候再说吧. 小梅哥 FPGA时序分析 FPGA时序约束 ...

  7. 小梅哥FPGA视频教程学习总结(持续学习中……)

    首先附上小梅哥FPGA视频教程链接:https://www.bilibili.com/video/BV1va411c7Dz?p=2&spm_id_from=pageDriver 小梅哥yyds ...

  8. 小梅哥FPGA:嵌入式块RAM使用之FIFO

    小梅哥FPGA:嵌入式块RAM使用之FIFO 课程目标:学会调用QuartusⅡ软件中提供的FIFO核并通过仿真,了解其接口时序 实现现象:通过QuartusⅡ软件中调用FIFO核,通过仿真来验证其接 ...

  9. 学习小梅哥FPGA培训视频第一天

    ** 学习小梅哥FPGA培训视频第一天 ** 学习实现计数器 利用quartus II 编写代码并仿真 仿真为前仿真和后仿真 这是前仿真 这是后仿真 在后仿真中,会有毛刺的出现,例如在 1(0001) ...

最新文章

  1. [Go]在vscode中添加对模板文件tmpl的html语法自动补全的支持
  2. [转] vuewebpack多页面配置
  3. nat端口限制_Cisco ASA 防火墙 NAT - 基本概念
  4. 了解CUDA计算(一)
  5. linux安装zookeeper+使用命令
  6. 【前缀和笔记】前缀和介绍和使用
  7. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_5_File类获取功能的方法...
  8. 计算机用户名不显示,Windows10中设置不显示最后用户名的方法
  9. Pascal语言学习手册 Inno Setup 学习资料大全
  10. java实现表白动图
  11. 【学数据结构】-----串(顺序串、堆串、块链串)(7000字总结+代码+图)
  12. 自建微信公众号文章搜索舆情系统
  13. 常用MAVROS话题和服务
  14. java基本数据类型长度
  15. 学习笔记-主成分分析法
  16. FTD vs FMC
  17. UG模具设计之汽车特斯拉车灯与后备箱规律边境构建技巧
  18. 想要专升本你不得不看的全干货_吐血整理_专升本_计算机文化基础(一)
  19. Unable to load Maven meta-data from xxx com/github/chrisbanes/photoview/
  20. 陳三甲网络笔记:抖音赚钱记,我被割韭菜的经历!

热门文章

  1. iphone备份失败_在由第三方修理您的iPhone之前,请三思而后行(如果这样做,请备份它)...
  2. 【微信小程序】框架wxml(六)wxml引用
  3. RMAN备份概念_关于备份保留策略(RETENTION POLICY)
  4. springboot项目中自定义注解的使用总结、java自定义注解实战(常用注解DEMO)
  5. 如何对wps流程图进行重命名,如何对wps流程图进行重命名,wps进入修订模式,wps怎么在尾部加公式标号英文论文格式要求及字体大小
  6. 一次协作多端同步,打通看云、github互相同步(serverless实践)
  7. VoIP通话之DTMF信号开发指南
  8. 【数据结构】如何高贵优雅地理解什么是数据结构?
  9. oppoa5系统服务器是什么,oppoa52是什么处理器
  10. 最新版图书馆招聘考试常考试题重点事业单位