【入门教程三】基于DE2-115的Nios V工程(一)——My First Nios V

 本教程演示如何在DE2-115开发板上创建一个基于Nios V 的SOPC系统,并在系统上运行Nios V软件工程。

一、Nios V简介

Nios V处理器是基于RISC-V规范的软知识产权(IP)处理器。

Nios V处理器系统相当于一个微控制器(或“芯片级计算机”),其中包括处理器以及单芯片上的外设和内存组合。Nios®V处理器系统由一个Nios V处理器内核、一组片内外设、片内存储器和片外存储器的接口组成,所有这些都集成在Intel FPGA芯片上进行实现。与微控制器类似,所有的Nios V处理器系统都使用一致的指令集和编程模型。

目前Intel推出了三款Nios® V处理器(图片来自Intel 官网):

 (点击图可放大)

 从截图可以看到这里面功能最强的是Nios V/g IP,用户可根据实际需求选择对应的软核。不过对于Cyclone V器件目前只支持Nios V/m软核。Agilex V等器件则支持以上三种软核。

 Nios V/m处理器性能

Nios®V/m处理器是Intel基于RISC-V指令集开发的微控制器核心。

Nios®V/m处理器支持两种不同的配置:

  1. 流水线

  • 应用RV32IZicsr指令集。

  • 支持五阶段流水线数据通路。

  2. 非流水线

  • 应用RV32IZicsr指令集。

  • 支持非流水线数据通路。

二、SOPC开发流程

在Quartus Prime完成嵌入式系统的硬件部分,在RiscFree IDE中完成NiosV软件部分。基于Nios V 的SOPC 的开发流程其实和以前Nios II 的流程是一样的,以下是Nios II 的开发流程:

本文具体会使用Quartus软件中的Platform Designer系统集成工具创建一个基于Nios V的FPGA硬件系统工程(一个简单的LED控制电路),将编译产生的sof编程文件下载到FPGA 中,然后使用Ashling RiscFree IDE创建Nios v软件工程——my_first_niosv(给LED提供控制信号),最后将软件编译产生的.elf可执行文件下载到DE2-115开发板。

在这个设计当中,除了可以直接在FPGA开发板上观察LED的现象,还可以在Nios V terminal上查看打印信息(这是因为Nios V软件程序要打印的信息通过JTAG UART传输到PC上,并在Nios V terminal进行了显示。)

三、开发工具下载

目前Quartus Prime Standard版从 22.1及以上版本都支持Nios V了,而且这些版本也支持Cyclone IV器件。Quartus Prime Pro版从22.2及以上版本都支持Nios V ,但Pro版不支持Cyclone IV器件。

本文以22.1.2版本为例进行操作演示。

1. Quartus Prime v22.1.2 Standard Edition 和对应的Ashling  RiscFree IDE下载链接:https://www.intel.com/content/www/us/en/software-kit/785052/intel-quartus-prime-standard-edition-design-software-version-22-1-2-for-windows.html

备注1:点击Individual Files找到QuartusSetup-22.1std.2.922-windows.exe文件并下载

备注2:点击Additional Software找到RiscFreeSetup-22.1std.2.922-windows.exe文件并下载

备注3:点击Individual Files找到cyclone-22.1std.0.915.qdz文件并下载

2. Quartus以及Nios® V/m Embedded Processor的license,在Intel [Self Service Licensing Center]可免费申请,申请步骤可参考链接(点击跳转),使用期限是90天。

3. 设置license环境变量。将Intel发送过来的license文件保存到本地盘,然后将其具体路径添加到计算机的环境变量窗口。

 同时,也在Quartus工具中点击菜单Tools——License setup设置license文件路径:

四、Quartus工程设计

系统组成

本教程要在FPGA里定制一个包含Nios V处理器、On-Chip Memory、JTAG UART和PIO的嵌入式系统。这个系统中使用的Nios V核是整个系统的核心,其他组件都会通过Avalon总线连接到这个系统核心上。

Clock Source:时钟源组件,提供时钟信号,驱动其他组件。

On-Chip Memory (RAM or ROM) Intel FPGA IP:Intel FPGA包含了可以在Platform Designer系统中当作RAM或ROM使用的片上存储器。片上存储器有以下优势:与片外存储器相比,片上存储器的访问时间更快;Platform Designer自动例化片上存储器,不需要进行任何手动连接;FPGA上电时,某些存储块可具有初始化的内容,这一特性在存储数据常量或处理器引导代码时很重要;片上存储器支持双端口访问,允许两个主设备同时访问同一内存;有RAM和ROM之分,容量大小不超过FPGA最大可用容量。

JTAG UART IP:是PC与FPGA通信电缆的控制台。PC可以将数据通过JTAG电缆传输到FPGA,也能将FPGA产生的数据回传到PC。

PIO(Parallel I/O) Intel FPGA IP :该IP是具有Avalon接口的并行输入/输出(parallel input/output)核,在Avalon存储器映射(Avalon Memory-Mapped Avalon-MM)从端口和通用I/O端口之间提供了一个存储器映射接口。I/O端口既可以连接片上用户逻辑,也可以连接到FPGA与外设连接的I/O引脚。每个PIO核可以提供最多32个I/O端口。像微处理器这样的智能主机通过读/写寄存器映射的Avalon-MM接口控制PIO端口。在主机控制下,PIO核捕获输入端口的数据,并驱动数据到输出端口。当PIO端口直接与I/O引脚相连时,主机通过写PIO核中的控制寄存器对I/O引脚进行三态控制。

或者直接参考Nios V 的handbook手册截图。(截图来自Nios® V 嵌入式处理器设计手册,点击可以跳转)

详细步骤

1. 点击Quartus菜单File——New Project Wizard——Next。

2. 在桌面创建一个my_first_niosv的文件夹,并将工程路径指向这里,且工程的名称也命名为my_first_niosv:

3. 连续点击3次Next得到如下界面,通过器件过滤器筛选选中DE2-115的Cyclone IV EP4CE115器件。

4. 最后点击Next和Finish完成工程创建。

5.点击Platform Designer 图标打开qsys系统界面。

6. 在IP Catalog搜索NiosV,双击Nios V/m Processor Intel FPGA IP以添加此IP到qsys系统,暂时保持默认参数设置不变,直接点击Finish。

7. 用同样的方法搜索并添加On-Chip Memory (RAM or ROM) Intel FPGA IP,Total Memory Size修改为131072(对应128K),其余参数不变。

 8. 继续搜索并添加JTAG UART Intel FPGA IP到系统,默认参数设置不变。

 9. 最后搜索添加PIO (Parallel I/O) Intel FPGA IP,Width设置为18,Direction设置为Output。

10. 按下图所示连接各IP,并按照下图重命名每个IP,最后双击箭头处将LED PIO导出。

 11. 修改Nios V/m IP的参数设置,勾选Enable Reset from Debug Module,Reset Agent选择SRAM.s1。

12.点击Platform Designer的菜单System—— Assign Base Addresses给每个模块分配地址空间。

13. 这时Message栏仍然有错误提示,请将My_NiosV的ndm_reset_in信号与系统rest信号连接起来。最后点击窗口右下角的Generate HDL按钮生成qsys文件。

 14. 点击OK。(虽然这里截图是提醒添加.qip和.sip文件到工程,但其实也可以添加my_first_niosv/niosv.qsys文件,结果是一样的。)

15. 点击菜单Project——Add/remove Files in Project...。

16. 在弹出的对话框里面点击...双击niosv.qsys文件就可以将该文件添加进工程里面去。

 17. 最后得到结果如下,然后点击Apply按钮后,就可以关闭该窗口了。

 18. 点击Quartus菜单File——New——Verilog HDL File——OK,创建my_first_niosv.v顶层文件。

19. 在该.v文件里面输入如下代码并保存为my_first_niosv.v。

module my_first_niosv(    CLOCK_50,    LEDR);input          CLOCK_50;output [9:0]   LEDR;    niosv u0 (        .clk_clk                        (CLOCK_50),   //clk.clk        .led_external_connection_export (LEDR)  // led_external_connection.export    );     endmodule

20. 点击Analysis & Synthesis进行分析与综合。

21. 分析综合完成以后,点击Quartus菜单Assignments——Pin Planner。

22.  按DE2-115开发板的相关引脚进行引脚分配,具体内容如如下。

23. 最后再点击Start Compilation图标编译Quartus工程,最终生成.sof文件。

五、创建Nios V 软件工程

 1. 点击电脑左下角的开始菜单打开Nios V Command Shell。

 2. 将路径切换到my_first_niosv工程文件夹路径下,然后新建software文件。

3. 先来看看niosv-app的用法(更多具体内容请自行阅读)。

3. 运行niosv-bsp -c -t=hal --sopcinfo=niosv.sopcinfo software/bsp/settings.bsp命令在software文件夹创建Nios V BSP。

4. 在software文件夹路径下再创建app文件夹,并在app文件夹下创建空白led.c文件。

5. 运行niosv-app -a=software/app -b=software/bsp -s=software/app/led.c命令在app文件夹生成CMakeLists.txt文件。(后面会在RIscFree IDE 中通过“Create a New Project” wizard创建软件工程,然后通过CMakeList.txt 来把APP project 导入进去。)

6. 在PC开始菜单栏打开Quartus v22.1.2下的RiscFree IDE。

 7. workspace指向software文件夹路径。然后点击Launch启动IDE软件。

8. 点击Create a project,在New Project窗口,选择C/C++下的C Project,点击Next以打开C Project窗口。

9. 在C Project窗口,Project name命名为app,Location指向app所在文件夹,Project Type选择CMake driven下的Empty Project。

10. 接下来的Select Configurations窗口保持默认设置不变,点击Finish即可。

11. 在led.c文件里面敲入如下代码:

#include <stdio.h>#include "system.h"#include "alt_types.h"#include "altera_avalon_pio_regs.h"/* 流水灯控制数组,高电平点亮  */const alt_u32 LED_TBL[] = {        0x201,  //10 0000 0001        0x102,  //01 0000 0010        0x84,   //00 1000 0100        0x48,   //00 0100 1000        0x30,   //00 0011 0000        0x48,   //00 0100 1000        0x84,   //00 1000 0100        0x102,  //01 0000 0010        0x201   //10 0000 0001};////// function: main// description: perform cyclically lighting the LED// parameter: none// return: 0////int main(){    printf("Realize the function of cyclically lighting the LED\n");   //在console窗口打印信息    alt_u8 i;    alt_u32 delay;    while(1){        for(i = 0; i<9; i++){                          //流水灯花样数组共有 9种状态            IOWR(LED_BASE, 0, LED_TBL[i]);          //流水灯花样显示            delay = 0;            while(delay < 500000)                       //延时大约1秒                delay++;        }    }    return 0;}
 

12. 左键选中app,点击Build Project编译led.c,编译完成可以看到生成app.elf文件。

六、下板测试

5.1 配置硬件

1. 将DE2-115开发板和电脑用板子自带的白色USB type B 线缆连接起来。给DE2-115插上电源并开机。

2. 打开Quartus的Programmer工具,点击Hardware Setup,选择USB-Blaster[USB-0]端口。

2. 点击Auto Detect,选择DE2-115的EP4CE115器件。

3. 右击器件EP4CE115,选择Change File...,然后选择C:\Users\terasic_002\Desktop\my_first_niosv\output_files路径下的my_first_niosv.sof文件,点击Start按钮开始配置FPGA。

 进度条显示100%代表FPGA 配置成功。

5.2 配置软件

 1. 在Nios V Command Shell里运行juart-terminal。(以前的Nios terimal tool 改为juart-termial了。)

 2.  在RiscFree IDE窗口左键选中app,依次选择菜单里的Run As-->3 Ashling RISC-V(auto-detect)Hardware Debugging。

3. 在C Local Application窗口选择app.elf再点OK按钮。

4. 运行完成后即可在DE2-115开发板上看到led.c程序的流水灯现象。

5. 同时,在Teminal会打印:Realize the function of cyclically lighting the LED

// // 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、付费专栏及课程。

余额充值