DE2-115开发板基于verilog和nioⅡ的流水灯实现

一、 内容概要

在DE2-115开发板上分别用 Verilog和 Nios软件编程两种方式完成LED流水灯显示,理解两种方式的差异

二、 实现

2.1 基于Nios II软核的流水灯

2.1.1 准备工作

  1. Quartus II
  2. DE2-115开发板
    在这里插入图片描述

2.1.2 工程搭建

  1. 打开Quartus,新建一个工程
    按照图片进行如下选择
    在这里插入图片描述
    在这里插入图片描述
    选择芯片
    在这里插入图片描述
    finish

2.1.3 硬件代码设计

Ⅰ 连接IP核

类似于以可视化界面的方式进行verilog里面的通过顶层文件连接各模块操作

找到platform Designer,某些版本可能是 Qsys
在这里插入图片描述

首先设置时钟
在这里插入图片描述
默认即为50MHZ,设置好后点右下角finish
在这里插入图片描述
左侧通过搜索栏进行搜索,添加以下模块:

Nios Ⅱ Processor (nios软核处理器)
On-Chip Memory (储存器)
JTAG UART (JTAG、UART)
System ID Peripheral (为Nios II生成一个ID号)
pio (流水灯管脚)

在这里插入图片描述
先全部点Finish保持默认
在这里插入图片描述
在这里插入图片描述
三连击Name标签下的属性可以修改名称:
在这里插入图片描述
略微修改了一下名字
在这里插入图片描述

连接模块:

clk,reset,datamaster需要和其他所有IP核连接,nios ii的指令端口(instruction_master)只与存储器进行连接,nios ii中的jtag_debug_model_reset与外部IP核进行连接 。jtag端口的中断信号的连接,其中0表示中断的优先级(可以进行设置)
在这里插入图片描述

在这里插入图片描述

接下来进行参数配置(右键模块点击edit)

  1. On-chip Memory
    设置为10k(10240)
    在这里插入图片描述
  2. nios
    在这里插入图片描述
  3. PIO
    将width设置为4表示4个Led灯
    在这里插入图片描述
    把管教名设置为led
    在这里插入图片描述

然后系统分配地址
在这里插入图片描述
完成后就不报错了
在这里插入图片描述
最后点击右下角Generate生成
在这里插入图片描述
在这里插入图片描述
然后等待
在这里插入图片描述
完成后一路finish

Ⅱ 编写代码

回到Quartus,新建一个verilog文件
在这里插入图片描述
在这里插入图片描述
写入代码

module led_ctrl(
	input clk,
	input reset_n,
	output  [3:0] led
);
Ⅲ 各种配置

在这里插入图片描述
找到生成的文件添加
在这里插入图片描述
找到这个总文件,根据管脚信息在之前写的代码里面加入:

demo2_waterled u0 (
        .clk_clk       (clk),       //   clk.clk
        .reset_reset_n (reset_n), // reset.reset_n
        .led_export    (led)     //   led.export
    );

在这里插入图片描述
这样完整的代码即为:

module led_ctrl(
	input clk,
	input reset_n,
	output  [3:0] led
);

demo2_waterled u0 (
        .clk_clk       (clk),       //   clk.clk
        .reset_reset_n (reset_n), // reset.reset_n
        .led_export    (led)     //   led.export
    );

endmodule

配置一下管脚

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后进入Dual-purpose Pins,全部设置为Use as regular I/O
在这里插入图片描述
然后编译一下
在这里插入图片描述
然后分配一下管脚
在这里插入图片描述
重新编译

2.1.4 软件代码设计

Ⅰ 环境构建

通过此处打开eclipse
在这里插入图片描述
自己选定一个工作空间(不一定是当前项目目录)
进入初始界面后创建文件
在这里插入图片描述
在这里插入图片描述
点击NEXT
在这里插入图片描述
点击Finish
完成后找到这个文件
在这里插入图片描述

Ⅱ 编写代码

把hello_world.c的代码修改为:

#include <stdio.h>
#include "system.h"
#include "altera_avalon_pio_regs.h"
#include "alt_types.h"
const alt_u8
led_data[4]={0x01,0x03,0x07,0x0F};
int main (void) {
 int count=0;
 alt_u8 led;
 volatile int i;
 while (1)
  {
 	 if (count==4)
 	 {
 		 count=0;
 	 }
 	 else
 	 {
 		 count++;
 	 }
 	 led=led_data[count];
 	 IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, led);
 	 //延时的设置
 	 i = 0;
 	 while (i<5000000)
 		 i++;
   }	
 return 0;
}

保存

而后右键waterled_bsp,再Nios II 中选择BSP Editor进行如下配置:

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0697eb0f10f54a1f95cc607c7c6d28bc.png在这里插入图片描述
在这里插入图片描述

选择Generate BSP
在这里插入图片描述
然后右键waterled,选择build project
在这里插入图片描述
完成
在这里插入图片描述

2.1.5 代码下载

Ⅰ 硬件下载

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

Ⅱ 软件下载

回到eclipse,右键waterled,选择Run As中的Nios II Hardware
在这里插入图片描述
刷新一下
在这里插入图片描述
然后先apply再run
在这里插入图片描述

2.1.6 运行结果

在这里插入图片描述

2.2 Verilog流水灯

直接编写Verilog代码

module led_ctrl(input En,input CP,input Dn,output reg [0:7] Out);//匹配8个灯,故宽度为8
reg [25:0] cnt;
reg cnt1;
reg Cn;
parameter cnt_max = 26'd49_999_999;//时钟的频率是50mhz,要实现几秒钟变一次就调到//相应时间,例子为1s每次

always@(posedge CP or negedge En)//该always循环实现的是一秒钟的计数
   if(En==1'b0)
 	cnt<=26'd0;
   else if(cnt == cnt_max)
	cnt<=26'd0;
   else 
	cnt<=cnt + 1'b1;
always @(posedge CP or negedge En) //cnt每次为1代表到了一秒钟
   if(En==1'b0)
 	cnt1<=1'b0;
   else if(cnt == cnt_max-1'd1)
	cnt1<=1'b1;
   else 
	cnt1<=1'b0;

always @(posedge CP or negedge En)
	if(En==1'b0) begin
	  if(Dn==1'b1)                  //用 Dn来判断赋不同的值,1为亮,也就可以实现两个灯一起移动的选择
 	     Out <=8'b00000001;
	  else
	     Out <=8'b00000011;
	 end
   else begin
	    if (Out[0]==1'b1)//不用判断整个Out,只需要判断最边上的1,为1则表示需要改变方向,方向由Cn判断
		      Cn<=1'b1;
		 else if(Out[7]==1'b1)
		      Cn<=1'b0;
	      if (cnt1==1'b1) begin
		      if(Cn==1'b1)
			       Out<={1'b0,Out[0:6]};//右移
			    else
			       Out<={Out[1:7],1'b0};//左移
			 end
   end


endmodule

管脚配置
在这里插入图片描述

正常编译烧录就行
结果:
在这里插入图片描述

三、 心得体会

·理解硬件与软件编程的差异:通过实践,我更深入地理解了硬件描述语言(如Verilog)和软件编程(如C语言)在FPGA设计中的应用差异。

·硬件编程的直观性:使用Verilog直接编程,可以直观地控制硬件行为,如LED的亮灭顺序,这种方式更接近底层硬件,对FPGA的资源利用和性能优化有更直接的控制。

·软件编程的便利性:Nios II软核提供了一个类似于通用处理器的环境,可以使用高级语言(如C语言)进行编程,这使得开发过程更加简便,代码更易于理解和维护。

·综合工具的重要性:无论是硬件还是软件编程,都需要依赖于综合工具(如Quartus II)来将设计部署到FPGA上。这些工具提供了图形界面和自动化流程,极大地提高了开发效率。

·学习曲线:Verilog编程可能对初学者来说有一定的难度,因为它需要对硬件电路有一定的理解。而Nios II软核编程则更容易上手,因为它使用的是更熟悉的编程语言和概念。

对比
·开发速度:使用Nios II软核进行软件编程通常开发速度更快,因为它允许开发者使用高级语言和现有的库函数。

·资源消耗:硬件编程(Verilog)通常对FPGA资源的消耗更少,因为它直接控制硬件,而软件编程可能需要更多的资源来运行软核处理器。

·性能:硬件编程可以实现更高的性能,因为它可以精细控制时序和并行操作,而软件编程可能受限于软核处理器的性能。

·灵活性与可移植性:软件编程在灵活性和可移植性方面具有优势,因为编写的软件可以在不同的硬件平台上运行,而硬件编程则更依赖于特定的FPGA架构。

·调试与测试:硬件编程的调试可能更复杂,需要使用仿真和硬件测试工具。软件编程则可以使用标准的调试工具,如Eclipse的调试器。

·应用场景:对于需要高性能和低延迟的应用,硬件编程可能更合适。而对于复杂的算法和数据处理任务,软件编程可能更加高效。

四、 参考链接

  1. https://blog.youkuaiyun.com/qq_43279579/article/details/115933154
  2. https://blog.youkuaiyun.com/m0_64791246/article/details/125114387
  3. https://blog.youkuaiyun.com/qq_31348733/article/details/101310105
  4. https://blog.youkuaiyun.com/qq_43279579/article/details/115953871
// // Permission: // // Terasic grants permission to use and modify this code for use // in synthesis for all Terasic Development Boards and Altera Development // Kits made by Terasic. Other use of this code, including the selling // ,duplication, or modification of any portion is strictly prohibited. // // Disclaimer: // // This VHDL/Verilog or C/C++ source code is intended as a design reference // which illustrates how these types of functions can be implemented. // It is the user's responsibility to verify their design for // consistency and functionality through the use of formal // verification methods. Terasic provides no warranty regarding the use // or functionality of this code. // // -------------------------------------------------------------------- // // Terasic Technologies Inc // 356 Fu-Shin E. Rd Sec. 1. JhuBei City, // HsinChu County, Taiwan // 302 // // web: http://www.terasic.com/ // email: support@terasic.com // // -------------------------------------------------------------------- // // Major Functions: DE2_115_PS2 Mouse Controller // // -------------------------------------------------------------------- // // Revision History : // -------------------------------------------------------------------- // Ver :| Author :| Mod. Date :| Changes Made: // V1.0 :| Johnny FAN,HdHuang :| 05/16/10 :| Initial Revision // -------------------------------------------------------------------- module ps2( iSTART, //press the button for transmitting instrucions to device; iRST_n, //FSM reset signal; iCLK_50, //clock source; PS2_CLK, //ps2_clock signal inout; PS2_DAT, //ps2_data signal inout; oLEFBUT, //left button press display; oRIGBUT, //right button press display; oMIDBUT, //middle button press display; oX_MOV1, //lower SEG of mouse displacement display for X axis. oX_MOV2, //higher SEG of mouse displacement display for X axis. oY_MOV1, //lower SEG of mouse displacement display for Y axis. oY_MOV2 //higher SEG of mouse displacement display for Y axis. ); //interface; //======================================================= // PORT declarations //======================================================= input iSTART; input iRST_n; input iCLK_50; inout PS2_CLK; inout PS2_DAT; output oLEFBUT; output oRIGBUT; output oMIDBUT; output [6:0] oX_MOV1; output [6:0] oX_MOV2; output [6:0] oY_MOV1; output [6:0] oY_MOV2; //instantiation SEG7_LUT U1(.oSEG(oX_MOV1),.iDIG(x_latch[3:0])); SEG7_LUT U2(.oSEG(oX_MOV2),.iDIG(x_latch[7:4])); SEG7_LUT U3(.oSEG(oY_MOV1),.iDIG(y_latch[3:0])); SEG7_LUT U4(.oSEG(oY_MOV2),.iDIG(y_latch[7:4])); //instruction define, users can charge the instruction byte here for other purpose according to ps/2 mouse datasheet. //the MSB is of parity check bit, that's when there are odd number of 1's with data bits, it's value is '0',otherwise it's '1' instead. parameter enable_byte =9'b011110100; //======================================================= // REG/WIRE declarations //======================================================= reg [1:0] cur_state,nex_state; reg ce,de; reg [3:0] byte_cnt,delay; reg [5:0] ct; reg [7:0] x_latch,y_latch,cnt; reg [8:0] clk_div; reg [9:0] dout_reg; reg [32:0] shift_reg; reg leflatch,riglatch,midlatch; reg ps2_clk_in,ps2_clk_syn1,ps2_dat_in,ps2_dat_syn1; wire clk,ps2_dat_syn0,ps2_clk_syn0,ps2_dat_out,ps2_clk_out,flag; //======================================================= // PARAMETER declarations //======================================================= //state define parameter listen =2'b00, pullclk=2'b01, pulldat=2'b10, trans =2'b11; //======================================================= // Structural coding //======================================================= //clk division, derive a 97.65625KHz clock from the 50MHz source; always@(posedge iCLK_50) begin clk_div <= clk_div+1; end assign clk = clk_div[8]; //tristate output control for PS2_DAT and PS2_CLK; assign PS2_CLK = ce?ps2_clk_out:1'bZ; assign PS2_DAT = de?ps2_dat_out:1'bZ; assign ps2_clk_out = 1'b0; assign ps2_dat_out = dout_reg[0]; assign ps2_clk_syn0 = ce?1'b1:PS2_CLK; assign ps2_dat_syn0 = de?1'b1:PS2_DAT; // assign oLEFBUT = leflatch; assign oRIGBUT = riglatch; assign oMIDBUT = midlatch; //multi-clock region simple synchronization always@(posedge clk) begin ps2_clk_syn1 <= ps2_clk_syn0; ps2_clk_in <= ps2_clk_syn1; ps2_dat_syn1 <= ps2_dat_syn0; ps2_dat_in <= ps2_dat_syn1; end //FSM shift always@(*) begin case(cur_state) listen :begin if ((!iSTART) && (cnt == 8'b11111111)) nex_state = pullclk; else nex_state = listen; ce = 1'b0; de = 1'b0; end pullclk :begin if (delay == 4'b1100) nex_state = pulldat; else nex_state = pullclk; ce = 1'b1; de = 1'b0; end pulldat :begin nex_state = trans; ce = 1'b1; de = 1'b1; end trans :begin if (byte_cnt == 4'b1010) nex_state = listen; else nex_state = trans; ce = 1'b0; de = 1'b1; end default : nex_state = listen; endcase end //idle counter always@(posedge clk) begin if ({ps2_clk_in,ps2_dat_in} == 2'b11) begin cnt <= cnt+1; end else begin cnt <= 8'd0; end end //periodically reset ct; ct counts the received data length; assign flag = (cnt == 8'hff)?1:0; always@(posedge ps2_clk_in,posedge flag) begin if (flag) ct <= 6'b000000; else ct <= ct+1; end //latch data from shift_reg;outputs is of 2's complement; //Please treat the cnt value here with caution, otherwise wrong data will be latched. always@(posedge clk,negedge iRST_n) begin if (!iRST_n) begin leflatch <= 1'b0; riglatch <= 1'b0; midlatch <= 1'b0; x_latch <= 8'd0; y_latch <= 8'd0; end else if (cnt == 8'b00011110 && (ct[5] == 1'b1 || ct[4] == 1'b1)) begin leflatch <= shift_reg[1]; riglatch <= shift_reg[2]; midlatch <= shift_reg[3]; x_latch <= x_latch+shift_reg[19 : 12]; y_latch <= y_latch+shift_reg[30 : 23]; end end //pull ps2_clk low for 100us before transmit starts; always@(posedge clk) begin if (cur_state == pullclk) delay <= delay+1; else delay <= 4'b0000; end //transmit data to ps2 device;eg. 0xF4 always@(negedge ps2_clk_in) begin if (cur_state == trans) dout_reg <= {1'b0,dout_reg[9:1]}; else dout_reg <= {enable_byte,1'b0}; end //transmit byte length counter always@(negedge ps2_clk_in) begin if (cur_state == trans) byte_cnt <= byte_cnt+1; else byte_cnt <= 4'b0000; end //receive data from ps2 device; always@(negedge ps2_clk_in) begin if (cur_state == listen) shift_reg <= {ps2_dat_in,shift_reg[32:1]}; end //FSM movement always@(posedge clk,negedge iRST_n) begin if (!iRST_n) cur_state <= listen; else cur_state <= nex_state; end endmodule
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值