數字信號處理專題(1)——DDS函數發生器環路Demo


一、前言

  會FPGA硬件描述語言、設計思想和接口協議,掌握些基本的算法是非常重要的,因此開設本專題探討些基於AD DA數字信號處理系統的一些簡單算法,在數字通信 信號分析與檢測等領域都會或多或少有應用。我們還是從老生常談的DDS函數發生器開始,講解DAC ADC基本使用以及DDS算法原理與設計方式。

二、設計預期

      功能:基於ROM的頻率可調DDS正弦函數發生器

  DAC ADC型號與設計參數:DAC為AD9708,更新速率125MSPS,精度8bit;ADC為AD9280,采樣率32MSPS,精度8bit。由於ADC采樣率限制,設計使用32MHZ頻率時鍾更新與采樣數據,並將ROM深度定義為1024.

  驗證手段:MATLAB產生正弦函數,經過8bit量化后存儲在ROM中,數據經過DAC 電纜 ADC環回到FPGA,ILA抓取ADC接收數據波形,觀察對比發送與接收數據是否相近。

三、DDS原理

  這里只介紹DDS的基本思想,關於詳細原理,請參考:【圖文】DDS原理_百度文庫 https://wenku.baidu.com/view/11cfbf85a0116c175f0e4818.html 

  實際上,DDS的核心就是將正弦或余弦函數存儲在ROM中,利用相位累加特性通過采用不同的步長對ROM尋址的方式產生頻率可調正弦波。另外需要注意產生信號的頻率范圍要滿足奈奎斯特采樣定理,該定理支持若想無失真恢復原始信號,采樣頻率必須大於等於信號最高頻率成分的2倍。反過來說:產生信號的最高頻率小於等於采樣率的1/2.采樣頻率即為FPGA是時鍾頻率。為防止信號混疊,一般取最高頻率成分的1/3.

 四、MATLAB產生正弦序列.coe文件及ROM初始化

   MATLAB產生頻率為1/2*pi標准正弦序列。驗證無誤后,在VIVADO中調用Block Memory Generator IP核,配置為單口ROM,使用剛才產生的系數文件初始化ROM地址數據。

五、DAC ADC驅動

  該設計使用的DAC ADC均為為低速並口轉換芯片,無需配置,只要FPGA給出時鍾信號,並輸出/入並行數據即可。根據AD9708 datasheet時序圖,其在時鍾上升沿采樣,故FPGA在輸出時鍾下降沿更新數據可滿足建立與保持時間要求。ADC同樣上升沿開始更新數據,接收端在時鍾是上升沿采集數據,這樣每一時鍾周期可以采到上一拍送出的數據。

六、函數發生器及測試工程設計

 1 `timescale 1ns / 1ps
 2 
 3 module sin_generator#(parameter FCW_W = 16,
 4                                 DAC_W = 8)
 5  (
 6     input               clk,//DAC采樣時鍾 由PLL產生
 7     input               rst_n,
 8 
 9     input  [FCW_W-1:0]  fcw,
10     output [DAC_W-1:0]  dac_data,
11     output              dac_clk
12     );
13 
14 reg [ (FCW_W-1):0]  sum     ;
15 wire [9:0] addra;
16 //reg [9:0] addra;//地址測試信號
17 wire ena;
18 wire [7:0] douta;
19 
20   //相位累加器
21   //時鍾下降沿產生數據 DAC上升沿采樣
22 always @(negedge clk or negedge rst_n )begin 
23     if(rst_n==0) begin
24         sum <= (0)  ;
25     end
26     else begin
27         sum <= (sum+fcw)  ;
28     end 
29 end
30 
31 assign addra = sum[FCW_W-1-:10];
32 
33 //rom地址測試
34 /*always @(posedge clk or negedge rst_n )begin 
35     if(rst_n==0) begin
36         addra <= (0)  ;
37     end
38     else begin
39         addra <= (addra+1)  ;
40     end 
41 end*/
42 
43 
44 blk_mem_gen_0 u_bram (
45   .clka(clk),    // input wire clka
46   .ena(ena),      // input wire ena
47   .addra(addra),  // input wire [9 : 0] addra
48   .douta(douta)  // output wire [7 : 0] douta
49 );
50 assign ena = 1'b1;
51 //輸出信號
52 assign dac_data = douta;
53 assign dac_clk = ~clk;
54 
55 endmodule
sin_generator

  函數發生器模塊由輸入端口fcw數值確定頻率控制字。測試工程頂層包括差分時鍾轉單端時鍾原語,用於產生DAC ADC時鍾的PLL 函數發生器模塊,生成特定頻率控制字的VIO IP核,還有接收端ADC數據采樣邏輯以及ILA 調試IP核。

 1 `timescale 1ns / 1ps
 2 
 3 
 4 module DDS_Demo_top
 5 #(parameter AD_DA_W = 8)
 6     (
 7     input sys_clk_p,
 8     input sys_clk_n,
 9     input rst_n,
10 
11     output [AD_DA_W-1:0] DAC_data,
12     output DAC_clk,
13 
14     input [AD_DA_W-1:0] ADC_data,
15     output ADC_clk
16     );
17 
18 localparam FCW_W = 16;
19 
20 wire sys_clk_ibufg;
21 wire clk_dac,clk_adc;
22 reg [ (AD_DA_W-1):0]  data_ad     ;
23 
24 wire [FCW_W-1 : 0] probe_out0;
25 wire [AD_DA_W*2-1:0] probe0;
26 
27 //ADC接口信號
28 //ADC在時鍾上升沿后送出數據,FPGA下一個上升沿采樣
29 assign ADC_clk = clk_adc;
30 
31 always @(posedge clk_adc or negedge rst_n )begin 
32     if(rst_n==0) begin
33         data_ad <= (0)  ;
34     end
35     else begin
36         data_ad <= (ADC_data)  ;
37     end 
38 end
39 
40 
41 /***************************************子模塊例化***************************************/
42 IBUFGDS #
43 (
44 .DIFF_TERM ("FALSE"),
45 .IBUF_LOW_PWR ("FALSE")
46 )
47 u_ibufg_sys_clk
48 (
49 .I (sys_clk_p),
50 .IB (sys_clk_n),
51 .O (sys_clk_ibufg)
52 );
53 
54 clk_wiz_0 u_pll
55    (
56     // Clock out ports
57     .clk_out1(clk_dac),         // output clk_out1
58     .clk_out2(clk_adc),         // output clk_out2
59     // Status and control signals
60     .resetn(rst_n),             // input resetn
61     .locked(),                  // output locked
62    // Clock in ports
63     .clk_in1(sys_clk_ibufg));   // input clk_in1
64 
65 sin_generator#(.FCW_W(FCW_W),
66                .DAC_W(AD_DA_W))
67 u_sin_gen
68  (
69     .clk      (clk_dac)  ,//DAC采樣時鍾 由PLL產生
70     .rst_n    (rst_n)  ,
71     .fcw      (probe_out0)  ,
72     .dac_data (DAC_data)  ,
73     .dac_clk  (DAC_clk)  //由clk_dac產生
74     );
75 
76 //debug cores
77 vio_0 u_vio (
78   .clk(clk_dac),                // input wire clk
79   .probe_out0(probe_out0)  // output wire [15 : 0] probe_out0
80 );
81 
82 ila_0 u_ila (
83     .clk(clk_adc), // input wire clk
84     .probe0(probe0) // input wire [15:0] probe0
85 );
86 
87 assign probe0[7:0] = DAC_data;
88 assign probe0[15:8] = ADC_data;
89 
90 endmodule
DDS_Demo

  最后添加引腳約束文件:

 1 #################################clock && reset###############################################
 2 create_clock -period 5 [get_ports sys_clk_p]
 3 set_property PACKAGE_PIN R4 [get_ports {sys_clk_p}]
 4 set_property IOSTANDARD DIFF_SSTL15 [get_ports {sys_clk_p}]
 5 
 6 set_property PACKAGE_PIN T6 [get_ports rst_n]
 7 set_property IOSTANDARD LVCMOS15 [get_ports rst_n]
 8 
 9 #####################DAC PIN connect J4 expansion interface##########################
10 set_property PACKAGE_PIN H14 [get_ports {DAC_clk}]
11 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_clk}]
12 
13 set_property PACKAGE_PIN J14 [get_ports {DAC_data[7]}]
14 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[7]}]
15 set_property PACKAGE_PIN H15 [get_ports {DAC_data[6]}]
16 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[6]}]
17 set_property PACKAGE_PIN J15 [get_ports {DAC_data[5]}]
18 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[5]}]
19 set_property PACKAGE_PIN G13 [get_ports {DAC_data[4]}]
20 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[4]}]
21 set_property PACKAGE_PIN H13 [get_ports {DAC_data[3]}]
22 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[3]}]
23 set_property PACKAGE_PIN J21 [get_ports {DAC_data[2]}]
24 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[2]}]
25 set_property PACKAGE_PIN J20 [get_ports {DAC_data[1]}]
26 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[1]}]
27 set_property PACKAGE_PIN G16 [get_ports {DAC_data[0]}]
28 set_property IOSTANDARD LVCMOS33 [get_ports {DAC_data[0]}]
29 
30 #####################ADC PIN connect J4 expansion interface##########################
31 
32 set_property PACKAGE_PIN D22 [get_ports {ADC_clk}]
33 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_clk}]
34 
35 set_property PACKAGE_PIN G21 [get_ports {ADC_data[7]}]
36 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[7]}]
37 set_property PACKAGE_PIN G22 [get_ports {ADC_data[6]}]
38 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[6]}]
39 set_property PACKAGE_PIN H20 [get_ports {ADC_data[5]}]
40 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[5]}]
41 set_property PACKAGE_PIN G20 [get_ports {ADC_data[4]}]
42 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[4]}]
43 set_property PACKAGE_PIN J22 [get_ports {ADC_data[3]}]
44 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[3]}]
45 set_property PACKAGE_PIN H22 [get_ports {ADC_data[2]}]
46 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[2]}]
47 set_property PACKAGE_PIN K21 [get_ports {ADC_data[1]}]
48 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[1]}]
49 set_property PACKAGE_PIN K22 [get_ports {ADC_data[0]}]
50 set_property IOSTANDARD LVCMOS33 [get_ports {ADC_data[0]}]
clk_pin

七、實驗結果分析

  依據之前的參數和DDS信號頻率公式,所生成正弦函數頻率最好在32/2^16~32/3MHZ之內,使用VIO改變頻率控制字數值,觀察ILA抓取的發送與接收數據模擬形式波形。任意給出三組頻率范圍內波形,頻率依次由低到高。

  總體來講還是比較簡單。搭建好DAC ADC環路,后面可以驗證些濾波 同步算法,或者做些數字頻率計、示波器之類的實用設計。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com