差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
任意波形产生 [2016/05/26 16:34] gongyu [代码实现] |
任意波形产生 [2020/10/09 01:31] (当前版本) gongyu |
||
---|---|---|---|
行 8: | 行 8: | ||
* 信号流程中的时序及各级时钟产生 | * 信号流程中的时序及各级时钟产生 | ||
* 通过[[示波器]]、[[频谱仪]]观察信号的构成及质量 | * 通过[[示波器]]、[[频谱仪]]观察信号的构成及质量 | ||
+ | |||
+ | {{drawio>simpledds}} | ||
====项目要求==== | ====项目要求==== | ||
{{ :stepfpga_dds.png |}} | {{ :stepfpga_dds.png |}} | ||
+ | <WRAP centeralign> **图1. 小脚丫FPGA同串行DAC构成的任意信号发生器** </WRAP> | ||
+ | |||
本项目采用[[http://www.analog.com|Analog Devices]]公司的8位串行DAC芯片[[http://www.analog.com/cn/search.html?q=ad5601|AD5601]],小脚丫FPGA模块通过SPI总线与AD5601连接,AD5601输出模拟信号,通过一个RC低通滤波器进行抗混叠滤波,得到最高频率为200KHz以内的信号。具体要求如下: | 本项目采用[[http://www.analog.com|Analog Devices]]公司的8位串行DAC芯片[[http://www.analog.com/cn/search.html?q=ad5601|AD5601]],小脚丫FPGA模块通过SPI总线与AD5601连接,AD5601输出模拟信号,通过一个RC低通滤波器进行抗混叠滤波,得到最高频率为200KHz以内的信号。具体要求如下: | ||
* 输入:5个按键,用于控制输出信号的波形以及频率选择 | * 输入:5个按键,用于控制输出信号的波形以及频率选择 | ||
行 28: | 行 32: | ||
* 采用LFCSP和SC70封装 | * 采用LFCSP和SC70封装 | ||
{{ :ad5601block.png |}} | {{ :ad5601block.png |}} | ||
+ | |||
+ | <WRAP centeralign>**图2 AD5601的内部功能框图** </WRAP> | ||
+ | |||
{{ :ad5601timing.png |}} | {{ :ad5601timing.png |}} | ||
+ | <WRAP centeralign> **图3 AD5601数据接口时序**</WRAP> | ||
===逻辑架构=== | ===逻辑架构=== | ||
{{ :dds_block.png |DDS的构成框图}} | {{ :dds_block.png |DDS的构成框图}} | ||
+ | <WRAP centeralign> **图4 DDS的构成框图**</WRAP> | ||
{{ :dds_spectrum.png |通过DDS产生的信号频谱}} | {{ :dds_spectrum.png |通过DDS产生的信号频谱}} | ||
+ | <WRAP centeralign> **图5 通过DDS产生的信号频谱**</WRAP> | ||
{{ :dds_antialias.png |DDS系统中的抗混叠滤波器的使用}} | {{ :dds_antialias.png |DDS系统中的抗混叠滤波器的使用}} | ||
+ | <WRAP centeralign> **图6 DDS系统中的抗混叠滤波器的使用**</WRAP> | ||
+ | |||
+ | **调试过程:**由于这是一个相对复杂的系统,我们采用分段实现的方式进行系统实现和分阶段调试: | ||
+ | - DAC产生直流电压:通过[[SPI]]串行总线的低速数模变换器[[DAC]]得到需要的直流电压,按键更改数字参数能够改变输出直流电压的值 | ||
+ | - DAC生成正弦波:通过[[FPGA]]内部寄存器或调用内部IP核将内嵌的块RAM配置成256深度,位宽为8位的[[ROM]]存储一个周期的正弦波波形信号,逻辑控制将波形表中的每个点通过DAC输出,生成模拟的正弦波信号 | ||
+ | - DAC生成任意波形,并且可以调整频率 | ||
===核心代码=== | ===核心代码=== | ||
行 41: | 行 57: | ||
* keyin.v: 按键输入控制,选择波形以及调整频率,需要防抖处理 | * keyin.v: 按键输入控制,选择波形以及调整频率,需要防抖处理 | ||
* dds.v: 根据频率控制字能够改变的相位累加器 | * dds.v: 根据频率控制字能够改变的相位累加器 | ||
- | * rom.v: Lattice Diamond软核构成的波表存储器,可以配置成宽度8位、深度256Byte的ROM,如果要存储多个波形方便切换,可以生成对应于不同波形的ROM文件 | + | * rom.v: [[Lattice Diamond]]系统自带软核构成的波表存储器,可以配置成宽度8位、深度256Byte的[[ROM]],如果要存储多个波形方便切换,可以生成对应于不同波形的ROM文件 |
* spidac.v: 通过SPI总线协议将ROM表中的数据串行发送給AD5601 | * spidac.v: 通过SPI总线协议将ROM表中的数据串行发送給AD5601 | ||
行 47: | 行 63: | ||
- | ===DAC MAX548的控制Verilog代码(近做参考)=== | + | ===通过SPI控制DAC的Verilog代码=== |
- | <code java> | + | 本参考代码是控制Max548 - 双通道8位串行DAC,其SPI接口模式和内部控制寄存器都不相同,但设计思路一致 |
- | module MAX548A (CLOCK, DAC_SCLK, DAC_DIN, DAC_CS, DAC_LD, DATA_BYTE_A, DATA_BYTE_B, RESET); | + | <code verilog> |
- | input CLOCK; // 96MHz system clock | + | module SPIDAC(CLOCK, DAC_SCLK, DAC_DIN, DAC_CS, DAC_LD, DATA_BYTE, RESET); |
- | input RESET; // system reset | + | input CLOCK; // 96MHz system clock |
- | input [7:0] DATA_BYTE_A,DATA_BYTE_B; // Data Byte Register | + | input RESET; // system reset |
+ | input [7:0] DATA_BYTE_A; // Data Byte Register | ||
output DAC_SCLK; // 6MHz Serial Clock | output DAC_SCLK; // 6MHz Serial Clock | ||
行 59: | 行 76: | ||
output DAC_LD; // DAC Load output | output DAC_LD; // DAC Load output | ||
- | // DAC input for 2 channels, data_reg is used for buffer 2 address and 2 data | + | // data_reg is used for buffer address and data |
- | reg [31:0] data_reg; | + | reg [15:0] data_reg; |
// Create 6MHz clock from system clock | // Create 6MHz clock from system clock | ||
行 66: | 行 83: | ||
wire clk6mhz; | wire clk6mhz; | ||
- | always @ (posedge CLOCK or posedge RESET) | + | always @(posedge CLOCK or posedge RESET) |
begin | begin | ||
if (RESET) | if (RESET) | ||
行 77: | 行 94: | ||
// Detect changing of control byte and data byte | // Detect changing of control byte and data byte | ||
- | reg [15:0] comp_reg; | + | reg [7:0] comp_reg; |
reg data_chg; | reg data_chg; | ||
行 84: | 行 101: | ||
if (RESET) {comp_reg, data_chg} <= 0; | if (RESET) {comp_reg, data_chg} <= 0; | ||
else begin | else begin | ||
- | comp_reg <= {DATA_BYTE_A, DATA_BYTE_B}; | + | comp_reg <= DATA_BYTE; |
- | if (comp_reg != {DATA_BYTE_A, DATA_BYTE_B}) data_chg <= 1; | + | if (comp_reg != DATA_BYTE) data_chg <= 1; |
else data_chg <= 0; | else data_chg <= 0; | ||
end | end | ||
行 91: | 行 108: | ||
// Shift data_reg | // Shift data_reg | ||
- | reg [5:0] cnt32; | + | reg [4:0] cnt16; |
reg DAC_CS; | reg DAC_CS; | ||
- | always @ (posedge clk6mhz or posedge RESET) | + | always @(posedge clk6mhz or posedge RESET) |
begin | begin | ||
if (RESET) begin | if (RESET) begin | ||
DAC_CS <= 1; | DAC_CS <= 1; | ||
- | cnt32 <= 0; | + | cnt16 <= 0; |
- | data_reg <={32'h0}; | + | data_reg <={16'h0}; |
end | end | ||
else if (data_chg) begin | else if (data_chg) begin | ||
DAC_CS <=0; | DAC_CS <=0; | ||
- | cnt32 <= 0; | + | cnt16 <= 0; |
- | data_reg <={8'h0a,DATA_BYTE_A,8'h09,DATA_BYTE_B}; | + | data_reg <={8'h0a,DATA_BYTE}; |
end | end | ||
else | else | ||
- | if(cnt32 < 31) begin | + | if(cnt16 < 15) begin |
- | cnt32 <= cnt32 + 1; | + | cnt16 <= cnt16 + 1; |
data_reg <= data_reg <<1; | data_reg <= data_reg <<1; | ||
end | end | ||
行 119: | 行 136: | ||
assign DAC_LD = 1'b1; | assign DAC_LD = 1'b1; | ||
- | assign DAC_DIN = data_reg[31]; | + | assign DAC_DIN = data_reg[15]; |
reg DAC_SCLK; | reg DAC_SCLK; | ||
- | always @ (negedge clk12mhz or posedge RESET) | + | always @(negedge clk12mhz or posedge RESET) |
begin | begin | ||
- | if (RESET) DAC_SCLK <= 0; | + | if (RESET) DAC_SCLK <= 0; |
else if (!DAC_CS) DAC_SCLK <= !DAC_SCLK ; | else if (!DAC_CS) DAC_SCLK <= !DAC_SCLK ; | ||
end | end | ||
endmodule | endmodule | ||
- | /* | ||
</code> | </code> | ||
====结果及资源报告==== | ====结果及资源报告==== | ||
- | |||
====参考资料==== | ====参考资料==== |