軟件環境:Quartus Prime Standard 18.1 Window 10
硬件環境:小梅哥 AC501 開發板
主要參考:
本實驗使用 Nios 的自定義組件控制開發板上 LED 閃爍。
本文首先建立了基於片上 RAM 的基礎 Nios 工程,之後在該工程上添加基於 Avalon-MM 接口的自定義組件,修改 Nios 軟件後實現 LED 閃爍。
建立 Quartus 工程
打開 Quartus 軟件,選擇菜單 File > New …,在彈出窗口中選擇 New Quartus Prime Project,點擊 OK 按鈕。
在 New Project Wizard 對話框中,按提示選擇 Next 頁面,需要進行特殊設置的頁面包括以下頁面,其它頁面保持默認。
設置工程名稱和路徑:
選擇 FPGA 芯片型號:
完成全部配置後點擊 Finish 按鈕創建新工程 cus_com。
在 Quartus 選擇菜單項 Assignments > Settings,在配置窗口選擇 Compilation Process Settings 頁,選擇 Use all available processors:
用 Platform Designer 建立 qsys 模塊
在 Quartus 選擇菜單項 Tools > Platform Designer,打開 Platform Designer 界面:
雙擊 clk_0 模塊,配置時鐘頻率爲 50 MHz
通過 IP Catalog 界面添加 System ID 模塊,保持默認配置點擊 Finish 按鈕:
添加 JTAG UART 模塊,保持默認配置點擊 Finish 按鈕:
添加 On-Chip Memory 模塊,並配置爲 128 KB 大小(小於當前 FPGA 芯片 1400 Kb 的 RAM 空間總量),其它配置項保持默認,點擊 Finish 按鈕:
添加 Nios II Processor 模塊,設置爲 Nios II/e 模式,其它配置保持默認,點擊 Finish 按鈕:
按下圖,在 System Contents 界面連接各模塊接口,保存當前設計,選擇菜單項 System > Assign Base Addresses:
注意將 nios2 模塊的 instruction_master 連接至 onchip_memory 的 s1:
雙擊 nios2 模塊打開配置界面,進入 Vectors 頁,設置 Reset vector memory 和 Exception vector memory 都爲 on_chip memory:
按前述方法保持當前設計後,選擇菜單項 Generate > Generate HDL…,在彈出窗口保持默認配置並且點擊 Generate 按鈕:
Quartus 工程頂層模塊設計
添加 qsys 模塊
回到 Quartus 軟件,選擇菜單項 Project > Add/Remove Files in Project,彈出窗口中點擊 … 按鈕,選擇 Platform Designer 保存的後綴名爲 qsys 的設計文件,完成後點擊 OK 按鈕:
在 Project Navigator 的 IP Components 頁可以看到添加的 nios_kernel 模塊
添加時鐘模塊
在 IP Catalog 界面選擇並雙擊 PLL Intel FPGA IP:
在彈出窗口中設置 IP 名稱,並點擊 OK 按鈕:
之後彈出的 IP 配置界面中設置參考時鐘爲 50 MHz(板上時鐘),輸出時鐘爲 50 MHz([作爲 qsys 模塊參考時鐘](#用 Platform Designer 建立 qsys 模塊)),其它配置項保持默認並點擊 Finish 按鈕:
之後彈出 Generation 窗口提示 IP 生成結束,點擊 Exit:
在彈出的提示窗口中保持默認,點擊 Yes,將剛生成的 IP 添加至工程:
建立並編寫頂層 HDL 模塊
選擇菜單項 File > New,在彈出窗口中選擇 Verilog HDL File,點擊 OK
在生成的 v 文件中編寫頂層 HDL 模塊,模塊名稱與建立 Quartus 工程時設置的頂層模塊名稱一致。
注意:PLL IP 的模塊端口定義在同名的 v 文件中,qsys 模塊的端口定義在 Platform Designer 的菜單項 Generate > Show Instantiation Template 中。
代碼如下:
module cus_com
(
input clk_50m
);
//時鐘生成
wire clk;
wire locked;
pll_50mhz pll_u
(
.refclk(clk_50m),
.rst(1'b0),
.outclk_0(clk),
.locked(locked)
);
//nios 例化
nios_kernel nios_u
(
.clk_clk (clk), // clk.clk
.reset_reset_n (locked) // reset.reset_n
);
endmodule
編譯工程
綜合
在 Tasks 界面雙擊 Analysis & Synthesis
管腳分配
完成綜合後,Tasks 界面提示如下:
選擇菜單項 Assignments > Pin Planner,在彈出窗口中設置 clk_50m 的 Location 爲 PIN_U10,並設置全部管腳的 I/O Standart 爲 3.3 V LVTTL
完成配置後關閉 Pin Planner 窗口。
添加時鐘約束
在 Tasks 界面雙擊 Timing Analysis
完成後,選擇菜單項 Tools > Timing Analyzer
在彈出窗口中雙擊 Create Timing Netlist:
在該窗口選擇菜單項 Constraints > Create Clock,設置時鐘名稱和週期後點擊 … 按鈕選中時鐘管腳 clk_50m,完成後點擊 Run 按鈕:
在當前窗口雙擊 Update Timing Netlist:
雙擊 Write SDC File…
在彈出窗口中保持默認,並點擊 OK 按鈕:
關閉 Timing Analyzer 窗口,回到 Quartus。
選擇菜單項 Assignments > Settings,進入 Timing Analyzer 頁,選擇並添加生成的 SDC 文件,完成後點擊 OK:
在 Tasks 界面雙擊 Compile Design
等待完成編譯
Nios 軟件
選擇菜單項 Tools > Nios II Software Build Tools for Eclipse(後文簡稱 SBT,與官方文檔一致)
在 Quartus 工程目錄下建立 workspace:
在 SBT 選擇菜單項 File > New > Nio II Application and BSP from Template,在彈出窗口中選擇 Quartus 工程目錄下的 nios_kernel.sopcinfo 文件,並設置工程名稱,並選擇 Hello World 模板,完成後點擊 Finish 按鈕:
通過 Project Explorer 雙擊打開 hello_world.c 文件:
修改代碼如下:
#include <stdio.h>
#include <unistd.h>
int main()
{
while (1)
{
printf("Hello from Nios II!\n");
usleep(500000);
}
return 0;
}
在 Project Explorer 中選擇 nios_app_bsp 工程,在右鍵菜單選擇 Build Project;完成後,同樣在 nios_app 工程上選擇 Build Project。
加載運行基礎工程
連接 USB Blaster 加載器和開發板後,開發板上電。
在 Quartus 選擇菜單項 Tools > Programmer,在 Programmer 窗口點擊 Auto Connect,並在彈出窗口中選中 5CSEBA2,並點擊 OK 按鈕:
在 FPGA 器件點擊右鍵,選擇菜單項 Change File
在 Select New Programming File 窗口中選擇 Quartus 工程目錄下 output_files 文件夾中的 cus_com.sof 文件,完成後選中 Program/Configure,並點擊 Start 按鈕:
完成 FPGA 程序載入後,Progress 顯示載入成功
關閉 Programmer。
回到 SBT 軟件,在 nios_app 工程上右鍵菜單選擇 Run As > Run Configurations:
在彈出窗口中右鍵點擊 Nio II Hardware,選中 New 選項,之後進入 Target Connection 頁,點擊 Refresh Connections 按鈕找到 USB Blaster,最後點擊 Run 按鈕:
在 SBT 界面的 Nios II Console 顯示來源於 JTAG UART 的調試信息:
用 Platform Designer 建立自定義組件
打開 Platform Desgner,並且在 IP Catalog 雙擊 New Component
在彈出窗口中配置組件:
- 在 Component Type 頁設置組件名稱和顯示名稱,以及 Group
- 在 Signal & Interfaces 頁,雙擊 add interface 添加接口
- 在 Signal & Interfaces 頁,進入每個 interface 的配置界面進行配置,主要是時鐘與復位
- 在 Signal & Interfaces 頁,在每個 interface 下雙擊 add signal 添加接口信號,並配置
- 由於 avalon_slave 只用於寫入數據,因此只有地址(4 位)、片選、寫使能和寫數據(8 位)
- 在 Files 頁,點擊 Create Synthesis File from Signals,根據提示建立關聯 HDL 文件,並且依據 Signal & Interfaces 頁的設置生成模塊端口
- 比較麻煩的是不能修改默認文件名,可以在生成文件後,用 Remove File 移除默認文件,修改文件名和內部模塊名後再用 Add File 添加
按以下代碼修改建立的 HDL 文件:
// new_component.v
// This file was auto-generated as a prototype implementation of a module
// created in component editor. It ties off all outputs to ground and
// ignores all inputs. It needs to be edited to make it do something
// useful.
//
// This file will not be automatically regenerated. You should check it in
// to your version control system if you want to keep it.
`timescale 1 ps / 1 ps
module new_component (
input wire [3:0] avalon_slave_address, // avalon_slave.address
input wire avalon_slave_chipselect, // .chipselect
input wire avalon_slave_write, // .write
input wire [7:0] avalon_slave_writedata, // .writedata
input wire reset_sink_reset, // reset_sink.reset
input wire clock_sink_clk, // clock_sink.clk
output wire conduit_end_led_out // conduit_end.new_signal
);
// TODO: Auto-generated HDL template
wire clk;
assign clk = clock_sink_clk;
wire rst;
assign rst = reset_sink_reset;
//輸出 LED 值
reg led = 1'b0;
always @(posedge clk or posedge rst) begin
if (rst == 1'b1) begin
led <= 1'b0;
end
else begin
case ({avalon_slave_chipselect, avalon_slave_write, avalon_slave_address})
{1'b1, 1'b1, 4'b1111}: begin
case (avalon_slave_writedata)
8'hFF: begin
led <= 1'b1;
end
8'h0: begin
led <= 1'b0;
end
default: begin
//保持
led <= led;
end
endcase
end
default: begin
//保持
led <= led;
end
endcase
end
end
assign conduit_end_led_out = led;
endmodule
完成上述步驟後,點擊 Finish 按鈕。
在 IP Catalog 中雙擊剛纔建立的組件,點擊 Finish 按鈕將組件添加至 System Contents 中
注意,在上圖中 avalon_led_0 組件的地址範圍是 0x0004_1000~0x0004_100f,對應自定義時配置的 4 位地址線。
在菜單中選擇 System > Assign Base Addresses,之後選擇 Generate > Generate HDL,生成 qsys 模塊
修改 Quartus 工程
向頂層模塊中的 qsys 模塊添加輸出 LED 端口,並連接至 FPGA 管腳,代碼如下:
module cus_com
(
input clk_50m,
output led0,
output led1
);
//時鐘生成
wire clk;
wire locked;
pll_50mhz pll_u
(
.refclk(clk_50m),
.rst(1'b0),
.outclk_0(clk),
.locked(locked)
);
//nios 例化
nios_kernel nios_u
(
.clk_clk (clk), // clk.clk
.reset_reset_n (locked), // reset.reset_n
.led_out_new_signal (led0) // led_out.new_signal
);
assign led1 = ~led0;
endmodule
按照與前述相同的辦法在 Pin Planner 中設置 led0 和 led1 管腳的位置
在 Quartus 中直接雙擊 Tasks 界面的 Compile Design 完成編譯,不需要再次添加時鐘約束。
修改 nios 軟件
完成 Quartus 工程的編譯後,打開 SBT 內的 workspace。
在 nios_app_bsp 工程選擇,Generate BSP 後,再次運行 Build Project
按以下代碼修改 hello_world.c 後,在 nios_app 工程選擇 Build Project
#include <stdio.h>
#include <unistd.h>
#include "../nios_app_bsp/system.h"
#include "alt_types.h"
int main()
{
alt_u8* ptr_led = AVALON_LED_0_BASE+15;//偏移地址 15 即爲組件 HDL 中的地址值
while (1)
{
printf("Hello from Nios II!\n");
usleep(250000);
*ptr_led = 255;
usleep(250000);
*ptr_led = 0;
}
return 0;
}
按前述相同的辦法加載並運行程序,發現板上 2 個 LED 按設計閃爍。