前言:
本文主要介绍了EDA原理与应用这门课程的相关实验及代码。使用的软件是Quartus Ⅱ,该实验使用fpga芯片为cycloneⅤ 5CSEMA5F31C6。
(一)实验目的
(1)学习复杂数字系统设计;
(2)学习用LPM(Library of Parameterized Modules 参数可设置模块库)进行设计;
(3)了解Verilog产生VGA显示时序的方法;
(4)学习用在线逻辑分析仪SignalTap观察FPGA产生的信号;
(5)培养工程思维及创新思维。
(二)实验要求
自选一个具有创意的数字系统综合应用题目,划分功能模块,设计调试完成。
以信号发生器设计为例------
基本设计要求(每个同学必须完成,独立验收考核)----LPM定制信号发生器:
(1)数字化波形数据存在ROM中,ROM用LPM进行设计;
(2)正弦波或方波、锯齿波波形可选并数码管显示所选波形种类;
(3)信号频率、幅度可调并用数码管显示频率和幅值;
(4)用SignalTap逻辑仪器观察信号波形。
(三)实验过程
1.首先我们安装下面给出的方法配置波形rom文件,方便调用。
从上文可以看出,rom文件的地址代表波形的横坐标即时间,地址里面的内容代表波形的纵坐标即幅度。
因此我们只需要随时钟一个一个地址读过去即可将波形完整的读出来,并且通过修改每个时钟地址的增值变更波形的频率,修改读出地址内容的大小变更波形的幅度。
这儿我们配置好三种形式的波形,分别为正弦波、矩形波、梯形波,然后用顶层文件调用rom例化。
(四)实验仿真
使用modelsim仿真
更进一步,可以使用SignalTap II嵌入式逻辑分析仪实时查看FPGA输出波形。
(五)实验源码
5.1顶层模块LPM
//顶层模块代码
module LPM(
input clk, /*时钟输入*/
input rst, /*低电平置0*/
input tp, //调节频率
input tf, //调节幅度
input mode_an, //波形选择
output reg [7:0] q , /*输出*/
output reg [6:0] SG0,SG1,SG2,SG3,SG4,SG5
);
/***************address generate***************/
wire [5:0] addr;
wire [7:0] q1,q2,q3; //存放三种波形输出
wire tp_flag,tf_flag,mode_an_flag;//按键有效信号
reg [31:0] cnt;
reg [31:0] pin;
reg [3:0] fu;
reg [1:0] mode;
reg [5:0] dp;
//幅度,频率调节
always@(posedge clk or negedge rst)
begin
if(!rst)
begin cnt <= 32'd0;pin<=32'h10000000;fu<=4'd1; dp<=6'd2;end
else
begin
cnt <= cnt+pin;
if(tp_flag)//每按下一次调频按键,频率大/小一倍
begin
dp<=dp*2;pin<=pin<<1;
if(dp==6'd4)
dp<=6'd1;
if(pin==32'h20000000)
pin<=32'h08000000;
end
if(tf_flag)//每按下一次调幅按键,幅度大/小一倍
begin
fu<=fu<<1;
if(fu==8)
fu<=4'd1;
end
end
end
/***********ROM instance**********************/
assign addr = cnt[31:26] ; //取高六位
//调用三种波形rom
rom_1 ROM_1(
.address(addr),
.clock(clk),
.q(q1)
);
rom_f ROM_f(
.address(addr),
.clock(clk),
.q(q2)
);
rom_j ROM_j(
.address(addr),
.clock(clk),
.q(q3)
);
//波形输出选择
always@(posedge clk or negedge rst)
begin
if(!rst)
begin
mode<=0;
end
else
begin
if(mode_an_flag)//每按下一次波形输出选择按键,改变波形
begin
mode<=mode+1;
if(mode==3)
mode<=0;
end
case(mode)
0: begin
q<=q1*fu/5;
end
1:begin
q<=q2*fu/5;
end
2:begin
q<=q3*fu/5;
end
default begin mode<=0;q<=q1*fu/5; end
endcase
end
end
//按键输入
key key_inst0
(
.sys_clk (clk ) ,
.sys_rst_n (rst) ,
.key_in (tp ) ,
.key_flag (tp_flag)
);
key key_inst1
(
.sys_clk (clk ) ,
.sys_rst_n (rst) ,
.key_in (tf ) ,
.key_flag (tf_flag)
);
key key_inst2
(
.sys_clk (clk ) ,
.sys_rst_n (rst) ,
.key_in (mode_an) ,
.key_flag (mode_an_flag)
);
//数码管显示
wire [3:0] dpb,dps,dpg;
wire [3:0] dfs,dfg;
assign dpb=dp/100;assign dps=dp%100/10;assign dpg=dp%10;
assign dfs=fu/10;assign dfg=fu%10;
always@(posedge clk)
begin
case(mode)
0:SG5<=7'b1000000; 1:SG5<=7'b1111001;
2:SG5<=7'b0100100; 3:SG5<=7'b0110000;
4:SG5<=7'b0011001; 5:SG5<=7'b0010010;
6:SG5<=7'b0000010; 7:SG5<=7'b1111000;
8:SG5<=7'b0000000; 9:SG5<=7'b0010000; //7段译码值
endcase
case(dpb)
0:SG4<=7'b1000000; 1:SG4<=7'b1111001;
2:SG4<=7'b0100100; 3:SG4<=7'b0110000;
4:SG4<=7'b0011001; 5:SG4<=7'b0010010;
6:SG4<=7'b0000010; 7:SG4<=7'b1111000;
8:SG4<=7'b0000000; 9:SG4<=7'b0010000; //7段译码值
endcase
case(dps)
0:SG3<=7'b1000000; 1:SG3<=7'b1111001;
2:SG3<=7'b0100100; 3:SG3<=7'b0110000;
4:SG3<=7'b0011001; 5:SG3<=7'b0010010;
6:SG3<=7'b0000010; 7:SG3<=7'b1111000;
8:SG3<=7'b0000000; 9:SG3<=7'b0010000; //7段译码值
endcase
case(dpg)
0:SG2<=7'b1000000; 1:SG2<=7'b1111001;
2:SG2<=7'b0100100; 3:SG2<=7'b0110000;
4:SG2<=7'b0011001; 5:SG2<=7'b0010010;
6:SG2<=7'b0000010; 7:SG2<=7'b1111000;
8:SG2<=7'b0000000; 9:SG2<=7'b0010000; //7段译码值
endcase
case(dfs)
0:SG1<=7'b1000000; 1:SG1<=7'b1111001;
2:SG1<=7'b0100100; 3:SG1<=7'b0110000;
4:SG1<=7'b0011001; 5:SG1<=7'b0010010;
6:SG1<=7'b0000010; 7:SG1<=7'b1111000;
8:SG1<=7'b0000000; 9:SG1<=7'b0010000; //7段译码值
endcase
case(dfg)
0:SG0<=7'b1000000; 1:SG0<=7'b1111001;
2:SG0<=7'b0100100; 3:SG0<=7'b0110000;
4:SG0<=7'b0011001; 5:SG0<=7'b0010010;
6:SG0<=7'b0000010; 7:SG0<=7'b1111000;
8:SG0<=7'b0000000; 9:SG0<=7'b0010000; //7段译码值
endcase
end
endmodule
5.2按键源码:
`timescale 1ns/1ns
//波动开关,只有key_in由0-1才会产生一个时钟高脉冲有效信号,即上升沿有效
module key
(
input sys_clk ,
input sys_rst_n ,
input key_in ,
output reg key_flag
);
reg key_now;
reg key_next;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
key_now <= 1'd0;
else
key_now <= key_next;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
key_next<=1'b0;
else if(key_in)
key_next<=1'b1;
else
key_next<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
key_flag<=1'b0;
else if((key_now==0)&&(key_next==1))
key_flag<=1'b1;
else
key_flag<=1'b0;
endmodule
5.3仿真源码:
`timescale 1ns/1ns
module tb_lpm();
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//wire define
wire [7:0] q ;/*输出*/
//reg define
reg sys_clk ;
reg sys_rst_n ;
reg tp ;
reg tf ;
reg mode_an ;
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//sys_clk,sys_rst_n初始赋值,模拟触摸按键信号值
initial
begin
sys_clk <= 1'b1 ;
sys_rst_n <= 1'b0 ;
tp <= 1'b0 ;
tf <= 1'b0 ;
mode_an <= 1'b0 ;
#200
sys_rst_n <= 1'b1 ;
#1000
mode_an <= 1'b1 ;
#100
mode_an <= 1'b0 ;
#1000
mode_an <= 1'b1 ;
#100
mode_an <= 1'b0 ;
#1000
tf <= 1'b1 ;
#100
tf <= 1'b0 ;
#1000
tp <= 1'b1 ;
#100
tp <= 1'b0 ;
end
//clk:产生时钟
always #10 sys_clk = ~sys_clk ;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- touch_ctrl_led_inst -------------
LPM LPM_list(
.clk (sys_clk ) , /*时钟输入*/
.rst (sys_rst_n ) , /*低电平置0*/
.tp (tp ) , //调节频率
.tf (tf ) , //调节幅度
.mode_an(mode_an) ,
.q (q ) /*输出*/
);
endmodule