去年从同学那里要了一块FPGA的空板,最近没什么事,所以就按着电路图在淘宝上买了一些需要的元器件,主芯片是ALTERA的EP2C5Q208C8,4800个LE,对于我一个初学者足够了。
焊完板子,我先测设了一下电源部分,3.3V和1.2V都正常,没有短路现象,然后用Quartus 8.0打开一个简单的例子(用verilog hdl 编写的,参考网上的),然后在网上找了一下Quartus 8.0的基本操作,竟然直接编译成功了,然后我将从淘宝上买的并口的ByteBlaster2连接上开发板,下载也成功了,板子看不出来什么现象,可能是由于程序功能或者管脚未配置的原因,但至少说明最小系统加JTAG功能好用。当时还不是特别明白AS下载方式和JTAG下载方式的区别。
我不是特别喜欢看书,我喜欢直接实践,在实践中会有一些感性的体会,所以我先下载了一些Quartus 8.0的使用教程然后一步一步的操作,渐渐体会出每一步的作用是什么,对整个开发过程也有了一些实实在在的认识: 编写输入文件(包括hdl语言和图像符号等方式)------编译和综合(综合就是将行为的功能的描述转化为与或非门级的形式)------布局布线(好像还包括综合后的优化,去除一些综合后的冗余逻辑)-------生成编程文件---------时序分析。大概这就是一个工程开发的整个过程。
在学习hdl时,我选择了Verilog HDL ,因为简单易懂,和C有些类似,关键是要体会HDL语言是硬件描述语言,最后设计的功能要转化为实在的电路,这里的关键是理解并行的概念,在Verilog模块中所有过程块(如inital块、always块)、连续赋值语句assign、实例引用都是并行工作的。同时在模块中还存在着一些顺序块,比如在begin---end间的语句(除非阻塞赋值)。这里我对于非阻塞和阻塞还是有些理解不好,以后慢慢深入吧。教材,我用的是《Verilog数字系统设计教材》,是国内比较好的教材,里面也有不少实例,便于实践。
第一个Verilog程序: LED闪烁
module LED (out1,out2,clock); // 端口列表
output out1,out2; // 端口类型定义
input clock;
reg out1,out2; // 输出都在定义为reg,我感觉好像reg像是定义了一个锁存器,
// 输出的信号需要保持就应该用到锁存器,不知道对不对
reg [25:0] counter; // 用于分频计数,全局时钟50M
initial
begin
out1 = 1;
out2 = 0;
end
always @ (posedge clock)
begin
counter <= counter + 1;
if(counter == 26'd25000000) //25000000/50000000=0.5s
begin
out1 = ~ out1;
out2 = ~ out2;
counter <= 0;
end
end
endmodule
在这个模块中包括两个过程块,initial和always,它们是并行同时在仿真进入这个模块后开始执行的,只是initial只执行一次,而always一直在执行,不断判断着后面的条件是否满足。begin---end是个顺序块,感觉就像是{ }的作用,担任它还有更复杂的用法,比如加在begin后块名,还可以加参数,还可以用disable禁止一个顺序块。
第一个程序我感觉最大的障碍有两个地方:
1. 全局时钟 原来用单片机ARM系统的时钟直接连接到内核和片上外设,只需要从几个已有的时钟源选择再分频就可以了,可是FPGA则不同,它内部就像是一块白纸,除了电源的管脚,其他的管脚和内部电路都是没有硬链接的,所以在使用时,首先看你的硬件电路图,外部晶振连接到FPGA芯片的哪些CLK输入管脚上,然后在你的模块中将时钟源分配为这个CLK管脚,这个时钟就是你系统的全局时钟了,你的模块的执行就是在这个CLK的触发下进行的。
2. 程序的固化 JTAG至少调试接口,将镜像文件(.sof文件)下载的芯片内部的RAM里运行,然后掉电就没了,如果要固化的话,在FPGA外部需要一个EPCS4的配置芯片,通过AS接口将程序(.pof文件)下载到EPCS4中,然后当上电是,FPGA自动从EPCS4中读取配置信息,然后执行,实现了程序的固化。
第二个Verilog程序: 共阴数码管显示
module shumaguan (LED,SHU,COM,CLK);
input CLK;
output [7:0] SHU;
output [3:0] COM;
output [3:0] LED;
reg [7:0] SHU;
reg [7:0] ZIMO[9:0];
reg [3:0] index;
reg [3:0] COM;
reg [3:0] LED;
reg [25:0] counter;
initial
begin
SHU = 8'b11111100; // a b c d e f g h //0
COM = 4'b1111; // com1 com2 com3 com4
LED = 4'b0001;
ZIMO[0] = 8'b11111100; //0
ZIMO[1] = 8'b01100000; //1
ZIMO[2] = 8'b11011010; //2
ZIMO[3] = 8'b11110010; //3
ZIMO[4] = 8'b01100110; //4
ZIMO[5] = 8'b10110110; //5
ZIMO[6] = 8'b10111110; //6
ZIMO[7] = 8'b11100000; //7
ZIMO[8] = 8'b11111110; //8
ZIMO[9] = 8'b11100110; //9
index = 4'b0000;
end
always @ (posedge CLK)
begin
counter <= counter + 1;
if(counter == 26'd15000000) //15000000/50000000=0.3S
begin
counter <= 0;
/*
//direct value
case (SHU)
8'b11111100: SHU <= 8'b01100000; //0---1
8'b01100000: SHU <= 8'b11011010; //1---2
8'b11011010: SHU <= 8'b11110010; //2---3
8'b11110010: SHU <= 8'b01100110; //3---4
8'b01100110: SHU <= 8'b10110110; //4---5
8'b10110110: SHU <= 8'b10111110; //5---6
8'b10111110: SHU <= 8'b11100000; //6---7
8'b11100000: SHU <= 8'b11111110; //7---8
8'b11111110: SHU <= 8'b11100110; //8---9
8'b11100110: SHU <= 8'b11111100; //9---0
default : SHU <= 8'b11111100; // 0
endcase
*/
/* */
//index memory
SHU <= ZIMO[index];
index = index + 1;
if (index == 10)
index <= 0;
/* */
case (LED)
4'b0001: LED <= 4'b0010;
4'b0010: LED <= 4'b0100;
4'b0100: LED <= 4'b1000;
4'b1000: LED <= 4'b0001;
default: LED <= 4'b0001;
endcase
end
end
endmodule
和第一个程序基本思路差不多
这3天的收获很多,接下来打算再多花时间看看Verilog,然后开始各种通信接口的设计。
文章评论(0条评论)
登录后参与讨论