找回密码
 注册
关于网站域名变更的通知
查看: 974|回复: 14
打印 上一主题 下一主题

基于fpga的FIR滤波器设计(附上源码代码下载)

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-3-23 19:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
基于FPGA的FIR滤波器设计
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
器件
AD9709管脚
原理图信号
FPGA管脚
FPGA工程信号
U8
MODE
DAC_MODE
Y4
dac_mode
SLEEP
DAC_SLEEP
H2
dac_sleep
CLK1
DA_CLKA
R2
dac_clka
WRT1
DA_WRA
U1
dac_wra
DB7P1
DAC_DA7
AA1
dac_da[7]
DB6P1
DAC_DA6
Y2
dac_da[6]
DB5P1
DAC_DA5
Y1
dac_da[5]
DB4P1
DAC_DA4
W2
dac_da[4]
DB3P1
DAC_DA3
W1
dac_da[3]
DB2P1
DAC_DA2
V2
dac_da[2]
DB1P1
DAC_DA1
V1
dac_da[1]
DB0P1
DAC_DA0
U2
dac_da[0]
CLK2
DA_CLKB
R1
dac_clkb
WRT2
DA_WRB
P2
dac_wrb
DB7P2
DAC_DB7
P1
dac_db[7]
DB6P2
DAC_DB6
N2
dac_db[6]
DB5P2
DAC_DB5
N1
dac_db[5]
DB4P2
DAC_DB4
M2
dac_db[4]
DB3P2
DAC_DB3
M1
dac_db[3]
DB2P2
DAC_DB2
J1
dac_db[2]
DB1P2
DAC_DB1
J2
dac_db[1]
DB0P2
DAC_DB0
H1
dac_db[0]
X1

7 M7 ]- ?! Y* [+ M. D. T
SYS_CLK
G1
clk
K1
/ V8 }0 \9 Y$ L% T  Q
SYS_RST
AB12
rst_n

, X, j! L- f4 _; V1 G0 B# A
, N3 {; ^' D7 U5 F$ n6 D
将module的名称定义为fir_prj,代码如下:
$ M, `$ z1 z+ k
1
2
3
4
5
6
7
8
9
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
1
2
3
4
5
6
7
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转换”一章的内容。
采样点i
sin_data
(16进制)
采样点i
sin_data
(16进制)
采样点i
sin_data
(16进制)
采样点i
sin_data
(16进制)
0
7F
32
FE
64
7D
96
1
1
85
33
FE
65
77
97
1
2
8C
34
FE
66
70
98
2
3
92
35
FD
67
6A
99
3
4
98
36
FC
68
64
100
4
5
9E
37
FA
69
5E
101
6
6
A4
38
F8
70
58
102
7
7
AA
39
F6
71
52
103
A
8
B0
40
F4
72
4C
104
C
9
B6
41
F1
73
46
105
F
10
BC
42
EF
74
41
106
12
11
C1
43
EB
75
3C
107
15
12
C6
44
E8
76
36
108
19
13
CB
45
E4
77
31
109
1D
14
D0
46
E0
78
2C
110
21
15
D5
47
DC
79
28
111
25
16
DA
48
D8
80
23
112
2A
17
DE
49
D3
81
1F
113
2E
18
E2
50
CE
82
1B
114
33
19
E6
51
C9
83
17
115
38
20
EA
52
C4
84
14
116
3E
21
ED
53
BE
85
11
117
43
22
F0
54
B9
86
E
118
49
23
F3
55
B3
87
B
119
4E
24
F5
56
AD
88
9
120
54
25
F7
57
A7
89
7
121
5A
26
F9
58
A1
90
5
122
60
27
FB
59
9B
91
3
123
67
28
FC
60
95
92
2
124
6D
29
FD
61
8F
93
1
125
73
30
FE
62
89
94
1
126
79
31
FE
63
82
95
1
127
7F
+ b. o; i0 h& v3 @
很自然地定义一个7位的选择信号addr。我们只要控制好addr,就能方便得到sin_data。因此可以写出下面代码。

0 y7 n$ Y1 a6 I& @" E, M7 a2 g
1
2
3
4
5
6
7
8
9
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的代码。
1
2
3
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
1
assign addr = addr_tmp >>10 ;
游客,如果您要查看本帖隐藏内容请回复
1 G2 z  q# ?7 W) f# D

1 e4 M& Y- z3 x; o

该用户从未签到

2#
发表于 2019-3-25 16:20 | 只看该作者
回复看看隐藏内容

该用户从未签到

3#
发表于 2019-5-16 16:24 | 只看该作者
我来瞅一眼+ O& c* l; u; \# P1 H1 R  h( n: ]

该用户从未签到

9#
发表于 2019-10-30 20:56 | 只看该作者
dddd做项目看看隐藏内容qwq4 b8 Q( }4 E8 t( @
  • TA的每日心情
    慵懒
    2024-12-9 15:04
  • 签到天数: 384 天

    [LV.9]以坛为家II

    11#
    发表于 2020-3-12 17:44 | 只看该作者
    好资源,下来看看

    该用户从未签到

    13#
    发表于 2020-3-28 15:39 | 只看该作者
    学习一下,谢大佬!

    该用户从未签到

    14#
    发表于 2020-4-18 16:30 | 只看该作者

    该用户从未签到

    15#
    发表于 2020-5-18 16:14 | 只看该作者
    看看楼主说的是什么9 h- g4 l0 @9 _$ i: ]9 d" X) g" G$ i
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-8-21 13:21 , Processed in 0.156250 second(s), 26 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表