自学前端设计——【开源骚客】FPGA超详细入门视频教程

前言

本文基于【开源骚客】FPGA超详细入门视频教程,简单做个笔记

00. FPGA开发软件的安装

  • Quartus II 13.1
  • Modelsim
  • Notepad++
  • Vim
    在这里插入图片描述

01. 我的第一个FPGA工程:点亮led

led.v
//led.v
module led(
			output wire     led0       ,//ctrl+D快速复制当前行
			output wire     led1       ,
			output wire     led2       ,
			output wire     led3       
);

// EP4CE6E22CBN 是FPGA开发板上的型号。

assign     led0  = 0;
assign     led1  = 0;
assign     led2  = 0;
assign     led3  = 0;

endmodule
pin planner

在这里插入图片描述

初次下载代码到FPGA时,需要给下载器安装驱动,Altera USB-Blaster。
驱动目录选择Quartus安装目录下的drivers即可。

下载到板子上

在这里插入图片描述

在这里插入图片描述

03. Verilog HDL语法

在这里插入图片描述
在这里插入图片描述

test.v
module	test(
		input				port_a			,		//只有wire,没有reg型
		input				port_b			,		//只有wire,没有reg型
		input				port_c			,		//只有wire,没有reg型
		output	wire		port_d			,		//默认为wire
		output	wire		port_e			,
		output	wire		port_f			,
		output	wire		port_g			,
		output	wire		port_h
);

//assign: 对wire型进行赋值
//always:对reg 型进行赋值

assign port_d	=		port_a	&	port_b;
assign port_e	=		port_a	|	port_c;
assign port_f	=		~port_a;
assign port_g	=		port_b ^ port_c;
assign port_h	=		port_a ^~ port_c;

endmodule

04. Modelsim 进行仿真(小编在这里用的questasim)

在这里插入图片描述
在这里插入图片描述

tb_test.v
`timescale		1ns/1ns       // 时间单位 / 时间精度

module	tb_test;

reg				test_a;
reg				test_b;
reg				test_c;

wire			rslt_d;
wire			rslt_e;
wire			rslt_f;
wire			rslt_g;
wire			rslt_h;

// initial 赋值的信号,必须定义成reg型
initial begin
		test_a	=		1;		// 在0时刻赋初值
		test_b	=		1;		
		test_c	=		1;	
		#5
		test_a	=		0;		// 在5时刻赋初值
		test_b	=		1;		
		test_c	=		1;	
		#5
		test_a	=		0;		// 在10时刻赋初值
		test_b	=		0;		
		test_c	=		0;	
end

test		test_inst(
		.port_a			(test_a			),		//只有wire,没有reg型
		.port_b			(test_b			),		//只有wire,没有reg型
		.port_c			(test_c			),		//只有wire,没有reg型
		.port_d			(rslt_d			),		//默认为wire
		.port_e			(rslt_e			),
		.port_f			(rslt_f			),
		.port_g			(rslt_g			),
		.port_h       	(rslt_h			)
);                    


endmodule
wave

在这里插入图片描述

05. verilog 语法讲解2(二选一选择器)

在这里插入图片描述

  • 上面这个图,是一个简单的、由一个信号控制的选择器,设计代码如下:
switch_2to1.v(一部分)
module	switch_2to1(
		input				sel				,		//只有wire,没有reg型
		input				data_a			,		//只有wire,没有reg型
		input				data_b			,		//只有wire,没有reg型
		output	wire		data_c					//默认为wire
);

//wire -- >  assign: 对wire型进行赋值

assign data_c	=		(sel == 0) ?  data_a	 :	data_b;

//assign 目标信号 = (判断表达式) ? (判断表达式为真时执行) : (判断表达式为假时执行);
//


endmodule
  • 下面将采取两个选择信号,完成选择,设计和验证代码如下:
switch_2to1.v(扩充)

在这里插入图片描述
在这里插入图片描述

module	switch_2to1(
		input				sel_a			,		
		input				sel_b			,		
		input				data_a			,		
		input				data_b			,		
		output	wire		data_c			,		//wire -- assign
		output	reg			data_d					//reg  -- always
);

//wire -- >  assign: 对wire型进行赋值

assign data_c	=		(sel == 0) ?  data_a	 :	data_b;

//assign 目标信号 = (判断表达式) ? (判断表达式为真时执行) : (判断表达式为假时执行);
//
assign data_c =		 (sel_a == 0) ? ((sel_b == 0) ? data_a : 0):((sel_b == 1) ? data_b : 0);

//always --> 对reg型进行赋值
//if_else是就近配对
//可以用*替代 =s el_a or sel_b or data_a or data_b
always @(*)begin
		if(sel_a == 0)
				if(sel_b == 0)
						data_d	=		data_a;
				else 
						data_d	=		0;
		else	 //sel_a = 1
				if(sel_b == 1)
						data_d	=		data_b;
				else 
						data_d	=		0;

end

endmodule
testbench

在这里插入图片描述

`timescale 1ns/1ns
module	tb_switch_2to1;

reg			sel_a			;
reg			sel_b			;
reg			data_a			;
reg			data_b			;
wire		data_c			;
wire		data_d			;

initial begin
	sel_a  =	0;
    sel_b  =	0;
    data_a =	1;
	data_b =	0;
	#5
	sel_a  =	1;
    sel_b  =	0;
    data_a =	1;
	data_b =	0;
	#5
	sel_a  =	0;
    sel_b  =	1;
    data_a =	0;
	data_b =	1;
	#5
	sel_a  =	1;
    sel_b  =	1;
    data_a =	0;
	data_b =	1;
end

switch_2to1		switch_2to1_inst(
		.sel_a			(sel_a ),		
		.sel_b			(sel_b ),		
		.data_a			(data_a),		
		.data_b			(data_b),		
		.data_c			(data_c),		//wire -- assign
		.data_d			(data_d)		//reg  -- always
);


endmodule

在这里插入图片描述

06.verilog语法讲解3(三八译码器)

在这里插入图片描述

  • 三八译码器的设计代码如下:
decode_3to8.v
module decode_3to8(
		input			[ 2:0]	pi_data			,
		output	reg		[ 7:0]	po_data
);

always	@(*)begin
		case(pi_data)
				0:		po_data =	1;  //8'b0000_0001
				1:		po_data =	2;  //8'b0000_0010
				2:		po_data =	4;  //8'b0000_0100
				3:		po_data =	8;  //8'b0000_1000
				4:		po_data =   16; //8'b0001_0000
				5:		po_data =	32; //8'b0010_0000
				6:		po_data =	64; //8'b0100_0000
				7:		po_data =	128;//8'b1000_0000
				default:po_data =	1;
		endcase	
end
endmodule

对应的testbench如下:

tb_decode_3to8.v
`timescale 1ns/1ns

module tb_decode_3to8;

reg		[2:0]		pi_data;

wire	[7:0]		po_data;

initial begin
		pi_data =		0;
		#5
		pi_data =		1;
		#5
		pi_data =		2;
		#5
		pi_data =		3;
		#5
		pi_data =		4;
		#5
		pi_data =		5;
		#5
		pi_data =		6;
		#5
		pi_data =		7;
end


decode_3to8		decode_3to8_inst(
		.pi_data			(pi_data),
		.po_data            (po_data)
);

endmodule

07.让LED灯闪起来

  • 设计代码如下:
flash_led.v
module flash_led(
		input				sclk			,
		input				s_rst_n			,
		output	reg	[3:0]	led				
);

//EP4CE6E22CBN这是FPGA开发板上的型号。
//50Mhz
//T = 1_000_000_000 /50_000_0000 = 20ns

reg			[25:0]				cnt;

// 50_000_000 - 1 =49_999_999
// 0 - 49_999_999 0

//always用时钟沿进行工作,<=赋值
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				cnt		<=		'd0;
		else if(cnt == 'd49_999_999)
				cnt		<=		'd0;
		else
				cnt		<=		cnt + 1'b1;
end

//0-1-0-1-0
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				led		<=		4'b0000;
		else if(cnt == 'd49_999_999)
				led		<=		~led;
end
endmodule
  • 下载到板子上,同01中所提到的。

08.verilog语法讲解4()

tb_flash_led.v
`timescale 1ns/1ns

module tb_flash_led;

reg			sclk;
reg			s_rst_n;
wire  [3:0]	led;


initial begin
		sclk	=		1;
		s_rst_n <= 		0;
		#100
		s_rst_n <=		1;
end


always	#5	sclk	=	~sclk;

flash_led	flash_led_inst(
		.sclk			(sclk	),	//system clock
		.s_rst_n			(s_rst_n	),  //system rst_n,active low
		.led			(led	)	
);
endmodule
  • 如上所述,设计中用到的49_999_999太长,可以改成49观察,最后改回去,启用参数的延迟代码如下:
//flash_led.v
module flash_led(
		input				sclk			,
		input				s_rst_n			,
		output	reg	[3:0]	led				
);

//localparam		DELAY_1S		=			'd49_999_999		;
localparam		DELAY_1S		=			'd49				;

//EP4CE6E22CBN这是FPGA开发板上的型号。
//50Mhz
//T = 1_000_000_000 /50_000_0000 = 20ns

reg			[25:0]				cnt;

// 50_000_000 - 1 =49_999_999
// 0 - 49_999_999 0

//always用时钟沿进行工作,<=赋值
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				cnt		<=		'd0;
		else if(cnt == DELAY_1S)
				cnt		<=		'd0;
		else
				cnt		<=		cnt + 1'b1;
end

//0-1-0-1-0
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				led		<=		4'b0000;
		else if(cnt == DELAY_1S)
				led		<=		~led;
end
endmodule

阻塞赋值(=)和非阻塞赋值(<=)

  • 简单讲,always块中有时钟沿就用非阻塞赋值<=),时序电路
  • 没有时钟沿就用 阻塞赋值(=),组合电路
    在这里插入图片描述
  • 下面的这个例子tx_en.v,就是对这段话作解释的!
tb_ex.v
`timescale 1ns/1ns

module tb_ex;

reg			a;
reg			b;
reg			c;
reg			d;
reg			e;
reg			f;

initial begin
		a	=		1;
		b	= 		0;
		c	=		a + b;
end

initial begin
		d	<=		1;
		e	<= 		0;
		f	<=		d + e;
end
endmodule
  • 这段代码仿真的波形如下,很容易看出阻塞和非阻塞是不一样的。
    在这里插入图片描述

组合逻辑和时序逻辑

在这里插入图片描述

09.FPGA实现流水灯

  • { }位拼接操作符
    在这里插入图片描述
    在这里插入图片描述

  • 此处使用位拼接符,简化了代码,与前面的代码相比,变动不大。

shift_led.v
module shift_led(
		input				sclk			,
		input				s_rst_n			,
		output	reg	[3:0]	led				
);

//localparam		DELAY_1S		=			'd49_999_999		;
localparam		DELAY_1S		=			'd49				;

//EP4CE6E22CBN这是FPGA开发板上的型号。
//50Mhz
//T = 1_000_000_000 /50_000_0000 = 20ns

reg			[25:0]				cnt;

// 50_000_000 - 1 =49_999_999
// 0 - 49_999_999 0

//always用时钟沿进行工作,<=赋值
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				cnt		<=		'd0;
		else if(cnt == DELAY_1S)
				cnt		<=		'd0;
		else
				cnt		<=		cnt + 1'b1;
end

//0-1-0-1-0
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				led		<=		4'b1110;
		else if(cnt == DELAY_1S)
				led		<=		{led[2:0],led[3]};
end
endmodule
tb_shift_led
`timescale 1ns/1ns

module tb_shift_led;

reg			sclk;
reg			s_rst_n;
wire  [3:0]	led;


initial begin
		sclk	=		1;
		s_rst_n <= 		0;
		#100
		s_rst_n <=		1;
end


always	#5	sclk	=	~sclk;

shift_led	shift_led_inst(
		.sclk			(sclk	),	//system clock
		.s_rst_n			(s_rst_n	),  //system rst_n,active low
		.led			(led	)	
);
endmodule

在这里插入图片描述

10-11.实现呼吸灯原理(PWM)

[“流水灯”升级,基于FPGA的呼吸灯设计](http://dengkanwen.com/24.html)
在这里插入图片描述

  • 逐渐变亮:
    在这里插入图片描述
  • 逐渐变暗(cnt_2ms >= cnt_2s)
    在这里插入图片描述
    在这里插入图片描述
breath_led.v
module breath_led(
		input				sclk			,
		input				s_rst_n			,
		output	reg	[3:0]	led				
);

/* localparam		DELAY_2US			=			'd99;
localparam		DELAY_2MS			=			'd999;
localparam		DELAY_2S			=			'd999; */

localparam		DELAY_2US			=			'd9;
localparam		DELAY_2MS			=			'd99;
localparam		DELAY_2S			=			'd99;

reg			[ 6:0]				cnt_2us			;
reg			[ 9:0]				cnt_2ms			;
reg			[ 9:0]				cnt_2s			;
reg								flag_2s			;


always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				cnt_2us		<=		'd0;
		else if(cnt_2us == DELAY_2US)
				cnt_2us		<=		'd0;
		else
				cnt_2us		<=		cnt_2us + 1'b1;
end

// cnt_2us = 9,cnt_2ms = 99
// 小范围条件写前面,大范围条件写后面
always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				cnt_2ms		<=		'd0;
		else if(cnt_2ms == DELAY_2MS && cnt_2us == DELAY_2US)
				cnt_2ms		<=		'd0;
		else if(cnt_2us == DELAY_2US)
				cnt_2ms		<=		cnt_2ms + 1'b1;
		
end

always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				cnt_2s		<=		'd0;
		else if(cnt_2s	== DELAY_2S && cnt_2ms == DELAY_2MS && cnt_2us == DELAY_2US)
				cnt_2s		<=		'd0;
		else if(cnt_2ms == DELAY_2MS && cnt_2us == DELAY_2US)
				cnt_2s		<=		cnt_2s + 1'b1;
		

end

always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				led			<=		4'b1111;
		else if(cnt_2s >= cnt_2ms && flag_2s == 1'b0)		//逐渐变亮
				led			<=		4'b0000;
		else if(cnt_2s <= cnt_2ms && flag_2s == 1'b1)		//逐渐变暗
				led			<=		4'b0000;
		else
				led			<=		4'b1111;
end

always	@(posedge sclk or negedge s_rst_n)begin
		if(s_rst_n == 1'b0)
				flag_2s		<=		1'b0;
		else if(cnt_2s	== DELAY_2S && cnt_2ms == DELAY_2MS && cnt_2us == DELAY_2US)
				flag_2s		<=		~flag_2s;
end
endmodule
tb_breath_led.v
`timescale 1ns/1ns

module tb_breath_led;

reg			sclk;
reg			s_rst_n;
wire  [3:0]	led;


initial begin
		sclk	=		1;
		s_rst_n <= 		0;
		#100
		s_rst_n <=		1;
end


always	#5	sclk	=	~sclk;

breath_led	breath_led_inst(
		.sclk			(sclk	),	//system clock
		.s_rst_n		(s_rst_n	),  //system rst_n,active low
		.led			(led	)	
);
endmodule

12-13. 按键控制流水灯

在这里插入图片描述
#后续更新代码

14. TOP-DOWN(自顶向下)设计思想

#后续更新代码

15. FPGA开发流程

  1. 设计定义:明确项目用FPGA需要实现的功能,指标、性能等,进行模块划分
  2. 设计输入:根据第一步的想法和思路,开始代码设计(代码: verilog,VHDL,原理图方式)
  3. 功能仿真:对第二步设计的仿真(Modelsim)
  4. 逻辑综合
  5. 布局布线
  6. 验证在布局布线后,时序是否违例:后仿真或静态时序分析
  7. 上板验证,看FPGA否能接照最初的想法实际跑起来
    在这里插入图片描述

在这里插入图片描述

后仿真用的不是很多

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
简介: FPGA技术经过20多年的发展,现在已经被应用到各个领域,并且正在逐渐成为越来越多领先技术的系统级解决方案。为了帮助从事或者即将从事FPGA设计的工程师尽快的了解FPGA技术,掌握设计的方法和手段,华清远见针对FPGA的初学者设计了这个视频教程。通过对FPGA技术的阐述,分析典型器件的特点,教授FPGA设计的常用方法及开发的基本流程,并通过简明合理的实验,帮助学员掌握相关设计工具的使用方法及FPGA硬件平台的常用调试手段。 本课程将对FPGA的相关基础概念、工艺特点、FPGA基本结构及选型策略进行讲解,结合开发工具及硬件平台使学员掌握FPGA设计方法和设计流程。在基础方面,掌握FPGA的结构特点及典型型号;在硬件设计方面,掌握FPGA PCB设计的要点;逻辑设计方面,掌握Verilog语言设计的要点;在调试方面,掌握工具的基本操作及常用软硬件协同调试手段。 主讲人:姚远老师,华清远见高级讲师,北京航空航天大学自动化专业博士学位,有8年的FPGA和DSP系统硬件开发经验,成功开发了卫星载高速图像压缩系统、红外图像采集压缩和传输系统、基于MPEG4/H.264的网络监控系统、高速(1GHz)并行(4颗)DSP图像处理系统,大规模高速500万门FPGA验证平台(Altera StratixII EP2S180)。 主要内容: 1、红色飓风FPGA入门普及活动 第一讲、FPGA设计基础 第二讲、FPGA设计入门 第三讲、VerilogHDL基础 第四讲:Verilog HDL中的组合逻辑设计方法 第五讲:ModelSim软件使用方法和技巧 第六讲、Sopc硬件系统 第七讲、sopc软件系统 2、红色飓风FPGA入门普及活动 第1讲:FPGA系统设计基础 第2讲:从零开始设计FPGA最小系统一:核心电路 第3讲:从零开始设计FPGA最小系统二:外围电路 第4讲:Verilog HDL语法一:常用语句 第5讲:Verilog HDL语法二:任务与函数 第6讲:Verilog HDL语法三:有限状态机 第7讲:QuartusII 7.2设计入门 第8讲:NIOSII 7.2设计入门 第9讲:FPGA系统设计技巧-乒乓操作 第10讲:FPGA设计常用IP核-锁相环 3、其它 2006年5月27日姚老师《FPGA技术与数字系统设计基础》视频 2006年9月17日姚老师《基于FPGA的数字视频图像处理系统设计方法》视频 2007年4月21日姚老师《FPGA在视频图像处理领域的应用》视频 2007年7月14日姚老师《FPGA硬件最小系统设计》视频 2007年8月25日陆老师《FPGA系统设计的主要思路和方法初探》视频 2008年5月24日潘老师《Xilinx FPGA开发要点介绍》视频 2008年5月24日姚老师《Altera FPGA的选型及开发》视频 2008年5月24日姚老师《FPGA在视频处理领域的应用》视频 2008年11月01日陆阳老师《FPGA设计的良好设计方法及误区》视频 2008年11月29日姚远老师《FPGA的高端应用案例》视频

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杰之行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值