【紫光同创国产FPGA教程】【第二章】LED流水灯实验及仿真

描述

原创声明:

本原创教程由芯驿电子科技(上海)有限公司(ALINX)创作,版权归本公司所有,如需转载,需授权并注明出处(alinx.com)。

适用于板卡型号:

PGL22G/PGL12G

1. 实验简介

通过LED流水灯实验,介绍使用PDS软件开发FPGA的基本流程,器件选择、设置、代码编写、编译、分配管脚、下载、程序FLASH固化、擦除等;同时也检验板上LED灯是否正常。

2. 实验环境

  • Windows 10 64位

  • Pango Design Suite 2020.3

3. 实验原理

3.1 LED硬件电路

 

紫光同创开发板 LED部分原理图

 

从上面的LED部分原理图可以看出,开发板都是将IO经过一个电阻和LED串联接电源端,FPGA的IO输出低电平点亮LED。IO输出高电平LED灯熄灭,其中的串联电阻都是为了限制电流。

3.2程序设计

FPGA的设计中通常使用计数器来计时,对于50Mhz的系统时钟,一个时钟周期是20ns,那么表示一秒需要50000000个时钟周期,如果一个时钟周期计数器累加一次,那么计数器从0到49999999正好是50000000个周期,就是1秒的时钟。

程序中定义了一个32位的计数器:

//Define the time counter 
reg[31:0]      timer;

最大可以表示4294967295,十六进制就是FFFFFFFF,如果计数器到最大值,可以表示85.89934592秒。程序设计中是每隔1秒LED变化一次,一共消耗4秒做一个循环。

always@(posedge sys_clk ornegedge rst_n)begin
	if(~rst_n)
		timer <=32'd0;
	elseif(timer ==32'd199_999_999)
		timer <=32'd0;
	else
		timer <= timer +1'b1;end

在第一秒、第二秒、第三秒、第四秒到来的时候分别改变LED的状态,其他时候都保持原来的值不变。

// LED controlalways@(posedge sys_clk ornegedge rst_n)begin
	if(~rst_n)
		led <=4'b0000;
	elseif(timer ==32'd49_999_999)
		led <=4'b0001;
	elseif(timer ==32'd99_999_999)
		led <=4'b0010;
	elseif(timer ==32'd149_999_999)
		led <=4'b0100;
	elseif(timer ==32'd199_999_999)
		led <=4'b1000;end

4. PDS工程

4.1 创建工程

1)启动Pango Design Suite 2020.3开发环境(在开始菜单中选择pango->Pango Design Suite 2020.3>Pango Design Suite 。Pango Design Suite(简称PDS)或者双击桌面的Pango Design Suite 2020.3的图标直接打开软件。

 

 

2)在PDS 开发环境里双击Create Project或File->New Project...这两种方式都可,如下图:

 

紫光同创

 

3) 弹出一个PDS的工程向导,点击Next按钮。

 

紫光同创

 

4)在弹出的对话框中输入工程名和工程存放的目录,这里取一个led_test的工程名,点击Next;

 

紫光同创

 

5) 在下面的对话框中默认选择RTL Project, 因为我们这里使用verilog行为描述语言来编程,单击Next

 

紫光同创

 

6) 进入Add Design Source Files界面,这里先不添加任何设计文件。点击Next;

 

紫光同创

 

7)这里问是否添加已有的IP,保持默认不添加,单击Next;

 

紫光同创

 

8)提示是否添加已有的约束文件,这里约束文件我们也没有设计好,也不添加。

 

紫光同创

 

9)在接下来的对话框选择所用的FPGA器件,以及进行一些配置。开发板首先在Family栏里选择Logos,Device中选择PGL22G,在Package栏选择BG324, Speed grade栏选择-6;综合工具选择ADS;单击NEXT进入下一界面:

 

紫光同创

 

10)再次确认一下板子型号有没有选对, 没有问题再点击“Finish”完成工程创建。

 

紫光同创

 

11)工程创建后如下图所示:

 

紫光同创

 

4.2 编写流水灯的verilog代码

1)双击Sources下的Designs图标;

 

紫光同创

 

2) 在Add Design Source Files界面中进行如下设置,点击OK;

 

紫光同创

 

3)可以看到已经新建发led_test.v文件,点击OK按钮。

 

紫光同创

 

向导会提示您定义I/O的端口,这里我们可以不定义,后面自己在程序中编写就可以,单击OK完成。

 

紫光同创

 

这时在Navigator界面下的Designs里已经有了一个led_test.v文件, 并且自动成为项目的顶层(Top)模块了。

 

紫光同创

 

4)接下去我们来编写led_test.v的程序,这里我们定义了一个32位的寄存器timer, 用于循环计数0~199_999_999(4秒钟), 当计数到49_999_999(1秒)的时候,熄灭第一个LED灯;当计数到99_999_999(2秒)的时候,熄灭第二个LED灯;当计数到149_999_999(3秒)的时候,熄灭第三个LED灯;当计数到199_999_999(4秒)的时候,熄灭第四个LED灯,计数器再重新计数。具体的操作直接看代码吧。

`timescale1ns/1nsmodule led_test (
  sys_clk,// system clock 50Mhz on board  rst_n,// reset ,low active            
  led             // LED,use for control the LED signal on board);input         sys_clk;input         rst_n;output[3:0]  led;//define the time counterreg[31:0]   timer;reg[3:0]    led;always@(posedge sys_clk ornegedge rst_n)beginif(~rst_n)
          timer <=32'd0;// when the reset signal valid,time counter clearingelseif(timer ==32'd199_999_999)//4 seconds count(50M*4-1=199999999)          timer <=32'd0;//count done,clearing the time counterelse
            timer <= timer +1'b1;//timer counter = timer counter + 1endalways@(posedge sys_clk ornegedge rst_n)beginif(~rst_n)
          led <=4'b0000;//when the reset signal active         
elseif(timer ==32'd49_999_999)//time counter count to 1st sec,LED1 lighten
          led <=4'b0001;elseif(timer ==32'd99_999_999)//time counter count to 2nd sec,LED2 lightenbegin
          led <=4'b0010;endelseif(timer ==32'd149_999_999)//time counter count to 3nd sec,LED3 lighten          led <=4'b0100;elseif(timer ==32'd199_999_999)//time counter count to 4nd sec,LED4 lighten          led <=4'b1000;endendmodule

5)编写好代码后保存,点击菜单File -Save All。

添加UCE约束

User Constraint Editor(Timing and Logic)简称UCE,主要是完成管脚的约束,时钟的约束, 以及组的约束。这里我们需要对led_test.v程序中的输入输出端口分配到FPGA的真实管脚上。

1)击菜单栏“Tools”下的"User Constraint Editor";

 

紫光同创

 

2)在弹出的界面中单击Device;

 

紫光同创

 

3)在Device中单击I/O,可看到工程中用到的IO端口;

 

紫光同创紫光同创

 

4)按如下方式分配管脚,LOC就是与硬件中FPGA相对应的管脚,VCCIO是FPGA的IO的电压标准,与硬件对应,其它在这里保持默认即可;

 

紫光同创

 

5)单击保存后会弹对话框,在这里选择默认;

 

紫光同创

 

4.4 生成位流文件

双击Generate Bitstream,然后软件会按照Synthesize-> Device Map-> Place & Route-> Generate Bitstream来产生位流文件。

 

紫光同创

 

如果工程在生成位流文件过程中没有错误,则会出现下图中每一步都正确的“√”,否则就会在Messages栏中显示errors的错误。

 

紫光同创

 

位流文件生成完成后,我们可以在Report Summary页面的到了FPGA资源的使用情况。

 

紫光同创

 

此外还可以通过下图操作查看RTL视图;

 

紫光同创紫光同创

 

4.5 下载和调试

在上面生成了位流文件(.sbit)后,我们可以把sbit文件下载到FPGA芯片中,看一下LED实际运行的效果。下载和调试之前先连接硬件,把JTAG下载器和开发板连接,然后开发板上电(下图为开发板的硬件连接图)。

 

 

1)单击界面中的“Configuration”按钮,作用一是下载程序到FPGA中运行;二是固化程序到flash中。

 

紫光同创

 

2)在弹出的界面中的单击“Boundary Scan”,然后在右侧空白区单击右键选择“Scan Device”;

 

紫光同创

 

3)在扫描到JTAG设备后会弹出如下对话框,并按如下加载.sbit文件即可;

 

紫光同创

 

4)然后可以看到左侧显示了要加载的文件,选中右侧绿色的方块,右击会弹出下拉菜单并选择"Program...",下载完成后在板上可以在开发板上看到LED流水灯的效果。注意:这种方式程序是在FPGA运行,掉电后会消失。

 

紫光同创

 

4.6 FLASH程序固化

可能已经有朋友发现下载.sbit文件到FPGA后,开发板重新上电后配置程序已经丢失,还需要JTAG下载。这岂不麻烦!好吧,这一节我们来介绍如何把配置程序固化到开发板上的FLASH中,这样不用担心掉电后程序丢失了。

在我们的开发板上有一个8Pin的128Mbit的FLASH, 用于存储配置程序。我们不能直接把sbit文件下载到这个FLASH中,只能下载sfc文件到flash中。下面为大家介绍FLASH程序的固化的流程。

1)首先,需要sbit文件转换成能下载的flash的sfc文件。在完成上节下载和调试后,选择菜单"Operations"下"Convert File"进行文件转换。

 

紫光同创

 

然后弹出如下界面,这里要根据硬件的flash型号来选择flash的厂家和设备型号,开发板用到的是WINBOND的W25Q128Q。Flash Read Mode 选择SPI X4然后选择要转换的sbit文件,点击OK即可转换;

 

紫光同创

 

转换完成后显示如下界面,单击OK;

 

紫光同创

 

2)选中右侧绿色的方块,右击会弹出下拉菜单并选择"Scan outer Flash"。

 

紫光同创

 

选择已生成的sfc文件,单击Open;

 

紫光同创

 

可以看到界面中有了flash器件,选中“Outer Flash”绿色方块并右击选择菜单中“Program...”

 

紫光同创

 

弹出正在编程的进度界面,flash编程完成后进度界面自动消失。

 

紫光同创

 

至此,SPI FLASH 烧写完毕,led_test程序已经固化到SPI FLASH中了。我们来验证一下,关电重新启动开发板,等待一会儿你就可以看到开发板上的LED灯已经在做跑马运动了。

4.7 仿真验证

接下来我们不妨小试牛刀,让仿真工具modelsim来输出波形验证流水灯程序设计结果和我们的预想是否一致。具体步骤如下:

1)添加激励测试文件,点击Project下的Add Source;

 

紫光同创

 

2)点击Add or create simulation sources并"Next";

 

紫光同创

 

3)在弹出的对话框中输入激励文件的名字,这里我们输入名为vtf_led_test,其它按下图设置;

 

紫光同创

 

4)点击OK按钮返回。

 

紫光同创

 

5)这里我们先不添加IO Ports,点击OK。

 

紫光同创

 

6)在Simulation目录下多了一个刚才添加的vtf_led_test文件。双击打开这个文件,可以看到里面只有module名的定义,其它都没有。

 

紫光同创

 

7) 接下去我们需要编写这个vtf_led_test.v文件的内容。首先定义输入和输出信号,然后需要实例化led_test模块,让led_test程序作为本测试程序的一部分。再添加复位和时钟的激励。完成后的vtf_led_test.v文件如下:

`timescale1ns/1ns//////////////////////////////////////////////////////////////////////////////////// Module Name: vtf_led_test//////////////////////////////////////////////////////////////////////////////////module vtf_led_test;// Inputsreg sys_clk;reg  rst_n;// Outputswire[3:0] led;// Instantiate the Unit Under Test (UUT)    led_test uut (.sys_clk(sys_clk),.rst_n(rst_n),.led(led));initialbegin// Initialize Inputs        sys_clk =0;
        rst_n =0;// Wait 100 ns for global reset to finish#1000;
          rst_n =1;// Add stimulus here#20000;//  $stop;endalways#10 sys_clk =~ sys_clk;//20ns,endmodule

8) 编写好后保存,vtf_led_test.v自动成了这个仿真的顶层了,它下面是设计文件led_test.v;

 

紫光同创

 

9)接下来设置PDS的仿真配置,在软件菜单Project->Project Setting,然后在弹出的界面中进行如下设置,注意仿真库的路径在《00.Pango Design Suite 2020.3安装》教程中已介绍。,设置好后单击OK。

 

紫光同创

 

10)右击仿真文件并在下拉菜单中选择Run Behavioral Simulation。这里我们做一下行为级的仿真就可以了。

 

紫光同创

 

如果没有错误,PDS会调用Modelsim仿真软件开始工作了。

11)在弹出仿真界面后如下图,界面是仿真软件自动运行到仿真设置的50ms的波形。

 

紫光同创

 

由于LED[3:0]在程序中设计的状态变化时间长,而仿真又比较耗时,在这里观测timer[31:0]计数器变化。把它放到Wave中观察(点击界面中的uut, 再右击右侧timer, 在弹出的下拉菜单里选择Add Wave)。

 

紫光同创

 

添加后timer显示在Wave的波形界面上,如下图所示。

 

紫光同创

 

12)点击Restart按钮复位一下,再点击Run All按钮。(需要耐心!!!),可以看到仿真波形与设计相符。

 

紫光同创紫光同创

 

我们可以看到led的信号会逐一变1,说明LED1~LED4灯逐个熄灭。

这里为止,我们的第一个项目就圆满完成了,相信您也掌握了PDS的FPGA开发的整个流程,再也不是那个FPGA的门外汉了吧! 师傅领进门,修行还需要靠本身!PDS软件的一些技巧的使用和掌握就需要靠大家在长期实践和探索中慢慢熟悉了。

5. 附录

led_test.v(verilog代码)

`timescale1ns/1psmodule led_test(
	input           sys_clk,// system clock 50Mhz on board	input           rst_n,// reset ,low active	outputreg[3:0] led            // LED,use for control the LED signal on board);//define the time counterreg[31:0]      timer;// cycle counter:from 0 to 4 secalways@(posedge sys_clk ornegedge rst_n)begin
	if(~rst_n)
		timer <=32'd0;//when the reset signal valid,time counter clearing	elseif(timer ==32'd199_999_999)//4 seconds count(50M*4-1=199999999)		timer <=32'd0;//count done,clearing the time counter	else
		timer <= timer +1'b1;//timer counter = timer counter + 1end// LED controlalways@(posedge sys_clk ornegedge rst_n)begin
	if(~rst_n)
		led <=4'b0000;//when the reset signal active	elseif(timer ==32'd49_999_999)//time counter count to 1st sec,LED1 lighten		led <=4'b0001;
	elseif(timer ==32'd99_999_999)//time counter count to 2nd sec,LED2 lighten		led <=4'b0010;
	elseif(timer ==32'd149_999_999)//time counter count to 3rd sec,LED3 lighten		led <=4'b0100;
	elseif(timer ==32'd199_999_999)//time counter count to 4th sec,LED4 lighten		led <=4'b1000;endendmodule

注意:在定义寄存器时,如果寄存器在always块里使用必须定义为reg类型,如果仅是用于连线或是直接赋值需定义为wire类型,输入信号的类型不能定义为reg型,不管是reg类型信号还是wire类型的信号,定义的寄存器宽度必须满足使用时的需要,但必须稍大于或等于需要使用的位宽。若定义寄存器位宽远远大于使用需求则会浪费资源,如果定义的位宽小于使用需求,则会造成数据位截断,导致程序错误。还有其他信号的类型及用法请大家参考Verilog语法教程。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分