明德扬肖老师 发表于 2020-6-19 18:13:20

【FPGA至简设计原理与应用】书籍连载22第三篇FPGA至简设计项目 第十三章FIR滤波器设计


温馨提示:明德扬2023推出了全新课程——逻辑设计基本功修炼课,降低学习FPGA门槛的同时,增加了学习的趣味性,并组织了考试赢积分活动(点击→了解课程详情)http://www.mdy-edu.com/ffkc/415.html,感兴趣请联系易老师:13112063618(微信同步)

本案例的编号为:000600000077,如果有疑问,请按编号在下面贴子查找答案:MDY案例交流【汇总贴】_FPGA-明德扬科教 (mdy-edu.com)
本文为明德扬原创及录用文章,转载请注明出处

大家好,近期我们会连载《FPGA至简设计原理与应用》一书,有兴趣的同学可以学习,也希望大家可以对我们的书提出宝贵的意见和建议。

《FPGA至简设计原理与应用》书籍连载索引目录
http://www.fpgabbs.cn/forum.php?mod=viewthread&tid=989


读过的朋友可积极在贴后留言,书籍正式出版时,我们会从留言者中挑选20位幸运读者,幸运读者可获潘老师亲笔签名书籍一本。

注:手机浏览可能格式会乱,建议用电脑端进行浏览。





第十三章 FIR滤波器设计


本文档编号:000600000025
需要看对应的视频,请点击视频编号:002700000453
1、本文档讲述FPGA产生两路正弦波数据,一路直接由DA输出,一路经过FIR处理之后输出,然后传到示波器进行观察,从而了解FIR滤波器的效果
2、801开发板使用

第1节 项目背景

1.1 FIR和IIR滤波器

有限冲激响应(Finite Impulse Response, FIR)滤波器,又被称为非递归线性滤波器,是数字信号处理系统中最基本的元件。FIR滤波器的脉冲响应由有限个采样值构成,长度(抽头数)为N、阶数为N−1的FIR系统的转移函数、差分方程和单位冲激响应分别如下列三式所示。无限冲激响应(Infinite Impulse Response,IIR)滤波器,又被称为递归线性滤波器。顾名思义,FIR和IIR是相对的,相比于IIR,FIR具备线性相位特性。这里解释一下线性相位的概念:如果滤波器的N个实值系数为对称或者反对称结构则该滤波器具有线性相位,即W(n)=±W(N−1−n)W(n)=±W(N−1−n)。此外,FIR更易于设计,但同样指标下FIR滤波器需要更多的参数,即实现时需要消耗更多的计算单元,因而会产生较大的延迟。
1.2 FIR滤波器的原理
FIR滤波器对信号的处理其实就是信号与FIR滤波器的系数进行卷积(即乘累加)的过程。以声音来举例来看一下滤波器的效果,回顾一下日常生活,在聊天时始终以一种音调说话令人感到舒适,但是如果使用了麦克风等收声设备对声音进行收集并且放大后,由于人的音调高低不平,通过麦克风放大后音调高的声音会变得刺耳。如果把音调转换成波形来描述可以得到如下图所示的波形,可以看出整个声音段比较平稳,但是由于声音的变化会出现异常高的两段波,在现实生活中这就代表着出现了两段特别刺耳的声音,即噪声。而滤波器的作用就是将一段波形中突出的部分弱化掉,因此此时就可以使用滤波器来将噪声弱化。图3.13-1声音的波形表示
明白了滤波器的作用后来讨论一下具体的工作原理。有些读者认为在上述波形中直接将高出来的波减去一定数值就可以了。那么同学们思考一下如何将高出来的波筛选出来呢?是否可以将其按照固定的数值范围划分呢?答案是否定的。这里需要明确一个概念:不同电压值的波形振幅是不同的。依旧拿声音来举例,如果一个人的说话声音一直维持在40分贝左右,那么当他忽然尖叫声音变为了100分贝时可以试着定义80分贝以上的波需要进行过滤弱化。但是如果另外一个人的说话声音一直维持在85分贝以上,他没有进行忽然的尖叫,声音波形一直是平稳的状态。但根据80分贝以上的波需要进行过滤的定义,一直保持85分贝的这一声音就会被过滤掉。
因此在设计时无法规定一个固定范围,令滤波器将此范围的波形全都过滤掉。同时也可以得出结论:滤波器过滤的对象没有固定数值,而是将一段波中忽高峰值弱化,如果本身波形趋于平稳,波的峰值再高也不会进行滤除。

大家都知道平均数的原理,如果你有7个苹果而我有1个苹果,你拥有的苹果数量比我多出很多。但是将所有苹果放在一起,一人分4个,此时相当于我帮你承担了3个苹果后我们拥有的苹果数量就没有任何的差距了。下图所示的统计图可以更加直观的显示,原本你的苹果数量属于高峰值,我们二人均分之后我们的波形都处于平稳的状态了。同理可知,如果将一个波形中的每个相邻点都进行这样的平均就可以得到一个趋于平滑的波形。图3.13-2均分苹果案例
滤波器分为高通、低通和带通等不同类型,即允许不同频率的信号通过滤波器。前文分析可知无法对频率进行临界值的定义,那么如何实现不同频率的值的过滤呢?此时可以采用将相邻两个点的值与过滤器模型值相乘后再进行平均的方法。滤波器的模型值由滤波器自身定义,根据不同的需求进行调整,有可能是一个很大的值,甚至可能是负数以达到过滤的效果。滤波器对信号的处理实际上就是信号与FIR滤波器的系数进行卷积(即乘累加)的过程。
下面通过计算一个简单信号模型来更加深入地了解FIR波形器的原理,本书会将三组信号进行对比,让同学们更加直观的感受到效果。
现在有三组信号,分别是:
信号1:低频信号,即在时域上变化慢的信号,其输入先后顺序为1 1 1 1 2 2 2 2。信号2:直流信号,其输入先后顺序为1 1 1 1 1 1 1 。信号3:高频信号,即在时域上变化快的信号,其输入先后顺序为1 2 1 2 1 2 1 2 。
滤波器选定为低通滤波器,其模型值为:1、1。
首先信号1与低通滤波器进行卷积运算,其结果再除以2,如下图所示,第一个信号数字“1”与第二个信号数字“1”和滤波器模型分别相乘求和后再除以2即(1*1+1*1)/2=1。随后每个相邻的信号依次进行同样的操作,处理后得到如下数据:1 1 1 1.5 2 2 2。可以看到低频信号经由低通滤波器处理后各个点仍然保持了其形状,而且在1变成2时变得平缓。图3.13-3信号1的低通滤波处理结果
同理,信号2与低通滤波器进行卷积运算,其结果再除以2,如下图所示,第一个信号数字“1”与第二个信号数字“1”和滤波器模型分别相乘求和后再除以2即(1*1+1*1)/2=1。随后每个相邻的信号依次进行同样的操作,处理后得到如下数据:1 1 1 1 1 1 1。可以看到直流信号与输入的信号完全相同。图3.13-4信号2的低通滤波处理结果
最后,信号3与低通滤波器进行卷积运算,其结果再除以2,如下图所示,第一个信号数字“1”与第二个信号数字“2”和滤波器模型分别相乘求和后再除以2即(1*1+2*1)/2=1.5。随后每个相邻的信号依次进行同样的操作,处理后得到如下数据:1.5 1.5 1.5 1.5 1.5 1.5 1.5。可以看到高频信号经由低通滤波器处理后已经完成消去了其原本形状,变成了直流信号。图3.13-5信号3的低通滤波处理结果
如果此时滤波器模型选为高通滤波器:1 -1,结果又会如何呢?
信号1与高通滤波器进行卷积运算,其结果再除以2,如下图所示,第一个信号数字“1”与第二个信号数字“1”和滤波器模型分别相乘求和后再除以2即*1+1*(-1)]/2=0。随后每个相邻的信号依次进行同样的操作,处理后得到如下数据:0 0 0 -0.5 0 0 0。可以看到低频信号经由高通滤波器处理后信号变化基本上消失。图3.13-6信号1的高通滤波处理结果
信号2与高通滤波器进行卷积运算,其结果再除以2,如下图所示,第一个信号数字“1”与第二个信号数字“1”和滤波器模型分别相乘求和后再除以2即*1+1*(-1)]/2=0。随后每个相邻的信号依次进行同样的操作,处理后得到如下数据:0 0 0 0 0 0 0。可以看到直流信号仍然没有任何变化。图3.13-7信号2的高通滤波处理结果
信号3与高通滤波器进行卷积运算,其结果再除以2,如下图所示,第一个信号数字“1”与第二个信号数字“2”和滤波器模型分别相乘求和后再除以2即*1+2*(-1)]/2= - 0.5。随后每个相邻的信号依次进行同样的操作,处理后得到如下数据:-0.5 0.5 -0.5 0.5 -0.5 0.5 -0.5。可以看到高频信号仍然保持了其变化形态。图3.13-8信号3的高通滤波处理结果
这里只选取了两个点进行滤波处理,如果按照同样的方法一次进行四、五个信号的卷积运算,滤波器处理后得到的波形会更加平滑。当滤波器的系数不同,抽头个数不同,得到的效果也会不同。
通过上面的案例,相信同学们都已经了解了FIR滤波器的工作原理,简而言之,FIR滤波器的信号处理过程就是信号与FIR滤波器的系数进行卷积(即乘累加)的过程。通过调整滤波器系数、抽头个数等参数可以实现低通、高通、带通等多种滤波器的设计。
1.3 FIR滤波器的设计

1.3.1 matlab产生滤波器系数
打开matlab,在其命令窗口输入fdatool按下回车。图3.13-9matlab命令窗口输入fdatool
调出FIR滤波器的设计界面如下图所示,在此需要进行对应的参数设计,点击Design Filter即可计算出抽头系数。图3.13-10MATLAB中FIR滤波器设计界面
在波形设计界面中需要关注以下几个选项:
Response Type:滤波器的类型选择,可以选择lowpass低通滤波器、Highpass高通滤波器、bandpass带通滤波器、bandstop带阻滤波器四个选项,在设计时根据需求进行选择;
Fs(采样频率):即采样速度或者采样率,其定义了每秒从连续信号中提取并组成离散信号的采样个数;
Fstop:信号截止频率
Fpass:信号通过率
Filter Order:设置滤波器的抽头个数设置,可以在specify order中输入个数,也可以选择Minimum order让系统计算满足要求前提下的最小抽头个数。
产生对应系数后点击“file”菜单里的“Export”将系数保存到工作区,如下图所示。图3.13-11保存滤波器系数
随后直接点击“Export”选项:图3.13-12设置保存滤波器系数路径
打开工作区里的“Num”:图3.13-13在MATLAB显示滤波器系数文件
将下图第一行的数据复制粘贴到txt文件中:图3.13-14在MATLAB打开滤波器文件
特别提示:复制后需在两个系数间插入英文状态下的逗号即可得到滤波器的系数,如下图所示:图3.13-15复制系数到TXT文本
1.3.2 FPGA生成FIR IP核
打开工程后,在“IP catalog”界面中在“DSP”目录下选择“Filter”目录中的“FIR II”选项,如下图所示: 图3.13-16在IP Catalog中找到FIR IP核
在Fitter界面进行如下图所示的设置。图3.13-17FIR IP核类型设置界面
Filter Type:选择滤波器类型Interpolation Factor:插值因子Decimation Factor:抽取因子Max Number of channels:设置通道个数;Clock rate:填写本IP核的工作时钟频率;clock slack:对采样时钟速率、质量的容忍程度,借由对数据的裕量来衡量;Input sample rate (msps):采样率;
点击“coefficients”进入“coefficients”界面后点击“import from file”,找出用matlab生成的系数文件,点击“import”将其导入。导入成功后可以看到“frequency response”界面的波形发生变化,如下图所示。图3.13-18FIR IP频率响应设置界面
在coefficient界面也可以对系数的格式、数据位宽等参数进行设置。图3.13-19FIR IP核滤波器系数设置界面
在此界面不更改其它选项,按照系统默认进行设置,点击“finish”结束。至此完成了生成 FIR滤波器的主要步骤。
第2节 设计目标
按照至简设计法的设计特色,开始一个新的设计之前首先应明确设计目标。设计目标是整个设计的核心灵魂,后续的每个步骤与操作都是围绕设计目标进行展开的。至简设计法旨在让设计师在设计过程中按照最中的简单快捷的方式实现每个步骤和思路,明确设计目标正是让后面每个阶段的工作都有意义,而不去进行不必要的工程展开,这样一来可以少走很多弯路。对于初学者来说学习阶段养成好习惯可以使之后的工程师生涯受益无穷。所以再次强调在开始设计前一定要将设计目标分析透彻,认真思考本次设计最终想要实现什么目的,达到什么效果,然后再投入到设计中去。
本次设计使用采样率大于100M的双通道的示波器与FPGA开发板相连,其连接示意如下图所示,将示波器的两个通道分别与FPGA的DA通道1和DA通道2相连,从而观察两路DA的输出。图3.13-20教学板连接图
本设计需要FPGA内部产生正弦信号,该信号一路输出给DA通道1,另一路经过FIR滤波器后输出给DA通道2。正弦信号的频率约等于100KHz * (key+1),其受开发板上的3个拨码开关控制,可以用3位信号key表示,即一共可以产生8种频率。例如,当key等于0时可以产生频率约为100KHz的正弦信号;当key等于1时可以产生频率约为200KHz的正弦波;当key等于7时可以产生频率约为800KHz的正弦波。FIR滤波器是低通滤波器,其截止频率是500KHz,由此可见,原则上超过500KHz的信号就会被滤除。FIR滤波器实现架构如下图所示,其输出传送给通道2。
图3.13-21FIR滤波器实现架构
FPGA输出后示波器的显示效果如下所示,其中黄色(上面的波形)是通道1输出的信号,蓝色(下面的波形)是通道2的输出信号。下面带领同学们看一下实际产生的信号效果,想要观看完整版视频演示效果的同学可以登陆网址查看:www.mdy-edu.com/xxxx。
100KHz的信号图如下:图3.13-22100K频率信号效果
200KHz的信号图如下:图3.13-23200K频率信号效果
300KHz的信号图如下:图3.13-24300K频率信号效果
400KHz的信号图如下所示,可以看到已经有了明显的衰减:图3.13-25400K频率信号效果
500KHz的信号图如下所示,可以看到已经衰减了很多,波形变得非常小:图3.13-26500K频率信号效果
600KHz的信号图如下所示,可以看到通道2已经几乎没有波形:图3.13-27600K频率信号效果
700KHz的信号图如下所示,可以看到通道2也同样几乎没有波形:图3.13-28700K频率信号效果
800KHz的信号图如下所示,可以看到通道2完全趋于没有波形:图3.13-29800K频率信号效果
第3节 设计实现接下来就进入设计的实现阶段,本书会按照步骤和原理分析与读者分享案例的实现方法,考虑到初学者的需要,此部分的内容会比较详细。基础知识掌握得比较牢靠,只想学习此设计的步骤的情况下可以跳过此部分,后面章节有简化版的步骤分享。在此还是建议初学者不要选择捷径,一定按照详细分析的内容进行学习,只有掌握基础知识、打好基础,才可以从容的独立完成项目设计。
3.1 顶层接口
新建目录:D:\mdy_book\fir_prj。在该目录中,新建一个名为fir_prj.v的文件。用GVIM打开后开始编写代码。这里再次强调,建议初学者按照书中提供的文件路径以及文件名进行设置,避免后续跳出未知错误。
首先来确定顶层信号。分析设计目标可知本设计需要实现以下功能:FPGA产生控制DA9709的信号,令通道A输出未滤波的正弦信号,令通道B输出滤波后的正弦信号,将两种信号进行对比。在此过程中,想要控制DA9709的工作模式则需控制DA9709的MODE、SLEEP管脚;想要控制通道A则需控制AD9280的CLK1、WRT1、DB7~0P1管脚;想要控制通道B则需要控制AD9280的CLK2、WRT2、DB7~0P2管脚。在设计中使用信号clk连接到晶振来表示50M时钟的输入;使用信号rst_n连接到按键来表示复位;使用3位信号key来表示三位拨码开关;将dac_mode信号连接到DA9709的MODE管脚用来控制其工作模式;将dac_sleep信号连接到DA9709的SLEEP管脚用来控制其睡眠模式;将dac_clka信号连接到DA9709的CLK1管脚用来控制通道A的时钟;将dac_wra信号连接到DA9709的WRT1管脚用来控制通道A的写使能;将8位信号dac_da连接到DA9709的DB7~0P1管脚用来控制通道A的写数据;将dac_clkb号连接到DA9709的CLK2脚用来控制通道B时钟;将dac_wrb信号连接到DA9709的WRT2脚用来控制通道B使能;将8位信号dac_db连接到DA9709的DB7~0P2脚用来控制通道B写数据。
综上所述,本工程需要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位信号。信号和硬件的对应关系如下表所示。表3.13 - 1信号和管脚关系
器件DA9709管脚原理图信号FPGA管脚FPGA工程信号
U8MODEDAC_MODEY4dac_mode
SLEEPDAC_SLEEPH2dac_sleep
CLK1DA_CLKAR2dac_clka
WRT1DA_WRAU1dac_wra
DB7P1DAC_DA7AA1dac_da
DB6P1DAC_DA6Y2dac_da
DB5P1DAC_DA5Y1dac_da
DB4P1DAC_DA4W2dac_da
DB3P1DAC_DA3W1dac_da
DB2P1DAC_DA2V2dac_da
DB1P1DAC_DA1V1dac_da
DB0P1DAC_DA0U2dac_da
CLK2DA_CLKBR1dac_clkb
WRT2DA_WRBP2dac_wrb
DB7P2DAC_DB7P1dac_db
DB6P2DAC_DB6N2dac_db
DB5P2DAC_DB5N1dac_db
DB4P2DAC_DB4M2dac_db
DB3P2DAC_DB3M1dac_db
DB2P2DAC_DB2J1dac_db
DB1P2DAC_DB1J2dac_db
DB0P2DAC_DB0H1dac_db
X1
SYS_CLKG1clk
K1
SYS_RSTAB12rst_n

SW_D0SW_DIP0AA3key

SW_D1SW_DIP1AB3key

SW_D2SW_DIP2ABB5key

将module的名称定义为fir_prj。已知该设计有11个信号:clk、rst_n、key、dac_mode、dac_sleep、dac_clka、dac_wra、dac_da、dac_clkb、dac_wrb和dac_db信号,将与外部相连接的信号写入模块接口列表,具体顶层代码如下所示:
12345678910111213module fir_prj(clk,rst_n,         key       ,dac_mode ,dac_sleep ,dac_clka,dac_da,dac_wra,dac_clkb,dac_db,dac_wrb         );

随后声明输入输出属性。这里需要声明这一信号对于FPGA来说属于输入还是输出,如果是输入信号则声明其为input,如果是输出信号则声明其为output。在本设计中,由于clk是外部的晶振输入给FPGA的,因此在FPGA中clk是1位的输入信号input;同样地,rst_n是外部按键输送给FPGA的,因此在FPGA中rst_n也为1位输入信号input;key是3位输入信号input,dac_da和dac_db是8位的输出信号output,dac_mode,dac_clka,dac_wra,dac_sleep,dac_clkb,dac_wrb均为是1位输出信号output。综上所述,补充输入输出端口定义后的代码如下:
1234567input             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;


3.2 正弦信号设计
将正弦信号命名为sin_data信号,sin_data是从表3.13- 2中选择出来的值,该表一共有128个点。该表的计算方法,在上一章节“信号发生器和DA转换”中有详细描述,这里就不再进行赘述了。表3.13- 2 DAC输出采样点对应幅度值
采样点isin_data(16进制)采样点isin_data(16进制)采样点isin_data(16进制)采样点isin_data(16进制)
07F32FE647D961
18533FE6577971
28C34FE6670982
39235FD676A993
49836FC68641004
59E37FA695E1016
6A438F870581027
7AA39F67152103A
8B040F4724C104C
9B641F17346105F
10BC42EF744110612
11C143EB753C10715
12C644E8763610819
13CB45E477311091D
14D046E0782C11021
15D547DC792811125
16DA48D880231122A
17DE49D3811F1132E
18E250CE821B11433
19E651C9831711538
20EA52C484141163E
21ED53BE851111743
22F054B986E11849
23F355B387B1194E
24F556AD88912054
25F757A78971215A
26F958A190512260
27FB599B91312367
28FC60959221246D
29FD618F93112573
30FE628994112679
31FE63829511277F

定义一个7位的选择信号addr,只要控制好addr信号就可以快速得到sin_data。可以写出下面代码:
123456789always@(*)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;endcaseend

那么addr信号又如何设计呢?在本设计中addr用以控制选择数据的地址,通过控制addr的增加值来产生多种频率的正弦波。以频率为100KHz的正弦信号为例,该正弦信号的周期是10000ns。本工程的工作时钟是20ns,也就是10000/20 = 500个时钟输出一个正弦信号,即500个时钟需要输出128个点,因此每个时钟addr增加的值为128/500 = 0.256。
按同样的分析方法,可以得到其他信号频率的addr增加值如下所示:
100KHz的正弦信号,每个时钟addr增加:128/250= 0.256200KHz的正弦信号,每个时钟addr增加:128/250= 0.512300KHz的正弦信号,每个时钟addr增加:128/166.6667 = 0.7679400KHz的正弦信号,每个时钟addr增加:128/125= 1.024500KHz的正弦信号,每个时钟addr增加:128/100 = 1.28600KHz的正弦信号,每个时钟addr增加:128/83.3333= 1.5358700KHz的正弦信号,每个时钟addr增加:128/71.4286 = 1.792800KHz的正弦信号,每个时钟addr增加:128/62.5 = 2.048
addr表示的是采样点的值,即为0~127的整数,但是上面计算出的addr的每次增加值包含小数,众所周知FPGA是没有小数的,因此需要将上面的小数乘以1024后取整,得到每次要增加的整数并将该结果保存到addr_tmp中。即:
100KHz的正弦信号,每个时钟addr_tmp增加:0.256*1024 = 262.144 ≈ 262200KHz的正弦信号,每个时钟addr_tmp增加:0.512*1024 = 524.288 ≈ 524300KHz的正弦信号,每个时钟addr_tmp增加:0.7679*1024 =786.3296 ≈ 786400KHz的正弦信号,每个时钟addr_tmp增加:1.024*1024 =1028.576 ≈ 1029500KHz的正弦信号,每个时钟addr_tmp增加:1.28*1024 =1310.72≈ 1311600KHz的正弦信号,每个时钟addr_tmp增加:1.5358*1024 =1572.6592 ≈1573700KHz的正弦信号,每个时钟addr_tmp增加:1.792*1024 =1835.008 ≈ 1835800KHz的正弦信号,每个时钟addr_tmp增加: 2.048*1024 =2097.152 ≈ 2097
前文分析可知:以上8种频率信号都是由拨码信号key进行控制,因此可以写出addr_tmp的代码如下:
123always@(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)beginaddr_tmp<= 0;    end    else if(key==0) beginaddr_tmp<= addr_tmp + 262;    end    else if(key==1) beginaddr_tmp<= addr_tmp + 524;    end    else if(key==2) beginaddr_tmp<= addr_tmp + 786;    end    else if(key==3) beginaddr_tmp<= addr_tmp + 1029;    end    else if(key==4) beginaddr_tmp<= addr_tmp + 1311;    end    else if(key==5) beginaddr_tmp<= addr_tmp + 1573;    end    else if(key==6) beginaddr_tmp<= addr_tmp + 1835;    end    else beginaddr_tmp<= addr_tmp + 2097;    endend

由于addr_tmp是小数乘以1024后得到的,因此最终addr_tmp需要除以1024后再赋给addr。除以1024的操作可以用右移10位来实现,addr_tmp向右移10位后保留7位结果赋给addr即可。因此addr_tmp位宽为17位,其代码表示如下:
1assign addr = addr_tmp>>10 ;

3.3 FIR滤波器设计


3.3.1 matlab生成FIR系数打开matlab,在其命令窗口输入fdatool按下回车调出波形设计界面。图3.13-30命令窗口输入fdatool
在波形设计界面中按照设计目标进行参数选择。
Response Type:案例要求滤波高于500KHz的信号,因此选择lowpass低通滤波器;Fstop:截止频率设为600KHzFs:采样频率: 12.5MHz(12500Khz)
其它选项默认
最后点击“Design Filter”,波形设计界面如下图所示:图3.13-31设置FIR滤波器参数
产生系数后点击“file”菜单里的“Export”将系数保存到工作区,如下图所示:图3.13-32保存FIR滤波器系数
滤波器系数类型和路径界面如下图所示,此界面不进行改变,直接点击“Export”。图3.13-33保存滤波器系数类型和路径
打开工作区里的“Num”,如下图所示。图3.13-34MATLAB打开系数
随后将下图第一行的数据复制粘贴到txt文件中:图3.13-35滤波器系数
注意复制后需在两个系数间在英文输入状态下插入逗号得到滤波器系数,如下图所示。图3.13-36复制滤波器系数到TXT文件
3.3.2 新建FPGA工程
打开软件“Quartus”,点击“File”菜单下的“New Project Wizard”,如下图所示。图3.13-37QUARTUS新建工程命令
弹出“Introduction”界面后点击“Next”,如下图所示。图3.13-38QUARTUS新建工程介绍界面
设置工程目录,工程名,顶层模块名,其中工程目录设置为:D:\mdy_book\fir_prj;工程名设置为:fir_prj;顶层模块名设置为:fir_prj,如下图所示,填写完毕后直接点击“next”。图3.13-39QUARTUS设置新工程路径和名称
在设置新工程类型界面选择“Empty project”选项建立空白工程,如下图所示,随后点击“Next”。图3.13-40QUARTUS设置新工程类型
错误!未找到引用源。接着是添加文件界面,此时不选择任何文件,直接点击“Next”,如下图所示。图3.13-41QUARTUS添加文件到工程界面
在选择芯片型号界面选择“Cyclone ⅣE”,在芯片型号选择处选择“EP4CE15F23C8”,完成后直接点击“Finish”,如下图所示。图3.13-42QUARTUS设置新工程的芯片型号
3.3.3 FPGA生成FIR IP核
建立工程后,在软件“Quartus”中“IP catalog”这一界面下选择“DSP”目录下“Filter”的“FIR II”选项,如下图所示。、图3.13-43在IP Catalog查找FIR IP核
进入此界面后将新生成的FIR滤波器IP核路径设置为:D:\mdy_book\fir_prj\my_fir.v,“IPvariation file name”这一项选择“Verilog”,随后点击“OK”进入FIR滤波器设置界面,如下图所示。file:///C:/Users/Administrator/Desktop/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%872/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC.files/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC17755.png图3.13-44设置FIR IP核名称和类型界面
在“Fitter specification”界面需要进行以下设置。
Filter Type:选择Single Rate,表示只采用一种采样率;Clock Rate:50MHz;Input Sample Rate (PSPS):12.5MHz;
其余选项默认参数,然后点击“coefficients”选项卡,如下图所示。
图3.13-45设置FIR IP核类型界面

单击“import from file ”选项,在输出的界面中找出用matlab生成的系数文件:my_fir_coe.txt,点击“import”将其导入。导入成功后可以看到下图的“frequency response”界面的波形发生变化。在“Coefficient Bit Width”选项中填写16,表示每个系数用16比特量化。图3.13-46FIR IP核系数设置界面
在“Input/Output Options”选项卡中,需要做如下设置:
Input Type:选择Signed Binary,表示输入的数据是有符号数(补码形式);Input Width:输入8,表示输入的数据是8位位宽;Output Type:选择Signed Binary,表示输出的数据是有符号数(补码形式);MSB Rounding:选择Truncation。表示输出结果的高位要截断;MSB Bits to Remove:填写3,表示MSB要截取3个符号位;LSB Rounding:选择Truncation,表示输出结果的低位要截断;LSB Bits to Remove:填写19,表示LSB要截断低19位;这样最终输出的结果就是8位。
其它选项默认,点击“Finish”,生成FIR IP核。图3.13-47FIR IP核输入输出设置界面
生成FIR IP核界面如下:图3.13-48生成FIR IP成功提示界面
IP核生成后弹出如下图所示对话框,点击“yes”将此IP核添加进工程。图3.13-49将FIR IP核加入工程提示界面
3.3.4 例化FIR IP核
用软件“GVIM”打开D:\mdy_book\fir_prj\my_fir.v文件,生成的FIR IP核文件如下图所示。图3.13-50FIR IP核模块和输出输出信号
my_fir模块的各个信号的描述见下表:表3.13- 3 my_fir模块各信号描述
信号名I/O位宽作用
clkI1时钟输入信号。在FIR设置时已经填写其为50MHz,所以此时连接50MHz时钟。
reset_nI1复位信号,低电平有效。
ast_sink_dataI8FIR滤波器输入的数据输入。注意,输入的是有符号数。
ast_sink_validI1FIR滤波器输入数据的有效指示信号。
ast_sink_errorI1输入数据错误指示信号,此处直接填0。
ast_source_dataO8FIR滤波器的输出。注意,是有符号数。
ast_source_validO1FIR滤波器输出有效指示信号。由于输入始终有效,输出也始终有效,因此此信号可以忽略不用,例化时不进行连接。
ast_source_errorO2FIR滤波器输出错误指示信号。由于输入没错误,输出也不会有错误,所以可以忽略该信号,例化时不进行连接。

由于滤波器的输入数据和输出数据都是有符号数(补码形式,-128~127),但是正弦信sin_data是无符号数(0~255)。因此需要将sin_data变成有符号数后再发送给FIR进行滤波。定义转换后的信号为fir_din,该信号位宽为8位。将sin_data减去128转换成有符号数,即fir_din = sin_data–128。
生成FIR IP核后需要对该IP核进行例化后才可以使用。所谓例化则为把FIR IP核的信号连接到对应的滤波器上。虽然这些信号是一样的,但是在每个模块中信号的命名不同,如果不进行连接,模块与模块之间就会互相不知道对方的存在。因此需要将两个相同的信号连接在一起来达成合作的效果。例化名为u_my_fir,fir的输出数据信号命名为fir_dout,可以写出代码如下:
12345678assign fir_din = sin_data - 128;
my_firu_my_fir(.clk             (clk   ) ,            .reset_n         (rst_n   ) ,          .ast_sink_data   (fir_din ) ,    .ast_sink_valid(1       ) ,   .ast_sink_error(0       ) ,   .ast_source_data (fir_dout) ,.ast_source_valid(      ) ,.ast_source_error(      )    );

3.4 DA接口信号设计
首先设计信号dac_da。dac_da是直接输出正弦信号的,但由于DA的输出电压与dac_da成反比例线性关系,所以dac_da通过(255-sin_data)得到。写代码时可以调用至简设计法模板,在编辑状态下输入“Shixu2”,将其补充完整得到dac_da的代码表示如下:
12345678always@(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begindac_da<= 0;    end    else begindac_da<= 255 - sin_data;    endend

接着设计信号dac_sleep,AD一直进行工作,因此dac_sleep始终为0;为了满足tS的时间要求,可以令dac_clka = ~clk,dac_wra信号与dac_clka相同,其具体代码表示如下:
123assign dac_sleep = 0      ;assign dac_wra   = dac_clka ;assign dac_clka= ~clk      ;

然后设计信号dac_db。dac_db是直接输出滤波后的信号fir_dout。需要注意的是fir_dout是有符号数(范围是-128~127),所以要转为无符号数(0~255)。假设转换后的信号为fir_dout2,则fir_dout2 = fir_dout + 128。由于DA的通道2的输出电压与dac_db是成反比例线性关系,所以dac_db通过(255-fir_dout2)得到。写出dac_db的代码表示如下:
12345678assign fir_dout2 = fir_dout + 128;always@(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begindac_db<= 0;    end    else begindac_db<= 255 - fir_dout2;    endend

最后设计dac_clkb信号,为了满足tS的时间要求,可以让dac_clkb = ~clk,dac_wrb信号与dac_clkb相同,其具体代码表示如下:
123assign dac_wrb   = dac_clkb ;assign dac_clkb= ~clk      ;

至此,模块主体已经完成。
3.5 信号定义
接下来将module补充完整,首先来定义信号类型。reg和wire的判断很容易搞不清楚总会有多余的联想,比如认为reg就是寄存器,wire是线;或者认为reg会综合成寄存器,wire不会综合成寄存器。但是这些其实和reg型还是wire型都并无关系,在进行信号类型判断时不需要做任何的联想,只要记住一个规则:“用always实现的是reg型,其他都是wire型”就可以了。
addr是用assign设计的,因此类型为wire。addr值最大为127,需要用7根线表示,即位宽为7。
关于信号位宽的获取,在这里至简设计法分享一个非常实用的技巧:打开计算器,点击“查看”,选择“程序员”模式,在“十进制”下将信号值输入进去,就会获得对应的信号位宽。利用这一方法将addr的最大计数值127输入到计算器中,如下图所示,可以看到其位宽为7。图3.13-51通过计算器获取信号位宽
综上所述,addr的定义代码如下:
1wire        addr    ;

addr_tmp是用always设计的,因此其类型为reg。该信号的位宽是17,代码表示如下:
1reg       addr_tmp    ;

sin_data是用always设计的,因此类型为reg。其最大值为255,要用8根线表示,位宽为8,可以在编辑状态下输入“Reg8”调用至简设计法模板,补充完整后得到代码如下:
1reg       sin_data    ;

fir_din是用assign设计的,因此类型为wire。该信号位宽为8,在编辑状态下输入“Wire8”调用至简设计法模板,补充完整后得到代码如下:
1wire        fir_din    ;

fir_dout是用例化模块的输出,非always设计因此类型为wire。其位宽为8,依旧在编辑状态下输入“Wire8”调用至简设计法模板,补充完整后得到代码如下:
1wire        fir_dout    ;

fir_dout2是用assign设计的,非always设计因此类型为wire。其位宽为8,同样在编辑状态下输入“Wire8”调用至简设计法模板,补充完整后得到代码如下:
1wire        fir_dout2    ;

dac_da是用always设计的,因此类型为reg,其位宽为8;dac_sleep是用assign设计的,因此类型为wire,其位宽为1;dac_wra是用assign设计的,因此类型为wire,其位宽为1;dac_clka是用assign设计的,因此类型为wire,其位宽为1;dac_mode是用assign设计的,因此类型为wire,其位宽为1。
依旧在编辑状态下输入“ Reg8”“Wire1”调用至简设计法模板,补充完整后得到相应代码如下:
1reg       dac_da    ;wire          dac_sleep;wire          dac_wra;wire          dac_clka;wire          dac_mode ;

dac_db是用always设计的,因此类型为reg,其位宽为8;dac_wrb是用assign设计的,因此类型为wire,其位宽为1;dac_clkb是用assign设计的,因此类型为wire,其位宽为1。
在编辑状态下输入“Reg8”“Wire1”调用至简设计法模板,补充完整后得到相应代码如下:
1reg       dac_db    ;wire          dac_wrb;wire          dac_clkb;

在代码的最后一行写下endmodule
1endmodule

至此,整个代码的设计工作已经完成。完整版的工程代码如下:module fir_prj(

clk,

rst_n,

key       ,

dac_mode ,

dac_sleep ,

dac_clka,

dac_da,

dac_wra,

dac_clkb,

dac_db,

dac_wrb

         );



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;



wire        addr    ;

reg       addr_tmp    ;

reg       sin_data    ;

wire        fir_din    ;

wire        fir_dout    ;

wire        fir_dout2    ;

reg       dac_da    ;

wire          dac_sleep;

wire          dac_wra;

wire          dac_clka;

wire          dac_mode ;



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



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





assign addr = addr_tmp>>10 ;

assign fir_din = sin_data - 128;



my_firu_my_fir(

.clk             (clk   ) ,            

.reset_n         (rst_n   ) ,         

.ast_sink_data   (fir_din ) ,   

.ast_sink_valid(1       ) ,   

.ast_sink_error(0       ) ,   

.ast_source_data (fir_dout) ,

.ast_source_valid(      ) ,

.ast_source_error(      )   

);





always@(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

dac_da<= 0;

    end

    else begin

dac_da<= 255 - sin_data;

    end

end





assign dac_sleep = 0      ;

assign dac_wra   = dac_clka ;

assign dac_clka= ~clk      ;



assign fir_dout2 = fir_dout + 128;

always@(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

dac_db<= 0;

    end

    else begin

dac_db<= 255 - fir_dout2;

    end

end



assign dac_wrb   = dac_clkb ;

assign dac_clkb= ~clk      ;



endmodule



第4节 综合与上板


4.1 添加文件上一节中已经介绍了新建工程的过程,这里就不再赘述了。现在打开软件“Quartus”,在“Project”菜单中选择“Add/Remove File to Project”,如下图所示,随后会弹出文件窗口。图3.13-52添加文件命令界面
点击右上角的按钮,在弹出来的窗口中双击选择D:\mdy_book\fir_prj目录下的fir_prj.v、my_fir.qip文件。点击“Add”添加成功后关闭本窗口,添加文件成功界面如下图所示。图3.13-53添加文件成功界面
4.2 综合
编译界面如下图所示,在菜单栏中选中Processing后选择Start Compilation,开始对整个工程进行编译和综合。图3.13-54编译命令界面
当出现如下图所示界面时说明编译综合成功。图3.13-55编译成功界面
4.3 配置管脚
下面需要对相应管脚进行配置。如下图所示,在菜单栏中,选中“Assignments”,然后选择“Pin Planner”,随后就会弹出配置管脚的窗口。图3.13-56配置管脚命令界面
在配置窗口最下方中的“location”一列,参考表3.2-2信号和管脚关系,按照表3.13- 1中最右两列配置好FPGA管脚。配置管理来源参见管脚配置环节,最终配置的结果如图3.13-58。配置完成后,关闭Pin Planner,软件自动会保存管脚配置信息。表3.13 –1 信号和管脚关系
器件DA9709管脚原理图信号FPGA管脚FPGA工程信号
U8MODEDAC_MODEY4dac_mode
SLEEPDAC_SLEEPH2dac_sleep
CLK1DA_CLKAR2dac_clka
WRT1DA_WRAU1dac_wra
DB7P1DAC_DA7AA1dac_da
DB6P1DAC_DA6Y2dac_da
DB5P1DAC_DA5Y1dac_da
DB4P1DAC_DA4W2dac_da
DB3P1DAC_DA3W1dac_da
DB2P1DAC_DA2V2dac_da
DB1P1DAC_DA1V1dac_da
DB0P1DAC_DA0U2dac_da
CLK2DA_CLKBR1dac_clkb
WRT2DA_WRBP2dac_wrb
DB7P2DAC_DB7P1dac_db
DB6P2DAC_DB6N2dac_db
DB5P2DAC_DB5N1dac_db
DB4P2DAC_DB4M2dac_db
DB3P2DAC_DB3M1dac_db
DB2P2DAC_DB2J1dac_db
DB1P2DAC_DB1J2dac_db
DB0P2DAC_DB0H1dac_db
X1 SYS_CLKG1clk
K1 SYS_RSTAB12rst_n


图3.13-57配置管脚界面

图3.13-58管脚配置成功界面

4.4 再次综合
再次打开“QUARTUS”软件,在菜单栏中选中“Processing”,然后选择“Start Compilation”,再次对整个工程进行编译和综合,如下图所示。图3.13-59编译命令界面
当出现图3.2-19QUARTUS编译成功标志,就说明编译综合成功。图3.13-60编译成功界面
4.5 连接开发板
完成编译后开始进行上板调试操作,开发板连接方式如下图所示。将电源接上开发板,USB BLASTER一端连接到JTAG插口,另一端连到PC的USB接口。将开发板上的AD接口和DA与示波器的两个通道相连,连接完成后将电源打开。图3.13-61教学板连接示意图
4.6 上板
在“Quartus”的“Task”窗口中,右键“Program Device”选择“Open”进入烧录界面,如下图所示。图3.13-62打开配置程序命令
默认选中文件output/fir_prj.sof,Hardware Setup的旁边会显示USB-Blaster,如下图所示。图3.13-63配置程序界面
当进度条到100%提示成功后即可在示波器上观看相应现象。图3.13-64配置成功界面
下载完成后,如果操作无误此时可以在示波器上看到对应的波形。如果没有显示成功,就需要返回检查一下连接是否到位,有没有写错代码或者软件参数的选择有没有发生错误。如果无法自己完成错误排查的话,可以重新按照步骤操作一遍,相信一定会达到想要的效果。
第5节 简化版步骤分享
这里依旧会分享简化版的步骤,方便掌握基础原理后进行反复操作复习。
5.1 设计实现

5.1.1 顶层接口
新建目录:D:\mdy_book\fir_prj。在该目录中,新建一个名为fir_prj.v的文件,并用GVIM打开,开始编写代码。
分析设计目标确定顶层信号,信号和硬件的对应关系图见下表所示。表3.13 –1信号和管脚关系
器件DA9709管脚原理图信号FPGA管脚FPGA工程信号
U8MODEDAC_MODEY4dac_mode
SLEEPDAC_SLEEPH2dac_sleep
CLK1DA_CLKAR2dac_clka
WRT1DA_WRAU1dac_wra
DB7P1DAC_DA7AA1dac_da
DB6P1DAC_DA6Y2dac_da
DB5P1DAC_DA5Y1dac_da
DB4P1DAC_DA4W2dac_da
DB3P1DAC_DA3W1dac_da
DB2P1DAC_DA2V2dac_da
DB1P1DAC_DA1V1dac_da
DB0P1DAC_DA0U2dac_da
CLK2DA_CLKBR1dac_clkb
WRT2DA_WRBP2dac_wrb
DB7P2DAC_DB7P1dac_db
DB6P2DAC_DB6N2dac_db
DB5P2DAC_DB5N1dac_db
DB4P2DAC_DB4M2dac_db
DB3P2DAC_DB3M1dac_db
DB2P2DAC_DB2J1dac_db
DB1P2DAC_DB1J2dac_db
DB0P2DAC_DB0H1dac_db
X1
SYS_CLKG1clk
K1
SYS_RSTAB12rst_n

写出顶层代码:
12345678910111213module fir_prj(clk,rst_n,key       ,dac_mode ,dac_sleep ,dac_clka,dac_da,dac_wra,dac_clkb,dac_db,dac_wrb         );

声明输入输出属性:
1234567input             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;


5.2 正弦信号设计
设计正弦信号sin_data信号:
123456789always@(*)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;endcaseend

设计addr_tmp信号:
123always@(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)beginaddr_tmp<= 0;    end    else if(key==0) beginaddr_tmp<= addr_tmp + 262;    end    else if(key==1) beginaddr_tmp<= addr_tmp + 524;    end    else if(key==2) beginaddr_tmp<= addr_tmp + 786;    end    else if(key==3) beginaddr_tmp<= addr_tmp + 1029;    end    else if(key==4) beginaddr_tmp<= addr_tmp + 1311;    end    else if(key==5) beginaddr_tmp<= addr_tmp + 1573;    end    else if(key==6) beginaddr_tmp<= addr_tmp + 1835;    end    else beginaddr_tmp<= addr_tmp + 2097;    endend

设计addr信号:
1assign addr = addr_tmp>>10 ;

5.2.1 FIR滤波器设计
步骤一:matlab生成FIR系数
打开matlab后在其命令窗口输入fdatool按下回车调出波形设计界面。
图3.13-9matlab命令窗口输入fdatool

点击“Design Filter”设计参数,波形设计界面如下图所示。图3.13-11设置FIR滤波器参数
点击“file”菜单里的“Export”将系数保存到工作区,如下图所示。图3.13-11保存FIR滤波器系数
随后直接点击“Export”。图3.13-12保存滤波器系数类型和路径
打开工作区里的“Num”,如下图所示。图3.13-13在MATLAB显示滤波器系数文件
将下图第一行的数据复制粘贴到txt文件中,得到滤波器系数。图3.13-14在MATLAB打开滤波器文件
特别提示:复制后需在两个系数间插入英文状态下的逗号即可得到滤波器的系数,如下图所示。图3.13-15复制系数到TXT文本
步骤二:新建FPGA工程
打开软件“Quartus”,点击“File”菜单下的“New Project Wizard”。图3.13-37QUARTUS新建工程命令
弹出“Introduction”界面后点击“Next”。图3.13-37 QUARTUS新建工程介绍界面
设置工程目录(目录为D:\mdy_book\fir_prj,工程名和顶层名为fir_prj)后点击“Next”。图3.13-37 QUARTUS设置新工程路径和名称
选择“Empty project”后点击“Next”。图3.13-37 QUARTUS设置新工程类型
此界面不选择任何文件,点击“Next”。图3.13-37 QUARTUS添加文件到工程界面
对芯片型号进行选择,在“Device family”选项中选择“Cyclone ⅣE”,“Available devices”选项下选择“EP4CE15F23C8”,随后点击“Next”。图3.13-37 QUARTUS设置新工程的芯片型号
步骤三:FPGA生成FIR IP核
建立工程后在软件“Quartus”的“IP catalog”界面中选择“DSP”目录下“Filter”的“FIR II”选项,如下图所示。图3.13-37在IP Catalog查找FIR IP
选择路径为D:\mdy_book\fir_prj\my_fir.v,随后选择“Verilog”并点击“OK”。图3.13-37设置FIR IP核名称和类型界面
随后对IP核类型进行设置。“Filter Type”选择“Single Rate”,“Clock Rate”填写“50MHz”,“Input Sample Rate (PSPS)”填写“12.5MHz”,随后点击“coefficients”选项卡。图3.13-37设置FIR IP核类型界面
单击“import from file”选项,导入文件“my_fir_coe.txt”后点击“import”。图3.13-37 FIR IP核系数设置界面
设置“Input/Output Options”选项卡后点击“Finish”。图3.13-37 FIR IP核输入输出设置界面
生成FIR IP核界面如下所示。图3.13-37生成FIR IP成功提示界面
IP核生成后会弹出如下图所示的对话框,点击“yes”将此IP核添加进工程。图3.13-37将FIR IP核加入工程提示界面
步骤四:例化FIR IP核
打开shiD:\mdy_book\fir_prj\my_fir.v文件,生成的FIR IP核文件如下图所示。图3.13-50FIR IP核模块和输出输出信号
将FIR IP核例化,具体代码如下:
12345678assign fir_din = sin_data - 128;
my_firu_my_fir(.clk             (clk   ) ,            .reset_n         (rst_n   ) ,          .ast_sink_data   (fir_din ) ,    .ast_sink_valid(1       ) ,   .ast_sink_error(0       ) ,   .ast_source_data (fir_dout) ,.ast_source_valid(      ) ,.ast_source_error(      )    );

5.2.2 DA接口信号设计
设计信号dac_da:
12345678always@(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begindac_da<= 0;    end    else begindac_da<= 255 - sin_data;    endend

设计信号dac_sleep、dac_clka、dac_wra:
123assign dac_sleep = 0      ;assign dac_wra   = dac_clka ;assign dac_clka= ~clk      ;

设计信号dac_db:
12345678assign fir_dout2 = fir_dout + 128;always@(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)begindac_db<= 0;    end    else begindac_db<= 255 - fir_dout2;    endend

设计信号dac_clkb,dac_wrb:
123assign dac_wrb   = dac_clkb ;assign dac_clkb= ~clk      ;

至此,模块主体已经完成,接下来将module补充完整。
5.2.3 信号定义
首先定义信号类型,addr的信号定义如下:
1wire        addr    ;

addr_tmp的信号定义如下:
1reg       addr_tmp    ;

sin_data的信号定义如下:
1reg       sin_data    ;

fir_din的信号定义如下:
1wire        fir_din    ;

fir_dout的信号定义如下:
1wire        fir_dout    ;

fir_dout2的信号定义如下:
1wire        fir_dout2    ;

dac_da、dac_sleep、dac_wra、dac_clka、dac_mode的信号定义如下:
1reg       dac_da    ;wire          dac_sleep;wire          dac_wra;wire          dac_clka;wire          dac_mode ;

dac_db、dac_wrb、dac_clkb的信号定义如下:
1reg       dac_db    ;wire          dac_wrb;wire          dac_clkb;

在代码的最后一行写下endmodule
1endmodule

至此,整个代码的设计工作已经完成。完整版的工程代码如下:module fir_prj(

clk,

rst_n,

key       ,

dac_mode ,

dac_sleep ,

dac_clka,

dac_da,

dac_wra,

dac_clkb,

dac_db,

dac_wrb

         );



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;



wire        addr    ;

reg       addr_tmp    ;

reg       sin_data    ;

wire        fir_din    ;

wire        fir_dout    ;

wire        fir_dout2    ;

reg       dac_da    ;

wire          dac_sleep;

wire          dac_wra;

wire          dac_clka;

wire          dac_mode ;





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



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





assign addr = addr_tmp>>10 ;

assign fir_din = sin_data - 128;



my_firu_my_fir(

.clk             (clk   ) ,            

.reset_n         (rst_n   ) ,         

.ast_sink_data   (fir_din ) ,   

.ast_sink_valid(1       ) ,   

.ast_sink_error(0       ) ,   

.ast_source_data (fir_dout) ,

.ast_source_valid(      ) ,

.ast_source_error(      )   

);





always@(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

dac_da<= 0;

    end

    else begin

dac_da<= 255 - sin_data;

    end

end





assign dac_sleep = 0      ;

assign dac_wra   = dac_clka ;

assign dac_clka= ~clk      ;



assign fir_dout2 = fir_dout + 128;

always@(posedge clk or negedge rst_n)begin

    if(rst_n==1'b0)begin

dac_db<= 0;

    end

    else begin

dac_db<= 255 - fir_dout2;

    end

end



assign dac_wrb   = dac_clkb ;

assign dac_clkb= ~clk      ;



endmodule

5.3 综合与上板


5.3.1 添加文件

上一节已经介绍了新建工程的过程,这里不再赘述了。
打开“Quartus”软件,在“Project”菜单中选择“Add/Remove File to Project”后弹出文件窗口。图3.13-50添加文件命令界面
点击右上角的按钮,在弹出来的窗口中双击选择D:\mdy_book\fir_prj目录下的fir_prj.v、fir_prj.qip文件。点击“Add”添加成功后关闭窗口。图3.13-50添加文件成功界面
5.3.2 综合
在菜单栏中选中“Processing”后选择“Start Compilation”,开始对整个工程进行编译和综合。图3.13-50编译命令界面
当出现下图的界面则说明编译综合成功。图3.13-50编译成功界面
5.3.3 配置管脚
配置管脚界面如下图所示,在菜单栏中选中“Assignments”后选择“Pin Planner”,随后就会弹出配置管脚的窗口。图3.13-50配置管脚命令界面
在配置窗口“location”配置管脚,配置完成关闭“Pin Planner”即可自动保存配置信息。file:///C:/Users/Administrator/Desktop/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%872/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC.files/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC50238.png图3.13-50配置管脚界面
5.3.4 再次综合file:///C:/Users/Administrator/Desktop/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%872/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC.files/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC50347.png再次打开“QUARTUS”软件,在菜单栏中选中“Processing”后选择“Start Compilation”,再次对整个工程进行编译和综合,如下图所示。图3.13-50编译命令界面当出现图3.2-19QUARTUS编译成功标志则说明编译综合成功。file:///C:/Users/Administrator/Desktop/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%872/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC.files/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC50489.png图3.13-50编译成功界面
5.3.5 连接开发板file:///C:/Users/Administrator/Desktop/%E4%B8%8A%E4%BC%A0%E5%9B%BE%E7%89%872/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC.files/%E4%B9%A6%E7%B1%8D%E8%BF%9E%E8%BD%BD%E7%AB%A0%E8%8A%82%E4%B8%AD%E8%BD%AC50602.png开发板连接方式如下图所示。将电源接上开发板,USB BLASTER一端连接到JTAG插口,另一端连到PC的USB接口。将开发板上的AD接口和DA与示波器的两个通道相连,连接完成后将电源打开。图3.13-50教学板连接示意图
5.3.6 上板

在“Quartus”的“Task”窗口中,右键“Program Device”选择“Open”进入烧录界面,如下图所示。图3.13-50打开配置程序命令
默认选中文件output/fir_prj.sof,在Hardware Setup旁边会显示USB-Blaster,如下图所示。图3.13-50配置程序界面
进度条提示成功后可在示波器上观察相应现象。图3.13-50配置成功界面
第6节 扩展练习
至此,整个FIR滤波器设计就分享完毕了,希望读者朋友们学会了整个设计之后也可以展开更多思考,在学会低通滤波器的基础上尝试一下高通滤波器的设计。基于原理不变的情况下,多做一些尝试,这样可以帮助同学们更深刻的掌握案例。也欢迎有更多思路和想法的同学前往至简设计法论坛进行交流讨论。

下面是工程使用的系数文件





923161517 发表于 2021-5-19 10:58:39

删不了留言

本帖最后由 923161517 于 2021-5-19 17:11 编辑

删不了留言:L

wx_tz5d9 发表于 2022-4-1 16:22:03

有没有测试文件可以参考一下啊?{:9001:}
页: [1]
查看完整版本: 【FPGA至简设计原理与应用】书籍连载22第三篇FPGA至简设计项目 第十三章FIR滤波器设计