DSP

DDS与并行ADC、DAC

2019-07-13 18:41发布

总任务: 用DDS合成信号,经过DAC输出,用ADC采集信号。 使用Signal TAP在时域观察信号 使用 Matlab 在频域观察信号   操作过程:   一.生成分频和倍频锁相环  
  1. 创建一个Megafunction。此在tools/MegaWizard Plug- In Manager,默认选第一项,点Next。
  2)创建PLL。注意以下四点: 1.左侧选择元件类型: I/O选项下ALTPLL 2.右上方选择FPGA系列; 3.为生成的PLL选择语言,在AHDL,VHDL,Verilog中选择,(在此选择Verilog); 4.为元件命名,此处命名为“pll_DAC_ADC”,在地址栏最后把名字加上去即可,如下:“D:FPGAprojectsfpga_sdr_lab_dds_dac_adclab_dds_dac_adcproject_q72pll_DAC_ADC" 效果图如下:   (3)定义PLL。根据自己开发板的时钟信号填写输入,如我的输入时钟是50M,如下图:   接下来将下面的选择框全部取消勾选,如下图: 然后一路next… …   (4)直到进行到定义的关键环节。clock multiplication factor是倍频,clock division factor是分频,在这里选择不同的数值,就会输出不同的分频和倍频的数值。注意系数上限和频率上限,但如果配置不正确,系统会有提示,所以不必太担心。按照设计要求,我们需要一个80M和20M的时钟,配置如下图:     (5)finish 之后,在左侧工程和文件的目录下调出PLL的.v文件,生成symbol即可。   成过程还可参考新浪博客 《FPGA学习笔记之嵌入式锁相环模块ALTPLL的配置和调用》http://blog.sina.com.cn/s/blog_b351f3660102w2t7.html   二.DDS发生器 理论部分可适量参考《FPGA学习笔记之DDS》,便于理解。网址如下:https://www.cnblogs.com/zhouzheng/p/5793073.html   (1)DDS发生器的module代码如下: // mc_dds // multi-cycle dds module module mc_dds(   CLK   ,   // clock posedge   RST   ,   // reset posedge   FREQIN,   // input frequency word   FREQEN,   // frequency word input enable   DDSEN ,   // multi-cycle dds work enable   OUTVD ,   // dds output valid   DDSOUT);  // dds  output wave   input           CLK   ; input           RST   ; input  [32-1:0] FREQIN; input           FREQEN; input           DDSEN ; output          OUTVD ; output [7  :0]  DDSOUT;   // work enable delay line reg ddsen_R1, ddsen_R2, ddsen_R3;   reg  [32-1:0]  freqin_R     ; reg  [32-1:0]  phase_acc_R  ; reg   [8-1:0]  DDSOUT       ; wire  [8-1:0]  rom_rdW      ;   // rom read data wire  [7-1:0]  rom_raW      ;   // rom read address   always @ (posedge CLK or posedge RST) begin   if(RST) begin     ddsen_R1 <= 1'b0;     ddsen_R2 <= 1'b0;     ddsen_R3 <= 1'b0;   end   else begin     ddsen_R1 <= DDSEN   ;     ddsen_R2 <= ddsen_R1;     ddsen_R3 <= ddsen_R2;   end end assign OUTVD = ddsen_R3;     // dds working pipeline //                                       OUTVD   // DDSEN    | ddsen_R1     |ddsen_R2    |ddsen_R3    //          | phase_acc_R  | //          | rom_raW      | rom_rdW    | DDSOUT always @ (posedge CLK or posedge RST) begin   if(RST) begin     phase_acc_R <= 0;     freqin_R    <= 0;   end   else begin     if(FREQEN) begin       freqin_R <= FREQIN;     end // if(FREQEN)     if(DDSEN) begin       phase_acc_R <= phase_acc_R + freqin_R;     end // if(DDSEN)     if(ddsen_R2) begin       DDSOUT <= rom_rdW;     end   end end assign rom_raW = phase_acc_R[32-1: 32-1-7+1];   sine_rom U_sine_rom(   .CLK    (CLK        ),  // clock   .RA     (rom_raW    ),  // read address   .RD     (rom_rdW    )); // read data   endmodule //  mc_dds();   (关于rommodule指路上一篇博客。主要就是在正弦波上取128等分点,可用matlab计算得到。语句为:x=linspace(0,2*pi,128);  y=128*sin(x)
  1. DDS的RTL Viewer 如下:
sine_rom U_sine_rom的内部RTL Viewer 如下:
  1. DDS线路图连线
如图所示,1~8路开关控制发生信号频率(第23~30位),经过DDS信号发生器输出信号。具体原理见参考链接。 三.DAC接口模块 (1)DAC接口module代码如下: //////////////////// DAC 接口模块 转换2补码为无符号数 ///////////////////////// // input is signed , output is unsigned module DAC_interface(   CLKIN   ,   //  input clk   DATIN   ,   //  input data   SCALE   ,   //  scale factor, right shift the data   DAT2DAC );   //  data to dac     input           CLKIN; input  [8-1:0]  DATIN   ; input  [2-1:0]  SCALE   ; output [12-1:0] DAT2DAC ;     reg [12-1:0]  DAT2DAC ; reg [12-1:0]  datin_R1;   always @ (posedge CLKIN) begin   datin_R1 [11]    <= ~ DATIN[7]; // inverse the msb to unsigned   datin_R1 [10: 4] <= DATIN[6:0];   datin_R1 [3 : 0] <= 0;   DAT2DAC          <= (datin_R1 >> SCALE); end     endmodule (2)原理解释: 关于: always @ (posedge CLKIN) begin   datin_R1 [11]    <= ~ DATIN[7]; // inverse the msb to unsigned   datin_R1 [10: 4] <= DATIN[6:0];   datin_R1 [3 : 0] <= 0;   DAT2DAC          <= (datin_R1 >> SCALE); end 这几行代码,是进行2补码到无符号数转变。AD9762是最大电压对应MAX值、0电压对应0值的无符号DAC器件,有符号补码需要先把高位取反再送给DAC。具体原理如下图(字丑莫怪) (3)接口的RTL Viewer 如下: (3)BDF图及引脚分配: DATIN接DDSOUT,SW调幅,接输入两路开关。具体引脚分配见下面链接: DE0引脚分配信息:https://wenku.baidu.com/view/ad51386452ea551810a687bc.html 四.ADC接口模块 (1)ADC接口module代码如下: module ADC_interface(   CLK_ADC  ,   //  adc clk   DAT_ADC  ,   //  input data, from adc   OTR_ADC  ,   //  from adc , signal out of range flag   OTR_OUT  ,   //  output otr flag   STBY_ADC ,   //  adc stand by, set 0 make adc running   DOUT     );   //  data out     input        CLK_ADC  ;  input  [9:0] DAT_ADC  ;  input        OTR_ADC  ; output       OTR_OUT  ; output       STBY_ADC ;   output [9:0] DOUT     ;     reg [9:0] DOUT   ;   reg       OTR_OUT;   always @ (posedge CLK_ADC) begin    DOUT    <= DAT_ADC   ;   OTR_OUT <= OTR_ADC; end   assign STBY_ADC = 1'b0;   endmodule 2)接口的RTL Viewer
  1. BDF图及引脚分配
  细节补充:clk信号处的非门:为了保证脉冲在数据稳定的时刻触发动作。   五.总图:
  • 该设计由一个PLL50MHz晶振生成80MHzDAC时钟、 20MHzADC时钟
  • 一个单周期的DDS生成补码正弦波,转成无符号后送至DAC
  • 拨码开关SW9  SW8 用于控制DAC的输出幅度
  • 其余的SW开关用于控制DDS频率字
  六.编译上载 SMA同轴电缆连接ADCDAC,注意子卡要加一个电源(USB供电)。   拨动开关调频率字: Signal tap 如下: 只开第一路开关,001h   全十路开关,3FFh   开关按照11000018h   开关按照1000011000218h   signal tap 的数据导入matlab生成频域图像: 1  Quartus工程中新建Stp文件,编译,正确的在线采集FPGA内部的数据。 2  如下图所示,在SignalTap窗口中的data下面,右键选择create SignalTapII List file                         3  经过步骤2之后,工程所在的文件夹中会生成一个my_stp_auto_singalTap_0.txt的文件。此时可以用Quartus打开,如下图所示:  4  3步骤的图中,蓝 {MOD}部分是数据的说明(具体表示某一列代表的某个变量),为了Matlab读取数据方便,我们可以去掉前面的说明文件,只留下感兴趣的数据,重新保存为txt文件。打开Matlab,在file下面选择Import Dta…导入.txt文件即可,效果如下图: 5)在matlab命令窗口手动输入sptool指令 6)在跳出窗口的菜单栏file/import导入需要画图的一组数据 7)在signal里面选中刚才的数据,然后再spectra下面的mtlbse模式下点create 8)在弹出的窗格中, method里面选择FFT,设置上阶数,apply即可。为了方便观察,在窗格的option菜单里选择Frequency Range/[-Fs/2,Fs/2] 参考资料: https://wenku.baidu.com/view/704ff8bc50e2524de5187eb2.html   可得效果图如下: DAC_DAT:   ADC_OUT:   可看出ADC底噪高于DAC输出。