EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
5 X/ {5 {, k$ G7 d
# d' h: x3 G; o2 G% z9 Z$ b0 w% S# l$ e9 L* v
1 设计实现1.1 顶层接口新建目录:D:\mdy_book\fir_prj。在该目录中,新建一个名为fir_prj.v的文件,并用GVIM打开,开始编写代码。 1 ]# \! R: R8 ?- h z
我们要实现的功能,概括起来就是FPGA产生控制AD9709,让其中的通道A未滤波的正弦信号,让通道B输出滤波后的正弦信号。为了控制AD9709的工作模式,就要控制AD9709的MODE、SLEEP管脚;为了控制通道A,就需要控制AD9729的CLK1、WRT1、DB7~0P1管脚;为了控制通道B,就需要控制AD9729的CLK2、WRT2、DB7~0P2管脚。根据设计目标的要求,整个工程需要以下信号: 1. 使用clk连接到晶振,表示50M时钟的输入。 2. 使用rst_n连接到按键,表示复位信号。 3. 使用3位信号key,表示三位拨码开关。 4. 使用DAC_mode信号连接到AD9709的MODE管脚,用来控制其工作模式。 5. 使用dac_sleep信号连接到AD9709的SLEEP管脚,用来控制其睡眠模式。 6. 使用dac_clka信号连接到AD9709的CLK1管脚,用来控制通道A的时钟。 7. 使用dac_wra信号连接到AD9709的WRT1管脚,用来控制通道A的写使能。 8. 使用8位信号dac_da连接到AD9709的DB7~0P1管脚,用来控制通道A的写数据。 9. 使用dac_clkb号连接到AD9709的CLK2脚,用来控制通道B时钟。 10. 使用dac_wrb号连接到AD9709的WRT2脚,用来控制通道B使能。 11. 使用8位信号dac_db接到AD9709的DB7~0P2脚,用来控制通道B写数据。 8 r; o- I2 P( j* H2 F, h( X
综上所述,我们这个工程需要11个信号,时钟clk,复位rst_n,拨码开关的输入key,dac_mode、dac_sleep、dac_clka、dac_wra、dac_da、dac_clkb、dac_wrb和dac_db信号,其中dac_da和dac_db是8位信号,其他都是1位信号。下面表格表示了硬件电路图的连接关系。
0 o, A/ W: T0 C器件 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
7 M7 ]- ?! Y* [+ M. D. T | | | | | / V8 }0 \9 Y$ L% T Q
| | | |
, X, j! L- f4 _; V1 G0 B# A
, N3 {; ^' D7 U5 F$ n6 D将module的名称定义为fir_prj,代码如下: $ M, `$ z1 z+ k
| module fir_prj( clk , rst_n , key , dac_mode , dac_sleep , dac_clka , dac_da , dac_wra , dac_clkb , dac_db , dac_wrb ); |
2 _9 g: m- [& q; U* m" x
其中clk、rst_n是1位的输入信号,dac_da和dac_db是8位的输出信号,key是3位输入信号,dac_mode,dac_clka,dac_wra,dac_sleep,dac_clkb,dac_wrb是一位输出信号。
: i% E, G L3 y6 M7 M | input clk ; input rst_n ; input [ 3-1:0] key ; output dac_mode ; output dac_clka ; output [ 8-1:0] dac_da ; output dac_wra ; output dac_sleep ; output dac_clkb ; output [ 8-1:0] dac_db ; output dac_wrb ; [size=9.5000pt] |
" K& u! C' ^7 V7 a5 g7 W
P8 [7 n, s+ E( m0 _
1.2 正弦信号设计假设产生的正弦信号命名为sin_data信号。sin_data是从表XX中选择出来的值,该表一共有128个点。该表的产生方法,请看案例“信号发生器和DA转换”一章的内容。 + b. o; i0 h& v3 @
很自然地定义一个7位的选择信号addr。我们只要控制好addr,就能方便得到sin_data。因此可以写出下面代码。
0 y7 n$ Y1 a6 I& @" E, M7 a2 g | always @(*)begin case(addr) 0: sin_data = 8'h7F; 1: sin_data = 8'H85; 2: sin_data = 8'h8C; 3: sin_data = 8'h92; 4: sin_data = 8'h98; 5: sin_data = 8'h9E; 6: sin_data = 8'hA4; 7: sin_data = 8'hAA; 8: sin_data = 8'hB0; 9: sin_data = 8'hB6; 10: sin_data = 8'hBC; 11: sin_data = 8'hC1; 12: sin_data = 8'hC6; 13: sin_data = 8'hCB; 14: sin_data = 8'hD0; 15: sin_data = 8'hD5; 16: sin_data = 8'hDA; 17: sin_data = 8'hDE; 18: sin_data = 8'hE2; 19: sin_data = 8'hE6; 20: sin_data = 8'hEA; 21: sin_data = 8'hED; 22: sin_data = 8'hF0; 23: sin_data = 8'hF3; 24: sin_data = 8'hF5; 25: sin_data = 8'hF7; 26: sin_data = 8'hF9; 27: sin_data = 8'hFB; 28: sin_data = 8'hFC; 29: sin_data = 8'hFD; 30: sin_data = 8'hFE; 31: sin_data = 8'hFE; 32: sin_data = 8'hFE; 33: sin_data = 8'hFE; 34: sin_data = 8'hFE; 35: sin_data = 8'hFD; 36: sin_data = 8'hFC; 37: sin_data = 8'hFA; 38: sin_data = 8'hF8; 39: sin_data = 8'hF6; 40: sin_data = 8'hF4; 41: sin_data = 8'hF1; 42: sin_data = 8'hEF; 43: sin_data = 8'hEB; 44: sin_data = 8'hE8; 45: sin_data = 8'hE4; 46: sin_data = 8'hE0; 47: sin_data = 8'hDC; 48: sin_data = 8'hD8; 49: sin_data = 8'hD3; 50: sin_data = 8'hCE; 51: sin_data = 8'hC9; 52: sin_data = 8'hC4; 53: sin_data = 8'hBE; 54: sin_data = 8'hB9; 55: sin_data = 8'hB3; 56: sin_data = 8'hAD; 57: sin_data = 8'hA7; 58: sin_data = 8'hA1; 59: sin_data = 8'h9B; 60: sin_data = 8'h95; 61: sin_data = 8'h8F; 62: sin_data = 8'h89; 63: sin_data = 8'h82; 64: sin_data = 8'h7D; 65: sin_data = 8'h77; 66: sin_data = 8'h70; 67: sin_data = 8'H6A; 68: sin_data = 8'h64; 69: sin_data = 8'H5E; 70: sin_data = 8'h58; 71: sin_data = 8'h52; 72: sin_data = 8'h4C; 73: sin_data = 8'h46; 74: sin_data = 8'h41; 75: sin_data = 8'H3C; 76: sin_data = 8'h36; 77: sin_data = 8'h31; 78: sin_data = 8'h2C; 79: sin_data = 8'h28; 80: sin_data = 8'h23; 81: sin_data = 8'h1F; 82: sin_data = 8'h1B; 83: sin_data = 8'h17; 84: sin_data = 8'h14; 85: sin_data = 8'h11; 86: sin_data = 8'hE ; 87: sin_data = 8'hB ; 88: sin_data = 8'h9 ; 89: sin_data = 8'h7 ; 90: sin_data = 8'h5 ; 91: sin_data = 8'h3 ; 92: sin_data = 8'h2 ; 93: sin_data = 8'h1 ; 94: sin_data = 8'h1 ; 95: sin_data = 8'h1 ; 96: sin_data = 8'h1 ; 97: sin_data = 8'h1 ; 98: sin_data = 8'h2 ; 99: sin_data = 8'h3 ; 100: sin_data = 8'h4 ; 101: sin_data = 8'h6 ; 102: sin_data = 8'h7 ; 103: sin_data = 8'hA ; 104: sin_data = 8'hC ; 105: sin_data = 8'hF ; 106: sin_data = 8'h12; 107: sin_data = 8'h15; 108: sin_data = 8'h19; 109: sin_data = 8'h1D; 110: sin_data = 8'h21; 111: sin_data = 8'h25; 112: sin_data = 8'h2A; 113: sin_data = 8'h2E; 114: sin_data = 8'h33; 115: sin_data = 8'h38; 116: sin_data = 8'h3E; 117: sin_data = 8'h43; 118: sin_data = 8'h49; 119: sin_data = 8'h4E; 120: sin_data = 8'h54; 121: sin_data = 8'h5A; 122: sin_data = 8'h60; 123: sin_data = 8'h67; 124: sin_data = 8'h6D; 125: sin_data = 8'h73; 126: sin_data = 8'h79; 127: sin_data = 8'h7F; endcase end |
/ K* H' N5 r& g接下来是设计信号addr。 addr是用来控制选择数据的地址,通过控制addr的增加值,就能产生多种频率的正弦波。 以频率为100KHz的正弦信号为例。该正弦信号的周期是10000ns。本工程的工作时钟是20ns,也就是10000/20 = 500个时钟输出一个正弦信号,也就是500个时钟将上表的128个值输出一遍。因此每个时钟addr增加的值:128/500 = 0.256。 按同样的分析方法,可以得到其他信号频率的addr增加值,总结如下。 100KHz的正弦信号,每个时钟addr增加:128/250 = 0.256 200KHz的正弦信号,每个时钟addr增加:128/250 = 0.512 300KHz的正弦信号,每个时钟addr增加:128/166.6667 = 0.7679 400KHz的正弦信号,每个时钟addr增加:128/125 = 1.024 500KHz的正弦信号,每个时钟addr增加:128/100 = 1.28 600KHz的正弦信号,每个时钟addr增加:128/83.3333 = 1.5358 700KHz的正弦信号,每个时钟addr增加:128/71.4286 = 1.792 800KHz的正弦信号,每个时钟addr增加:128/62.5 = 2.048
) {) m! d) S. k' p$ r7 \$ R由于addr是表示0~127的整数,而addr每次增加的值包含小数,而FPGA是没有小数的。为此,我们将上面的小数乘以1024,然后取整,就变成了每次要增加的整数,结果保存到addr_tmp中。即: 100KHz的正弦信号,每个时钟addr_tmp增加:0.256 *1024 = 262.144 ≈ 262 200KHz的正弦信号,每个时钟addr_tmp增加:0.512 *1024 = 524.288 ≈ 524 300KHz的正弦信号,每个时钟addr_tmp增加:0.7679 *1024 =786.3296 ≈ 786 400KHz的正弦信号,每个时钟addr_tmp增加:1.024 *1024 =1028.576 ≈ 1029 500KHz的正弦信号,每个时钟addr_tmp增加:1.28 *1024 =1310.72 ≈ 1311 600KHz的正弦信号,每个时钟addr_tmp增加:1.5358 *1024 =1572.6592 ≈1573 700KHz的正弦信号,每个时钟addr_tmp增加:1.792 *1024 =1835.008 ≈ 1835 800KHz的正弦信号,每个时钟addr_tmp增加: 2.048 *1024 =2097.152 ≈ 2097 # S6 ]; B( w7 q$ }! l
而上面8种频率信号,是由拨码信号key控制的。因此,可以写出addr_tmp的代码。 | always @(posEDGE clk or negedge rst_n)begin if(rst_n==1'b0)begin addr_tmp <= 0; end else if(key==0) begin addr_tmp <= addr_tmp + 262; end else if(key==1) begin addr_tmp <= addr_tmp + 524; end else if(key==2) begin addr_tmp <= addr_tmp + 786; end else if(key==3) begin addr_tmp <= addr_tmp + 1029; end else if(key==4) begin addr_tmp <= addr_tmp + 1311; end else if(key==5) begin addr_tmp <= addr_tmp + 1573; end else if(key==6) begin addr_tmp <= addr_tmp + 1835; end else begin addr_tmp <= addr_tmp + 2097; end end |
z9 d/ J h% X% f5 u上面的代码中,addr_tmp是小数乘以1024后得到的,那么最终addr_tmp要除以1024,再赋给addr。除以1024,其实就是向右移10位。addr_tmp向各移10位后,保留7位结果赋给addr就够了。所以addr_tmp位宽为17位。 ( \8 O# w( a; S1 L
| assign addr = addr_tmp >>10 ; |
1 G2 z q# ?7 W) f# D
1 e4 M& Y- z3 x; o |