FPGA实战——【1】流水灯
很多软件的使用在之前的博客中写到了,所以不再重复,可以对照之前的文章。
使用Xilinx 的Spartan 6,控制4个LED灯循环点亮。
硬件设计
程序设计
写程序之前,首先建立一个文件夹,包含四个子文件夹。
rtl文件编写
用notepad++写.V文件,存放到rtl文件夹之中。先附上程序,然后讲解。
module flow_led(
input sys_clk,
input sys_rst_n,
output reg [3:0] led //output默认是wire型的,但是在always语句块中赋值,所以必须是reg类型的,就要加上reg
);
//计数器
reg [23:0] counter; //1000_0000 对应24位的计数器
//写计数操作
always @( posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
counter <= 24'd0; //如果不写24'd 就会按系统默认位宽,32位,这样就会造成资源浪费
else if( counter < 24'd1000_0000 )
counter <= counter + 1'b1; //加 二进制的1 ,,区分b与d
else
counter <= 24'b0; //数到最大值,计数值清零
end
//移位操作
always @( posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led <= 4'b0001;
else if(counter == 24'd1000_0000) //如果计数到了1000_0000
led <= {led[2:0],led[3]}; //移位操作,通过{}实现,将最高位移到最低位以实现移位操作
else
led <= led;
end
endmodule
对照程序,首先是要定义端口,也就是输入输出。(注意输出是reg型的)因为这个流水灯是0.2s换一次,而开发板的晶振是50MHz,也就是20ns,所以需要1000_0000次,才能到达0.2s。所以我们需要定义一个counter作为计数器。
接下来写计数操作,也就是计时器怎么工作,代码注释很详细了,注意数制的b与d。
然后就是具体的流水灯实现,移位使用的拼接符{ },把最高位放到最低位以实现循环移位。
可以看到流水灯的rtl文件是很简单。写完文件之后,就可以打开ISE建立工程到prj文件夹中,然后把.V文件添加进去。
ucf文件编写
写完rtl文件,接下来就是编写时序约束ucf文件。首先新建ucf文件到prj文件夹中,然后依据开发板硬件电路,编写ucf约束文件。
##NET sys_clk 表示这是一个sys_clk的端口
##TNM_NET sys_clk_pin将这个端口所驱动的器件,分成一个组,这个组就叫sys_clk_pin
NET sys_clk TNM_NET = sys_clk_pin;
TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 20ns HIGH 50%;
##对其进行周期约束,上升沿有效,占空比50%
##下面对引脚和电平进行约束
NET sys_clk LOC = T8 | IOSTANDARD = LVCMOS33;
NET sys_rst_n LOC = L3 | IOSTANDARD = LVCMOS33;
NET led<0> LOC = P4 | IOSTANDARD = LVCMOS33;
NET led<1> LOC = N5 | IOSTANDARD = LVCMOS33;
NET led<2> LOC = P5 | IOSTANDARD = LVCMOS33;
NET led<3> LOC = M6 | IOSTANDARD = LVCMOS33;
## 1.区分大小写
## 2.led<3> 与 "led[3] " 都是可以的,后面的"LVCMOS33"引号也可以不加。
下载
两个文件都编写完成之后,就可以编译,然后生成bit 流文件,下载到开发板中即可。具体操作参考之前有关ISE使用的文章,很详细。
仿真
编写tb文件
建立tb文件(见之前文章有关仿真的文章)生成文件之后,只需要初始化之后把复位引脚拉高,然后写一个时钟即可(即always语句),大部分代码ISE都自动生成了。
`timescale 1ns / 1ns
module flow_led_tb;
// Inputs
reg sys_clk;
reg sys_rst_n;
// Outputs
wire [3:0] led;
// Instantiate the Unit Under Test (UUT)
flow_led u_flow_led (
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.led(led)
);
initial begin
// Initialize Inputs
sys_clk = 0;
sys_rst_n = 0;
// Wait 100 ns for global reset to finish
#100;
sys_rst_n = 1;
end
always #10 sys_clk = ~sys_clk;
endmodule
联和仿真
编写完tb文件,只需要综合(仿真不需要编译),然后打开打开到仿真模式,启动Modelsim仿真就可以了。
总结
有些步骤并没有很详细,因为之前的几篇文章,把ISE、Modelsim、tb文件编写等都写的比较详细了,参考之前即可。流水灯并不难 ,所以主要是借流水灯开个头,认识一下FPGA开发的流程大致是什么样子的。