Abstract
很多人跑DE2本身的範例,都可以上μC/OS-II這個作業系統,但只要自己用SOPC Builder建立的Nios II系統,就無法上μC/OS-II,本文示範如何用SOPC Builder手動打造一個在DE2上能跑uC/OS-II的Nios II系統。
使用環境:Quartus II 7.2 SP1 + Nios II 7.2 SP1 + DE2(Cyclone II EP2C35F627C6) + μC/OS-II
Introduction
本文為我較早期的文章,雖然仍有參考價值,不過並非最佳的設計,建議您一併參考(原創) 如何自己用SOPC Builder建立一個能在DE2上跑μC/OS-II的Nios II系統 (SRAM精簡版)? (SOC) (Quartus II) (Nios II) (SOPC Builder) (μC/OS-II) (DE2)
根據Altera原廠的資料,要讓Nios II上μC/OS-II,只要依照Using MicroC/OS-II RTOS with the Nios II Processor Tutorial這份資料照著做即可,不過這份資料有幾個問題:
1.這份資料是Altera為自己的開發版所寫的,儘管你照著步驟做,仍無法在DE2上執行。
2.他使用了已經編譯好的sof檔,若你主要是用於Nios II軟體的開發,可以採用這種方式。若你可能加入自己設計的硬體元件,則勢必重新編譯sof檔,很多人就是因為這樣而無法上μC/OS-II。
在(原創) 如何成功執行『Using μC/OS-II RTOS with the Nios II Processor Tutorial』? (中級) (IC Design) (Quartus II) (Nios II) (μC/OS-II) 中雖然克服了萬難讓Nios II上μC/OS-II了,不用總有個遺憾,為什麼只能用DE2原廠範例的DE2_SD_Card_Audio.sof呢?為什麼不能自己用SOPC Builder建立一個Nios II系統跑uC/OS-II呢?後來在Terasic原廠網站
http://www.terasic.com/downloads/cd-rom/de2/DE2_System_v1.4b.zip
中發現在這個目錄下
\DE2_demonstrations\SOPC_Builder\Reference_Design\DE2_NIOS\
有Terasic原廠所建議的Nios II硬體設計,經過一番研究後,整理出這份文件。
Solution
要讓Nios II軟體跑在on-chip memory並不是不可能,但DE2最多只能有49K的on-chip memory,所以若要讓軟體能跑,必須動一些最佳化的方式讓軟體盡量的小,在(原創) 如何在DE2執行Checksum Master範例 (中級) (IC Design) (DE2) (Quartus II) (Nios II) (SOPC Builder)用過幾個方式從軟體解決,有興趣的人可以參考,本篇主要是從硬體解決,直接將μC/OS-II跑在SRAM上。
Quartus II
使用Quartus II建立一個全新的project
Step 1:
建立一個新project

Step 2:

按Next下一步。
Step 3:
輸入project路徑名稱、project名稱與top-level module名稱,按Next下一步
Step 4:
c:/DE2/hello_ucosii目錄尚未建立,是否建立此目錄,按Yes繼續
Step 5:
加入既有檔案,由於我們目前沒有任何檔案,所以按Next下一步

Step 6:
選擇FPGA型號,DE2用的是EP2C35F627C6,按Next下一步
Step 7:
EDA工具設定,不需額外設定,按Next下一步
Step 8:
最後的Summary,按Finish
SOPC Builder
使用SOPC Builder建立一個全新的Nios II系統
Step 1:
啟動SOPC Builder

Step 2:
輸入System名稱:nios_ii,選擇Verilog
Step 3:
加入Nios II Processor
選擇左側Altera SOPC Builder->Nios II Processor,滑鼠按兩下加入

使用預設的Nios II/f即可,按Finish

Step 4:
加入SRAM
由於我們要將μC/OS-II放在SRAM跑,所以要加入SRAM controller,不過這裡有個值得注意的地方,你不能使用SOPC Builder所附的SRAM controller,必須改用Terasic本身所附的SRAM controller,將SRAM_16Bit_512K.7z下載,或者
http://www.terasic.com/downloads/cd-rom/de2/DE2_System_v1.4b.zip內的\DE2_demonstrations\SOPC_Builder\Component\SRAM_16Bit_512K
目錄複製到
C:\DE2\hello_ucosii\
複製完成後,請重新開啟SOPC Builder,就可以在左側的Altera SOPC Builder->Terasic Technologies Inc\發現SRAM_16Bit_512K這個contoller,滑鼠按兩下加入

Step 5:
加入Tristate Bridge
由於SRAM需要連接到Tristate Bridge的slave,所以需要加入Tristate Bridge controller,在左側Altera SOPC Builder->Bridges and Adapters->Memoery Mapped下找到Avalon-MM Tristate Bridge,滑鼠按兩下加入

按Finish即可,完成後如下圖出現了一個錯誤訊息:

錯誤訊息表示Tristate Bridge的master必須接到一個slave裝置,所以加上一個Flash Memory controller連上Tristate Bridge。
Step 6:
加入Flash Memory controller
在左側Altera SOPC Builder->Memories and Memory Controllers->Flash下找到Flash Memory(CFI),按兩下加入,將Address Width(bits)改成22

加入後,會如下圖,發現tristate_bridge的tristate_master仍然沒和cfi_flash相接:

所以我們必須手動的接上去

Step 7:
加入JTAG UART
由於我們需在console顯示文字,所以需要加上JTAG UART
在左側Altera SOPC Builder->Interface Protocols->Serial下找到JTAG UART,滑鼠點兩下加入,接受預設值即可,按Finish

最後如下圖所示

Step 8:
加入Interval Timer
由於μC/OS-II需要用到Internal Timer,所以需要加上。
在左側Altera SOPC Builder->Peripherals->Microcontroller Peripherals下找到Interval Timer,滑鼠點兩下加入,接受預設值即可,按Finish

最後如下圖所示

Step 9:
加入System ID Peripheral
System ID Peripheral可以用來辨識硬體,雖然沒有加入也能執行,不過Altera原廠手冊仍建議加入此controller。
在左側Altera SOPC Builder->Peripherals->Debug and Performance下找到System ID Peripheral,滑鼠點兩下加入,接受預設值即可,按Finish

最後如下圖所示

Step 10:
解決錯誤訊息
上圖最下面有幾個錯誤訊息
Error : cpu.instruction_master:"cpu.jtag_debug_module"(0x800..0xfff) overlaps "cfi_flash.s1"(0x0..0x3fffff)
Error : cpu.data_master:"cpu.jtag_debug_module"(0x800..0xfff) overlaps "cfi_flash.s1"(0x0..0x3fffff)
Error : cpu.d_irq:Interrupt number conflict(jtag_uart, timer.irg) on 0
在
Error : cpu.instruction_master:"cpu.jtag_debug_module"(0x800..0xfff) overlaps "cfi_flash.s1"(0x0..0x3fffff)
點兩下,將Reset Vector選擇cfi_flash,Exception Vector選擇sram_16bit_512k_0,按Finish完成

Step 11:
重新分配Base Address
Menu的System->Auto-Assign Base Address

Step 12:
重新分配IRQ
Menu的System->Auto-Assign IRQs

Step 13:
新增Clock Settings
將原本clk改成100.0 Mhz
另外加上clk_50為50.0 Mhz
至此,一個能跑μC/OS-II最小的Nios II系統已經完成,而且是我們DIY用SOPC Builder完成的,最後完成圖如下。

最後按下Generate開始產生硬體,詢問是否儲存,按Save

需要一些時間,完全看你CPU速度而定。
Quartus II Top Module
至此我們還缺Quartus II的Top Module,建立一個新的Verilog檔,名為hello_ucosii.v
hello_ucosii.v
1
module hello_ucosii (
2
endmodule
56行的Reset_Dealy module和SDRAM_PLL module,我們須自己建立。
Reset_Delay.v
1
module Reset_Delay(iRST,iCLK,oRESET);
2
input iCLK;
3
input iRST;
4
output reg oRESET;
5
reg [23:0] Cont;
6
7
always@(posedge iCLK or negedge iRST)
8
begin
9
if(!iRST)
10
begin
11
oRESET <= 1'b0;
12
Cont <= 24'h0000000;
13
end
14
else
15
begin
16
if(Cont!=24'hFFFFFF)
17
begin
18
Cont <= Cont+1;
19
oRESET <= 1'b0;
20
end
21
else
22
oRESET <= 1'b1;
23
end
24
end
25
26
endmodule
SDRAM_PLL.v
1
// megafunction wizard: %ALTPLL%
2
// GENERATION: STANDARD
3
// VERSION: WM1.0
4
// MODULE: altpll
5
6
// ============================================================
7
// File Name: SDRAM_PLL.v
8
// Megafunction Name(s):
9
// altpll
10
// ============================================================
11
// ************************************************************
12
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
13
//
14
// 6.0 Build 202 06/20/2006 SP 1 SJ Full Version
15
// ************************************************************
16
17
18
//Copyright (C) 1991-2006 Altera Corporation
19
//Your use of Altera Corporation's design tools, logic functions
20
//and other software and tools, and its AMPP partner logic
21
//functions, and any output files any of the foregoing
22
//(including device programming or simulation files), and any
23
//associated documentation or information are expressly subject
24
//to the terms and conditions of the Altera Program License
25
//Subscription Agreement, Altera MegaCore Function License
26
//Agreement, or other applicable license agreement, including,
27
//without limitation, that your use is for the sole purpose of
28
//programming logic devices manufactured by Altera and sold by
29
//Altera or its authorized distributors. Please refer to the
30
//applicable agreement for further details.
31
32
33
// synopsys translate_off
34
`timescale 1 ps / 1 ps
35
// synopsys translate_on
36
module SDRAM_PLL (
37
inclk0,
38
c0,
39
c1,
40
c2);
41
42
input inclk0;
43
output c0;
44
output c1;
45
output c2;
46
47
wire [5:0] sub_wire0;
48
wire [0:0] sub_wire6 = 1'h0;
49
wire [2:2] sub_wire3 = sub_wire0[2:2];
50
wire [1:1] sub_wire2 = sub_wire0[1:1];
51
wire [0:0] sub_wire1 = sub_wire0[0:0];
52
wire c0 = sub_wire1;
53
wire c1 = sub_wire2;
54
wire c2 = sub_wire3;
55
wire sub_wire4 = inclk0;
56
Retrieval info: GEN_FILE: TYPE_NORMAL SDRAM_PLL.ppf TRUE FALSE
你一定會問,為什麼還要自己加上Reset_Delay.v和SDRAM_PLL.v,明明我只用到SRAM,卻還要用到SDRAM的pll?
這是參考友晶科技reference design的作法,所以加上Reset_Delay.v和SDRAM_PLL.v。
先談SDRAM_PLL.v,這是由MegaWizard透過MegaCore產生出來的code,主要有三個功能,c0產生SDRAM所需要的50MHz相位延遲60度的clock,c1產生100MHz給Nios II CPU使用,c2產生除頻的25MHz,由於要讓Nios II CPU跑100MHz,所以才動用SDRAM_PLL.v。
Reset_Delay.v則是延緩reset的時間,詳細理由我還不清楚。
根據實驗,若你願意只讓Nios II CPU只跑50MHz,的確可以不加SDRAM_PLL.v和Reset_Delay.v,依然可以正常運作。
hello_ucosii.v
1
module hello_ucosii (
2
endmodule
處理pin腳
Step 1:
pins.tcl
1
cmp add_assignment "hello_ucosii" "" "CLOCK_27" "LOCATION" "PIN_D13"
2
cmp add_assignment "hello_ucosii" "" "CLOCK_50" "LOCATION" "PIN_N2"
3
cmp add_assignment "hello_ucosii" "" "EXT_CLOCK" "LOCATION" "PIN_N26"
4
cmp add_assignment "hello_ucosii" "" "EXT_CLOCK" "LOCATION" "PIN_N26"
5
cmp add_assignment "hello_ucosii" "" "KEY[0]" "LOCATION" "PIN_G26"
6
cmp add_assignment "hello_ucosii" "" "KEY[1]" "LOCATION" "PIN_N23"
7
cmp add_assignment "hello_ucosii" "" "KEY[2]" "LOCATION" "PIN_P23"
8
cmp add_assignment "hello_ucosii" "" "KEY[3]" "LOCATION" "PIN_W26"
9
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[0]" "LOCATION" "PIN_AE4"
10
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[1]" "LOCATION" "PIN_AF4"
11
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[2]" "LOCATION" "PIN_AC5"
12
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[3]" "LOCATION" "PIN_AC6"
13
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[4]" "LOCATION" "PIN_AD4"
14
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[5]" "LOCATION" "PIN_AD5"
15
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[6]" "LOCATION" "PIN_AE5"
16
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[7]" "LOCATION" "PIN_AF5"
17
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[8]" "LOCATION" "PIN_AD6"
18
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[9]" "LOCATION" "PIN_AD7"
19
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[10]" "LOCATION" "PIN_V10"
20
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[11]" "LOCATION" "PIN_V9"
21
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[12]" "LOCATION" "PIN_AC7"
22
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[13]" "LOCATION" "PIN_W8"
23
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[14]" "LOCATION" "PIN_W10"
24
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[15]" "LOCATION" "PIN_Y10"
25
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[16]" "LOCATION" "PIN_AB8"
26
cmp add_assignment "hello_ucosii" "" "SRAM_ADDR[17]" "LOCATION" "PIN_AC8"
27
cmp add_assignment "hello_ucosii" "" "SRAM_CE_N" "LOCATION" "PIN_AC11"
28
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[0]" "LOCATION" "PIN_AD8"
29
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[1]" "LOCATION" "PIN_AE6"
30
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[2]" "LOCATION" "PIN_AF6"
31
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[3]" "LOCATION" "PIN_AA9"
32
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[4]" "LOCATION" "PIN_AA10"
33
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[5]" "LOCATION" "PIN_AB10"
34
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[6]" "LOCATION" "PIN_AA11"
35
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[7]" "LOCATION" "PIN_Y11"
36
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[8]" "LOCATION" "PIN_AE7"
37
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[9]" "LOCATION" "PIN_AF7"
38
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[10]" "LOCATION" "PIN_AE8"
39
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[11]" "LOCATION" "PIN_AF8"
40
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[12]" "LOCATION" "PIN_W11"
41
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[13]" "LOCATION" "PIN_W12"
42
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[14]" "LOCATION" "PIN_AC9"
43
cmp add_assignment "hello_ucosii" "" "SRAM_DQ[15]" "LOCATION" "PIN_AC10"
44
cmp add_assignment "hello_ucosii" "" "SRAM_LB_N" "LOCATION" "PIN_AE9"
45
cmp add_assignment "hello_ucosii" "" "SRAM_OE_N" "LOCATION" "PIN_AD10"
46
cmp add_assignment "hello_ucosii" "" "SRAM_UB_N" "LOCATION" "PIN_AF9"
47
cmp add_assignment "hello_ucosii" "" "SRAM_WE_N" "LOCATION" "PIN_AE10"
48
cmp add_assignment "hello_ucosii" "" "FL_CE_N" "LOCATION" "PIN_V17"
49
cmp add_assignment "hello_ucosii" "" "FL_ADDR[0]" "LOCATION" "PIN_AC18"
50
cmp add_assignment "hello_ucosii" "" "FL_ADDR[1]" "LOCATION" "PIN_AB18"
51
cmp add_assignment "hello_ucosii" "" "FL_ADDR[2]" "LOCATION" "PIN_AE19"
52
cmp add_assignment "hello_ucosii" "" "FL_ADDR[3]" "LOCATION" "PIN_AF19"
53
cmp add_assignment "hello_ucosii" "" "FL_ADDR[4]" "LOCATION" "PIN_AE18"
54
cmp add_assignment "hello_ucosii" "" "FL_ADDR[5]" "LOCATION" "PIN_AF18"
55
cmp add_assignment "hello_ucosii" "" "FL_ADDR[6]" "LOCATION" "PIN_Y16"
56
cmp add_assignment "hello_ucosii" "" "FL_ADDR[7]" "LOCATION" "PIN_AA16"
57
cmp add_assignment "hello_ucosii" "" "FL_ADDR[8]" "LOCATION" "PIN_AD17"
58
cmp add_assignment "hello_ucosii" "" "FL_ADDR[9]" "LOCATION" "PIN_AC17"
59
cmp add_assignment "hello_ucosii" "" "FL_ADDR[10]" "LOCATION" "PIN_AE17"
60
cmp add_assignment "hello_ucosii" "" "FL_ADDR[11]" "LOCATION" "PIN_AF17"
61
cmp add_assignment "hello_ucosii" "" "FL_ADDR[12]" "LOCATION" "PIN_W16"
62
cmp add_assignment "hello_ucosii" "" "FL_ADDR[13]" "LOCATION" "PIN_W15"
63
cmp add_assignment "hello_ucosii" "" "FL_ADDR[14]" "LOCATION" "PIN_AC16"
64
cmp add_assignment "hello_ucosii" "" "FL_ADDR[15]" "LOCATION" "PIN_AD16"
65
cmp add_assignment "hello_ucosii" "" "FL_ADDR[16]" "LOCATION" "PIN_AE16"
66
cmp add_assignment "hello_ucosii" "" "FL_ADDR[17]" "LOCATION" "PIN_AC15"
67
cmp add_assignment "hello_ucosii" "" "FL_ADDR[18]" "LOCATION" "PIN_AB15"
68
cmp add_assignment "hello_ucosii" "" "FL_ADDR[19]" "LOCATION" "PIN_AA15"
69
cmp add_assignment "hello_ucosii" "" "FL_ADDR[20]" "LOCATION" "PIN_Y15"
70
cmp add_assignment "hello_ucosii" "" "FL_ADDR[21]" "LOCATION" "PIN_Y14"
71
cmp add_assignment "hello_ucosii" "" "FL_DQ[0]" "LOCATION" "PIN_AD19"
72
cmp add_assignment "hello_ucosii" "" "FL_DQ[1]" "LOCATION" "PIN_AC19"
73
cmp add_assignment "hello_ucosii" "" "FL_DQ[2]" "LOCATION" "PIN_AF20"
74
cmp add_assignment "hello_ucosii" "" "FL_DQ[3]" "LOCATION" "PIN_AE20"
75
cmp add_assignment "hello_ucosii" "" "FL_DQ[4]" "LOCATION" "PIN_AB20"
76
cmp add_assignment "hello_ucosii" "" "FL_DQ[5]" "LOCATION" "PIN_AC20"
77
cmp add_assignment "hello_ucosii" "" "FL_DQ[6]" "LOCATION" "PIN_AF21"
78
cmp add_assignment "hello_ucosii" "" "FL_DQ[7]" "LOCATION" "PIN_AE21"
79
cmp add_assignment "hello_ucosii" "" "FL_OE_N" "LOCATION" "PIN_W17"
80
cmp add_assignment "hello_ucosii" "" "FL_WE_N" "LOCATION" "PIN_AA17"
81
cmp add_assignment "hello_ucosii" "" "FL_RST_N" "LOCATION" "PIN_AA18"
在View->Utility Windows->Tcl Console出現Tcl Console
輸入
source pins.tcl
Step 2:
將沒用到的pin設為tri-state
Menu的Assignment->Device..

按下Device and Pin Options..
選擇Unused Pins tab,將Reserve all unused pins設為 As input tri-stated

至此,Quartus II部分已經完成,可以開始編譯產生.sof檔,這需要很久的時間,完全看你CPU速度而定,編譯完成後燒將hello_ucosii.sof燒進DE2。
Nios II IDE
Step 1:
建立Hello MicroC/OS-II project
Menu:File->New->Nios II C/C++ Application

Step 2:
選擇Hello MicroC/OS-II template,講指定nios_ii.ptf路徑,完成按Finish

Step 3:
執行hello_ucosii_0
選著hello_ucosii_0 project,右鍵Run As->Nios II Hardware

最後執行結果,表示μC/OS-II順利執行

完整程式碼下載
hello_ucosii_sram_big.7z (含SDRAM_PLL.v和Reset_Delay.v)
hello_ucosii_sram_small.7z (不含SDRAM_PLL.v和Reset_Delay.v)
Conclusion
DE2和Altera原廠的版子還是有些差異,很多Altera官方的文件並不適用,在本文又再次證明了這個事實。
See Also
(原創) 如何自己用SOPC Builder建立一個能在DE2-70上跑μC/OS-II的Nios II系統? (SOC) (Nios II) (μC/OS-II) (DE2-70)