找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 3151|回复: 4

【FPGA】我的第一个FPGA程序

[复制链接]
发表于 2019-12-8 20:41:43 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
FPGA是Field Programmable Gate Array,翻译过来叫“场可编程门阵列”。FPGA被用于设计各种高性能集成电路——比起运行C语言程序的单片机,FPGA拥有更高的自由度和更高的开发难度。FPGA编程使用硬件描述语言,主要使用两种编程语言,一个是VHDL,一个是Verilog HDL。注意VHDL并非Verilog HDL的缩写,它们俩是不同的语言。VHDL的“V”是VHSIC的缩写,Very High Speed Integrated Circuits,意为“相当快的集成电路”、“贼他妈快的集成电路”。使用硬件描述语言编写FPGA程序,然后将其烧录到FPGA芯片上后,FPGA芯片的行为就会变成如你所描述的硬件一样工作了。

比FPGA更屌的是ASIC,Application Specific Integrated Circuit,专用集成电路。FPGA是可编程门电路,而ASIC是“不可编程”的,也就是一旦生产出来,它就“定型”了。现在的GPU就是一种ASIC。给ASIC编写硬件描述语言,似乎只能使用Verilog HDL而非VHDL。

Verilog HDL编程语言比VHDL历史更悠久,而且,对于掌握了C语言的人而言,似乎学习起来更加轻松一些。但由于一些不可抗的运气相关的因素,我最先接触的是VHDL,而且我还试着在接触它的第一天就用它写东西出来玩。

我的入门用的FPGA设备是如下图这样的玩意儿:



这玩意儿名叫Cyclone II EP2C5T144开发板。这玩意儿似乎很容易被买到、很流行且还算廉价。然而我并没有成功给它买到能装上去的SDRAM模块,所以暂时计划用它去做一些简单的实例。
注意它的供电的地方,也就是如下图圈出来的那个三极管,贼容易变烫,摸到它的时候你很可能会被烫得吓一跳。

gongdian.jpg

烧录它的工具是一个叫USB Blaster的玩意儿。

IMG_3570(20191208-193451).jpg

然后我使用的软件是Quartus II 13.0.1 网络版(免费版)(点击可以跳转到下载页帖子),挺大的,安装需要花费一些时间。这个软件我还没怎么玩熟悉。

启动的时候会弹出这个(你们的会和我的不太一样):

newinst.png

选“Create a New Project”,然后会弹出一个向导,一步步来。
其中下图这个页面是让你选工程名字和存储位置的,这里要注意一下。第一栏是你的工程存储位置,第二栏是工程名字,第三栏通常会跟着第二栏自动被填写,但你也可以改成别的。

20191208194956.png

然后如果你已经有现成的写好了的hdl文件的时候,是可以在下面这个页面里加入的。但也可以留到后面再往工程里面加文件。

20191208195133.png

下面这个页面是让你选择你的设备和型号的。我的是EP2C5T144C8,所以我输入了以后,它有这个设备。选中它即可。

20191208195241.png

下面这一页EDA Tool Settings里面的Simulation要将其选择为ModelSim-Altera。如果你用的软件是从我上面给出的链接里下载的话,你肯定有ModelSim仿真器软件,这里你要选择使用ModelSim仿真器,不然你调试你的RTL很麻烦。

20191208195542.png

最后这一页是一个总结,大致看看没有问题(主要检查文件路径、FPGA板子型号等)的话,就可以Finish了。

20191208195654.png

创建好了工程以后,你的软件界面是这个样子的。要开始你的FPGA开发,你需要给这个工程添加若干HDL文件,让它编译,然后就可以调试或者烧录了。

20191208195734.png

直接点这里的新建文件按钮,然后选择VHDL文件,就可以开始编写VHDL了。

new.png

20191208195938.png

顺手就来一段。其实,Quartus II要求你实现一个和工程同名的entity后,才能完全编译通过并且完成分析。

20191208200829.png

按Ctrl+S保存,注意勾上“Add file to current project”,把这个文件顺手加入到工程里。

20191208200955.png

然后就可以试着编译一下看看了,在菜单栏找到Processing -> Start Compilation,它就能编译。

20191208201130.png

完成编译后,找到菜单栏的Assignments -> Pin Planner,指定你的每个输入输出对应的Pin。

20191208201300.png

这块板子的时钟是接到Pin 17上,然后三个LED分别为Pin 3,Pin 7,Pin 9,并且按钮是Pin 144。
而其中我接下来打算写着玩儿的UART串口的两个Pin则是我随便指定的Pin 40和Pin 41。

pp.png

上述代码其实我只是随便写了一下,但感觉可以写个跑马灯一样的玩意儿来做测试。

20191208204825.png

代码如下:
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;

entity myuart is
        generic
        (
                g_Clk_Freq : Integer := 50000000 -- Cyclone II EP2C5T144C8的板子自带的时钟是50MHz
        );
        port
        (
                i_Clk                : in std_logic; -- 输入时钟,用于驱动整个机器工作
                i_NReset        : in std_logic; -- 重置信号,在板子上是Pin 144,连接一个按钮,按下后信号会变为'0'
                
                -- 三个LED,分别为Pin 3,Pin 7,Pin 9
                o_LED1        : out std_logic;
                o_LED2        : out std_logic;
                o_LED3        : out std_logic;
                
                -- 串口信号,我打算用Pin 40和Pin 41作为串口的TX和RX
                o_UART_TX        : out std_logic;
                i_UART_RX        : in std_logic
        );
end myuart;

architecture rtl of myuart is
        signal r_LED_Status : std_logic_vector(2 downto 0) := "111";
        constant c_LED_Blink_Freq : integer := 5; -- 每秒钟灯动的频率
        constant c_LED_Blink_Clks : integer := g_Clk_Freq / c_LED_Blink_Freq;
        signal r_Clk_Count : integer range 0 to c_LED_Blink_Clks - 1 := 0;
begin
        o_LED1 <= r_LED_Status(0);
        o_LED2 <= r_LED_Status(1);
        o_LED3 <= r_LED_Status(2);
        
        p_Main: process(i_Clk)
        begin
        if rising_edge(i_Clk) then -- 每个时钟的上升沿执行一次
                        if i_NReset = '1' then -- 没有按下重置按钮的话
                                if r_Clk_Count < c_LED_Blink_Clks - 1 then -- 使用计数器进行时钟计数
                                        r_Clk_Count <= r_Clk_Count + 1; -- 计数器递增
                                else
                                        r_Clk_Count <= 0; -- 计数器增满了,则让三个灯的状态动一下,并重新计数
                                        
                                        if r_LED_Status = "111" then -- 全灭的话,就亮起一盏
                                                r_LED_Status <= "110";
                                        else -- 否则让灯移动一格
                                                r_LED_Status <= r_LED_Status(1 downto 0) & "1";
                                        end if;
                                        
                                end if;
                        else
                                r_Clk_Count <= 0;
                                r_LED_Status <= "111";
                                
                        end if;
                end if;
        end process p_Main;
end rtl;
接下来准备烧录。将USB Blaster插上电脑,然后把另一头插到AS插槽。

IMG_3571(20191208-203151).jpg

然后打开Tools -> Programmer。它如果没问题的话会自动识别你的USB Blaster,而如果你是先打开的Programmer再插入的USB Blaster的话,也可以点“Hardware Setup”然后选中你的USB Blaster。
Mode那里将烧录模式设为Active Serial Programming,然后左边找到Add File,把你编译好的pof文件加入进来即可。注意编译好的pof文件在工程目录下的output_files文件夹内。

20191208203637.png

20191208203700.png

在加入了pof文件后,别忘了勾上Program / Configure、Verify、Blank - Check 三个选项(其实主要是第一个必须勾上)

20191208203832.png

然后点Start就可以完成烧录了。

20191208203914.png

顺手按个Ctrl+S把烧录器的配置也保存一下。

20191208204013.png

接下来可以拔掉USB Blaster了,然后插上供电,就可以看到运行效果了。




其实光看物理效果还不够爽,因为你可能会觉得自己面对的这个黑盒子依然如同黑魔法一般令人感到不安和困惑。此时我们打开仿真器看看它的工作情况吧。
运行Tools -> Run Simulation Tool -> RTL Simulation,然后这个时候ModelSim Altera就冒了出来。

20191208210816.png

其实ModelSim很可能冒不出来,你会遇到一条错误消息,说Quartus II并不知道你的ModelSim被安装到哪里了。此时在Quartus II的主菜单上找到Tools -> Options打开选项对话框如下。

20191208210958.png

然后找到EDA Tool Options,你可以看到它所有栏都是空的。找到ModelSim-Altera的栏,然后点最右边的“...”按钮,定位到你的Quartus II的安装文件夹,在它里面有modelsim_ase文件夹。将modelsim_ase文件夹内的win32aloem文件夹的路径作为这一栏的内容即可,如下(我的Quartus II被安装到了I盘)。

20191208211214.png

之后点OK退回,再找到菜单的Tools -> Run Simulation Tool -> RTL Simulation,没问题的话ModelSim Altera就会冒出来。从左边的Library里面找到work,点开后可以看到我们刚才创建的工程myuart,双击它,你会看到Objects里面多了很多东西。

20191208211513.png

在Objects里面选中第一个,然后按住Shift并点选最后一个,就能选中全部,然后右键菜单 -> Add Wave。此时右边会出来一个波形图,但里面没有显示出波形。

aw.png

wv.png

这些波形是需要我们设置输入的,改变输入,它才会有输出。我们需要输入一个时钟信号,一个重置信号,一个UART的输入信号。但我们并没有编写UART的RX的部分,所以先不管它。先设置时钟信号。鼠标在i_Clk右键菜单 -> Clock

clk.png

设置时钟输入的Period(周期)为2(它默认是100),然后点OK,i_Clk之后就会被自动输入一个时钟。

20191208212226.png

因为我们的重置信号是低激活,我们不想让它保持重置,所以设置它保持为“高”即可。右键菜单 -> Force,将Value设置为1,然后点OK。

20191208212344.png

接下来基本上算是万事俱备了。按下F9,波形就出来了。多按几下F9的话,它就会出来更长的波形。

w.png

但是看起来波形很密。此时按I可以放大,按O可以缩小。按I放大后,可以明确地观察到各个信号量的变化。
注意看下面显示的时间轴,单位是ps,皮秒,也就是1000分之一纳秒,1000000分之一微秒,1000000000分之一毫秒,1000000000000分之一秒。这么短的时间里,就连真空中的光速,也只能直线穿行大约0.3毫米的距离。

wave.png

但其实,这只是因为我把时钟输入的i_Clk的周期(Period)设置为每2ps一个周期而已。我这样做,只是为了让波形图尽可能地短,以便于更好地观察波形。但实际上,我们的设备在物理上并没有这么快的响应速度,尤其是我们在VHDL代码里使用的那个integer,它的累加计算并不能做到这么快(以500 GHz的频率不断地进行二进制整数的加法)。

光速,或者电磁波在真空中的传播速度,虽然我们在初高中学习的教科书内容里,被定义为每秒约30万公里,但电磁波在不同的媒介里的传播速度是不一样的。此外,很多人都误以为电流在导线里传播的速度等同于光速,但其实不是。导线的材料、密度、粗细、阻抗等各项因素都会影响电流在导线里的传导速度,而且电流在导线里的传播速度远没有光速快。

事实上,除了电流传播速度影响硬件的运行能力以外,门电路的响应速度和充能、饱和过程也需要消耗时间,而且消耗的时间的量还受到电压大小的影响。

eyeimg.png

所以,ModelSim在这个阶段进行的RTL模拟过程,是在对我们设计的架构进行逻辑层面上的模拟。实际的运行必须要经过硬件测试才能知道真正的效果。
回复

使用道具 举报

发表于 2019-12-8 21:13:16 | 显示全部楼层
可以吃吗?可以赚钱吗?
可以装逼泡妞吗?
回复 赞! 靠!

使用道具 举报

发表于 2019-12-8 21:15:43 | 显示全部楼层
我写软件的,感觉寂寞,身边没人会编程,找不到朋友,
站长搞这个,怕是更加寂寞吧
回复 赞! 靠!

使用道具 举报

发表于 2019-12-10 22:28:10 | 显示全部楼层
目前实用性高些的是带MCU的FPGA,比如国产的CME-M5,带个200M的8051硬核,我之前买过这个芯片的开发板.不过一直没时间折腾....
回复 赞! 靠!

使用道具 举报

 楼主| 发表于 2020-4-25 16:22:47 | 显示全部楼层
嗷嗷叫的老马 发表于 2019-12-10 22:28
目前实用性高些的是带MCU的FPGA,比如国产的CME-M5,带个200M的8051硬核,我之前买过这个芯片的开发板.不过一 ...

我甚至想自己写一个自带MCU的逻辑代码,然后我想写ARMv7的
回复 赞! 靠!

使用道具 举报

本版积分规则

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-11-21 20:40 , Processed in 0.037658 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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