(原創) 如何自己用SOPC Builder建立一個能在DE2-70上跑μC/OS-II的Nios II系統? (SOC) (Nios II) (μC/OS-II) (DE2-70)

Abstract
本文使用Quartus II、SOPC Builder、Nios II EDS從0開始打造一個能在DE2-70上跑μC/OS-II的Nios II系統,初學者可借此範例熟悉Quartus II、SOPC Builder、Nios II EDS的使用,並且了解基於FPGA的嵌入式系統開發流程。

Introduction
使用環境:Quartus II 8.1 + Nios II EDS 8.1 + DE2-70 (Cyclone II EP2C70F896C6N)

這4篇原本是設計在一起的lab,適合初學者從0開始慢慢熟悉Quartus II、SOPC Builder、Nios II EDS、Avalon Bus Slave、Avalon Bus Master。

(原創) 如何自己用SOPC Builder建立一個能在DE2-70上跑μC/OS-II的Nios II系統? (SOC) (Quartus II) (SOPC Builder) (Nios II) (μC/OS-II) (DE2-70)
(原創) 如何設計一個七段顯示器Controller? (SOC) (Quartus II) (SOPC Builder) (Nios II) (DE2-70)
(原創) 如何設計一個SD卡Wav Player? (SOC) (Quartus II) (SOPC Builder) (Nios II) (DE2-70)
(原創) 如何設計一個數位相框? (SOC) (Quartus II) (SOPC Builder) (Nios II) (DE2-70)

(很多人應該早已在http://quest.ee.ntu.edu.tw/jenny/homepage/sdwang_codesign2008/Lab1-ucos-ii/Lab1.html這個網址看過這篇教學,其實這篇是我在學校當助教時所寫的Lab,這個Lab共有4篇教學,這篇只是第1篇而已,我將陸續將剩下3篇也公佈在blog上。由於年代有點久遠,當時是在Quartus II 8.1上實驗,並不保證在未來的Quartus II版本能正常執行,若遇到Nios II規格變動,或者Quartus II timing的問題,請您自行調試)

為什麼要從0開始建立一個Nios II系統呢?

1.可以自行對SOPC做最佳化。

2.很多範例都是純硬體的Verilog code,需要自行從0開始建立Nios II系統,不能再使用Altera或友晶科技所建立好的Nios II系統。

3.DE2-70並非Altera原廠的開發版,而是友晶科技ODM的版子,很多周邊都與Altera原廠的版子不一樣,所以很多Altera手冊中範例都無法執行,必須要有自己從硬體到軟體建立系統的能力,將來才有辦法將Altera原廠的範例移植到DE2-70上執行並做最佳化。

DE2-70開發版

 hello_ucos2_70

DE2-70系統架構圖

hello_ucos2_10

本範例系統架構圖
最後結果希望在μC/OS-II下實現多執行緒執行,並且LEDG[17:0]能透過軟體被SW[17:0]控制。

hello_ucos2_11

Quartus II部分
使用Quartus II建立一個全新的project

Step 1:
建立一個新project

hello_ucos2_00

Step 2:
Introduction

按Next繼續。

hello_ucos2_01

Step 3:
輸入project路徑名稱、project名稱與top module名稱

按Next繼續。

hello_ucos2_02

Step 4:
c:/DE2-70/hello_ucosii目錄尚未建立,是否建立此目錄

按是(Y)繼續。

hello_ucos2_03

Step 5:
加入既有檔案到project,

由於我們目前還沒有建立任何檔案,所以按Next繼續。

hello_ucos2_04

Step 6:
選擇FPGA型號

DE2-70使用的FPGA是Cyclone II EP2C70F896C6N,由Altera對FPGA的命名規則可得知:
EP2C:Cyclone II
70:70家族
F:FBGA
896:896 pin
C6:speed grade 6

按Next繼續。

hello_ucos2_06

Step 7:
選擇3rd Party的EDA工具

Quartus II支援3rd Part的EDA工具,如ModelSim,若有用到可在此設定,目前沒用到,按 Next繼續。

hello_ucos2_08

Step 8:
最後的Summary

按Finish完成。

hello_ucos2_09

 

SOPC Builder部分
使用SOPC Builder建立一個全新的Nios II系統

Step 9:
啟動SOPC Builder

hello_ucos2_12

Step 10:
輸入System name,並選擇Verilog

選擇Verilog,表示SOPC Builder會將你稍後所設定的ip,以Verilog表示,若你熟悉VHDL,也可以選擇VHDL。這理的設定不限制你日後只能用Verilog或VHDL寫code,因為Quartus II本來就允許你Verilog與VHDL混合編程,也就是說Verilog的module可以使用VHDL的entity,VHDL的entity可以使用Verilog的module,最後都能順利編譯。

hello_ucos2_13

注意左上角Device Family為Cyclone II,且右上角clk_0為50.0Mhz,雖然Nios II在DE2-70可以只跑50.0MHz,但這等於是CPU降頻在跑,正常情況下,Nios II在DE2-70可以跑100.0MHz,所以我們接著打算用PLL將clk倍頻成100.0Mhz。

hello_ucos2_14

Step 11:
加入PLL

產生Nios II CPU與SDRAM所需要的clk,在左側用滑鼠按兩下PLL加入SOPC。

hello_ucos2_16

Page1

接受預設值即可,按Next繼續。

hello_ucos2_18

Page2

接受預設值即可,按Next繼續。

hello_ucos2_18

Page3

接受預設值即可,按Next繼續。

hello_ucos2_20

Page4

設定CPU所需要的100MHz clk,將Clock multiplication factor設為2,注意Actual settings出現100.000000Mhz。

使用ALTPLL產生clk有一點需注意,並不是任何clk都可以產生,若ATLPLL可以合成的clk,會在上方出現Able to implement the requested PLL

按Next繼續。

hello_ucos2_21

Page5

設定SDRAM所需要的100MHz clk,但必須有-65度的phase shift。

按Next繼續。

hello_ucos2_22

 Page 6

不再需要其他clk,按Next繼續。

hello_ucos2_23

Page 7

接受預設值即可,按Next繼續。

hello_ucos2_24

Page 8

接受預設值即可,按Finish完成。

hello_ucos2_25

最後按Finish完成。

hello_ucos2_26

最後會出現pll_0: pll_0.s1 must be connected to an Avalon-MM master的錯誤訊息,因為pll_0是個slave ip,必須被動的受master ip控制,稍後等到SOPC加入了master ip(此系統就是Nios II CPU)後,就可解決。

hello_ucos2_28

Step 12:
更改clk名稱

將clk改成有意義的名稱。

clk_0改成clk_50。
pll_0_c0改成cpu_clk。
pll_0_c1改成sdram_clk。
pll_0改成pll。

hello_ucos2_29

Step 13 :
加入Nios II CPU

hello_ucos2_30

根據用戶需要選擇Nios II Core:
1.Nios II/e (economic):占用LE最少,功能最少,速度最慢。
2.Nios II/s (standard):速度與LE平衡,具有Nios II CPU一般功能。
3.Nios II/f (full):占用LE最多,功能也最多,速度最快。

本範例選用Nios II/f。

Reset Vector與Exception Vector暫時不需設定,因為還未將記憶體ip掛上,最後再設定。

其他設定接受預設值即可,按Finish完成

hello_ucos2_31

將cpu_0改成cpu。

因為Nios II CPU的加入,而Nios II CPU就是個典型的master ip,SOPC自動將將cpu(master)與pll(slave)相連,因此pll_0: pll_0.s1 must be connected to an Avalon-MM master錯誤訊息不見了。

新增的warning是剛提到的reset vector與exception vector,最後再設定。

hello_ucos2_32

Step 14:
加入On-Chip Memory

FPGA內少量的M4K記憶體,是DE2-70所有記憶體中速度最快,不過容量最小的記憶體。

hello_ucos2_33

設定30 KBytes的On-chip Memory。

Total memory size與能使用的M4K記憶體數量有關。不同的FPGA型號有關、選擇不同的Nios II CPU Core、使用Megafunction(如fcfifo)都會影響On-chip Memory的size。

將onchip_memory2_0改成onchip_mem。

出現2個cannot be at 0x1000的錯誤訊息是正常的,因為SOPC Builder初步為onchip_mem的定址0x1000並不合法,等所有ip都加入後,最後會一併重新對所有slave ip定址。

Step 15:
加入SSRAM的Tristate Bridge

因為SSRAM與Flash的databus是tristate,所以Nios II CPU與SSRAM、Flash相接時需要透過Tristate Bridge。

hello_ucos2_36

接受預設值即可,按Finish完成。

hello_ucos2_37

將tri_state_bridge_0改成tristate_bridge_ssram。

出現了tristate_bridge_ssram: tristate_bridge_ssram.tristate_master must connected to Avalon-MM Tristate slave的錯誤訊息,因為tristate_bridge_ssram的master interface需要與slave ip相連,下一步加上SSRAM controller後,就可以解決此問題。

hello_ucos2_38

Step 16:
加入SSRAM

hello_ucos2_71

 

hello_ucos2_39

接受預設值即可,按Finish完成。

hello_ucos2_40

將ssram_0改成ssram。

將ssram與tristate_bridge_ssram相連,這樣就可解掉tristate_bridge_ssram: tristate_bridge_ssram.tristate_master must connected to Avalon-MM Tristate slave錯誤訊息。

hello_ucos2_41

SSRAM是DE2-70上速度僅次於On-chip Memory的記憶體,且容量從DE2的512KB進步到2MB,實用性大增。大部分的軟體跑在SSRAM都相當足夠。

Step 17:
加入Flash的Tristate Bridge

如同Step 15加入一個Tristate Bridge,並將名稱改成tristate_bridge_flash

hello_ucos2_42

Step 18:
加入Flash

hello_ucos2_72

hello_ucos2_43

在Attribute這一頁,將Address Width設為22,Data Width設為16。

hello_ucos2_44

在Timing這一頁,將Wait設為100。按Finish完成。

hello_ucos2_45

將cfi_flash_0改成cfi_flash。

將cfi_flash與tristate_bridge_flash相連,這樣就可解掉tristate_bridge_flash: tristate_bridge_flash.tristate_master must connected to Avalon-MM Tristate slave錯誤訊息。

多了cpu.instruction_master: onchip_mem.s1 (0x1000..0x8fff) overlaps cfi_flash.s1(0x0..0x7fffff) 與 cpu.data_master: onchip_mem.s1 (0x1000..0x8fff) overlaps cfi_flash.s1(0x0..0x7fffff) 兩個錯誤訊息,因為SOPC Builder為cfi_flash初步的定址0x00000000..0x007fffff已經與onchip_mem的0x00001000..0x000087ff相重疊,等所有controler都加入後,最後會一併重新對所有controller定址。

hello_ucos2_46

Flash為DE2-70上唯一斷電後仍保存資料的記憶體,若想Nios II程式斷電後,一通電就可以執行,就要將軟體放在Flash上。

Step 19:
加入SDRAM

hello_ucos2_73

hello_ucos2_47

在Memory Profile這一頁,設定
Presets : Custom
Data width : 32
Chip select : 1
Banks : 4
Row : 13

注意最後Memory size為64MBytes。

hello_ucos2_49

在Timing這一頁,設定
Issue one refresh command every: 7.8125 us
Delay after powerup, before initialization : 200 us

hello_ucos2_50

將sdram_0改成sdram。

一樣會出現sdram base address的錯誤訊息,最後會一併解決。

hello_ucos2_51

Step 20:
加入JTAG UART

JTAG UART是PC與SOPC進行序列傳輸的一種方式,也是Nios II標準的輸出/輸入設備。如printf()透過JTAG UART,經過USB Blaster將輸出結果顯示在PC的Nios II EDS上的console,scanf()透過USB Blaster經過JTAG UART將輸入傳給SOPC的Nios II。

hello_ucos2_74

hello_ucos2_52

接受預設值即可,按Finish完成。

hello_ucos2_53

將jtag_uart_0改成jtag_uart。

hello_ucos2_54

Step 21:
加入UART(RS-232 Serial Port)

UART是PC與SOPC進行序列傳輸的另一種方式,也是Nios II標準的輸出/輸入設備。如printf()也可透過UART,經過RS232將輸出結果顯示在PC的Nios II EDS上的console,scanf()也可透過RS232經過UART將輸入傳給SOPC的Nios II。

hello_ucos2_75

hello_ucos2_63

將Include CTS/RTS pins and control register bits打勾,其他接受預設值即可,按Finish完成。

hello_ucos2_64

將uart_0改成uart。

hello_ucos2_65

Step 22:
加入Timer

此處要加入2個timer,一個做為system clock,一個做為timestamp。尤其μC/OS-II一定需要timestamp timer,否則無法執行。

hello_ucos2_55

接受預設值即可,按Finish完成。

hello_ucos2_56

將timer_0改成sys_clk_timer

hello_ucos2_57

重複相同的步驟,加入timestamp_timer。

hello_ucos2_58

Step 23:
加入System ID

SOPC Builder會使用System ID為每個系統提供識別符號,Nios II EDS可以此防止使用者燒錄了與*.ptf不符合的*.sof。

hello_ucos2_59

接受預設值即可,按Finish完成。

hello_ucos2_60

將sysid_0改成sysid。

(一定要將名稱改成sysid,因為Nios II EDS將會使用sysid做判斷,否則會產生錯誤。)

hello_ucos2_61

Step 24:
加入Character LCD

為DE2-70上的16 x 2字元型LCD,可做為Nios II的標準輸出設備。如printf()也可透過Character LCD將字串顯示在LCD上。

hello_ucos2_76

hello_ucos2_66

接受預設值即可,按Finish完成。

hello_ucos2_67

將lcd_0改成lcd。

hello_ucos2_68

Step 25:
加入LED PIO

此處要加入2個LED PIO,一個為LEDG,一個做為LEDR。

LEDG

hello_ucos2_77

hello_ucos2_69

因為LEDG[8:0]且僅用於輸出,所以width設為9,且選擇Output ports only,按Finish完成。

hello_ucos2_78

將pio_0改成pio_ledg。

hello_ucos2_79

LEDR

hello_ucos2_80

如同增加LEDG PIO的方式加入LEDR PIO。

因為LEDR[17:0]且僅用於輸出,所以width設為9,且選擇Output ports only,按Finish完成。

hello_ucos2_81

將pio_0改成pio_ledr。

hello_ucos2_82

Step 26:
加入Input PIO

此處要加入2個Input PIO,一個為KEY,一個做為SW。

KEY

hello_ucos2_90 

如同Step 25一樣,選擇PIO(Parallel I/O)。

因為KEY[3:0]且僅用於輸入,所以width設為4,且選擇Input ports only,按Finish完成。

hello_ucos2_83

將pio_0改成pio_key。

hello_ucos2_84

SW

hello_ucos2_91

因為SW[17:0]且僅用於輸入,所以width設為18,且選擇Input ports only,按Finish完成。

hello_ucos2_88

將pio_0改成pio_sw。

hello_ucos2_89

Step 27:
重新設定Base Address

之前很多error與warning都是因為都是因為controller的base address重複,目前已經將所有用到的controller加到SOPC Builder,可以讓SOPC Builder重新設定base address。

hello_ucos2_92

錯誤訊息都不見了。

hello_ucos2_93

Step 28:
設定Nios II CPU的Reset Vector與Exception Vector

在Step 13設定Nios II CPU時,因為當時還沒有掛上任何記憶體,所以當時還沒設定Reset Vector與Exception Vector,現在回頭設定。

簡單的說,reset vector就是當系統reset時,CPU會跳到reset vector所指定的位址執行,所以reset vector所指定的記憶體必須是非揮發性記憶體,在DE2-70只有flash。

而exception vector則是當發生hardware interrupt或software exception時,CPU會跳到exception vector所指定的位址執行,為了更有效率,我們會將exception vector指向速度最快的記憶體,通常是on-chip memory或SSRAM。

最後按Finish完成。

 

hello_ucos2_94

最後完成所有SOPC設定,注意下方只有3條訊息,前2個warning是提醒pio_key與pio_sw需要input testbench,這可以忽略

hello_ucos2_95

Step 29:
產生SOPC

按下Generate,正式產生nios_ii.ptf,這需要一點時間產生,依CPU運算速度而定。

hello_ucos2_96

按Save將nios_ii.sopc存檔,這個檔記載著所有SOPC Builder的controller與設定值。 

hello_ucos2_97

約1分半後,SOPC Builder generate成功。

hello_ucos2_98

SOPC Builder Generate主要做2件事情。
1.產生nios_ii.ptf檔:
這個檔案將來是Nios II EDS產生用來產生System Library的依據,Nios II軟體與μC/OS-II才能藉此存取SOPC。

2.產生各controller的Verilog檔:
由於SOPC基於FPGA技術,最後必須由Quartus II產生*.sof檔燒到FPGA內,SOPC Builder會產生controller的Verilog code供Quartus II編譯。你可以發現project的根目錄多了很多*.v,這就是SOPC Builder所產生的。

 

Top Module部分
SOPC Builder為我們產生了各controller的module後,需要有一個top module使之與DE2-70的I/O port相連。

Step 30:
建立Top Mudule

在C:\DE2-70\hello_ucosii\建立hardware目錄。
下載Lab1_files.zip,其中的hello_ucosii.v是一個未完成的top module,將hello_ucosii.v與Reset_Delay.v放在C:\DE2-70\hello_ucosii\目錄下。

有4個地方必須修改後,才能完成top module。

256行

.sdram_clk(), // SDRAM Clock // To do!! SDRAM Clock output

改成

.sdram_clk(sdram_clk), // SDRAM Clock

217行

// To do!! assign sdram clk to oDRAM0_CLK

改成

assign oDRAM0_CLK = sdram_clk; // SDRAM0 Clock

229行

// To do!! assign sdram clk to oDRAM1_CLK

改成

assign oDRAM1_CLK = sdram_clk; // SDRAM1 Clock 

因為DE2-70有2顆SDRAM,所以要assign兩次clk。

277行

.zs_dq_to_and_from_the_sdram(), // SDRAM Data bus 32 Bits // To do!! SDRAM Data bus output

改成

.zs_dq_to_and_from_the_sdram(DRAM_DQ), // SDRAM Data bus 32 Bits

因為DRAM_DQ是inout型態,不能使用wire連接,要直接連到inout port。

 

要如何知道SOPC System有哪些port呢?

開啟nios_ii.v,這是由SOPC Builder所產生的Verilog code,搜尋『module nios_ii (』,可以找到SOPC System的module定義,top module就是根據這裡的定義,連到DE2-70的I/O port。

Step 31:
設定Reserved all unused pins As input tri-stated

Assignment -> Device

hello_ucos2_100

Device and Pin Options...

hello_ucos2_101

Unused Pins : Reserve all unused pins: As input tri-stated

hello_ucos2_102

這個步驟一定要做,否則Nios II無法執行,會出現以下錯誤訊息,初學者常常忽略這個步驟!!

hello_ucos2_99

Step 32:
Import Pin Assignment

下載Lab1_files.zip,其中的DE2_70_pin_assignments.csv記錄了DE2-70所有 I/O的連接腳位。

Assignments -> Import Assignments...

hello_ucos2_103

載入DE2_70_pin_assignments.csv,按OK繼續。

hello_ucos2_104

查看Pin Assignment結果

Assignments -> Assignment Editor

hello_ucos2_105

如下圖,表示Pin Assignment設定成功。

hello_ucos2_106

這個步驟也一定要做,否則Nios II無法執行,也會出現以下錯誤訊息,初學者常常忽略這個步驟!!

hello_ucos2_99

Step 33:
設定nCEO為Use as regular I/O

Assignments –> Device

hello_ucos2_100

Device and Pin Options...

hello_ucos2_101

Dual-Purpose Pins

hello_ucos2_107

將nCEO改成Use as regular I/O

hello_ucos2_108

這是DE2-70設計上的問題,在DE2或其他的Altera的開發版並不需要如此設定。若不這樣設定,Quartus II在編譯時會出現以下錯誤訊息而編譯失敗。

hello_ucos2_109

Step 34:
Quartus II編譯

需要2到10分鐘的時間,視CPU速度而定。

hello_ucos2_110

 

Programmer部分
使用Programmer將編譯的的*.sof燒進FPGA

Step 35:
啟動Programmer

hello_ucos2_111

按Hardware Setup,設定USB-Blaster。

hello_ucos2_112

選擇可用的USB-Blaster

hello_ucos2_113

按Start開始將*.sof燒進FPGA,當100%出現時,表示燒錄成功。

hello_ucos2_114

至目前為止,硬體部分結束,接下來是軟體部分。

 

Nios II EDS部分
使用Nios II EDS開發Nios II軟體

Step 36:
使用Hello Wrold測試硬體是否設計成功

Quartus II能正常編譯,不代表硬體設計成功,SOPC Builder各controller的參數設定錯誤、clk設定錯誤、top module連線錯誤、Quartus II設定錯誤...等,都可能造成Nios II無法執行,所以先用最簡單的Hello World測試硬體,若連Hello World都不能執行,軟體部分就不用繼續了,先回頭找硬體部分的bug。

hello_ucos2_115

右側選擇Hello World template,並指定SOPC Builder System PFT File:c:\DE2-70\hello_ucosii\nios_ii.ptf,這是先前SOPC Builder所generate的ptf檔。最後直接按Finish完成。

hello_ucos2_116

Nios II EDS會根據你選的project template與SOPC Builder System File產生2個project:
1.hello_world_0:Nios II Software project。
2.hello_world_0_syslib:Nios II System Library project。(System Library = HAL(Hardware Abstraction Layer) = BSP(Board Support Package) = Driver)

hello_ucos2_117

選hello_world_0,按滑鼠右鍵,選System Library Properties

hello_ucos2_118

將System clock timer選sys_clk_timer,另外將軟體全部跑在SDRAM,當然也可以跑在其他記憶體,只是因為SDRAM容量最大,而且SDRAM的clk需要phase shift,所以最常出現問題都是在SDRAM,所以在此特別使用SDRAM,至於其他記憶體可自行測試。

hello_ucos2_119

Rus As Nios II Hardware,此實Nios II軟體會透過JTAG UART傳到SDRAM開始執行。

若第一次執行,Nios II EDS會編譯整個System Library,需要一點時間,約2到3分鐘。

hello_ucos2_120

最後執行結果,Nios II由JTAG UART傳回Hello from Nios II到PC的Console。

hello_ucos2_121

若能正確執行Hello World,表示SOPC硬體正確,可以繼續軟體的開發。

Step 37
測試Hello μC/OS-II

目前為止,single thread的軟體程式已經能跑在Nios II上,若要讓Nios II能跑multi thread,就必須靠OS才行,Nios II EDS已經已經巧妙的將μC/OS-II包在System Library裡面。

hello_ucos2_122

執行結果

hello_ucos2_123

Step 38:
開發一個多執行緒且控制硬體的程式

能成功執行Hello Wrold與Hello μC/OS-II,表示軟硬體都已經設定妥當,可以正式用C寫程式了。

再用Hello μC/OS-II template建立一個project。

hello_ucos2_124

將hello_ucosii.c改成如以下的程式

hello_ucosii.c / C 

1 #include <stdio.h>
2 #include "includes.h"
3 #include "system.h"
4 #include <io.h>
5
6  /* Definition of Task Stacks */
7  #define TASK_STACKSIZE 2048
8 OS_STK task1_stk[TASK_STACKSIZE];
9 OS_STK task2_stk[TASK_STACKSIZE];
10
11  /* Definition of Task Priorities */
12
13  #define TASK1_PRIORITY 1
14  #define TASK2_PRIORITY 2
15
16  /* Prints "Hello World" and sleeps for three seconds */
17 void task1(void* pdata)
18 {
19 while (1)
20 {
21 printf("Hello uCOS-II\n");
22 OSTimeDlyHMSM(0, 0, 3, 0);
23 }
24 }
25  /* Prints "Hello World" and sleeps for three seconds */
26 void task2(void* pdata)
27 {
28 unsigned int i;
29 while (1)
30 {
31 // read switch
32   i = IORD(PIO_SW_BASE, 0);
33 // write ledr
34   IOWR(PIO_LEDR_BASE, 0, i);
35 }
36 }
37  /* The main function creates two task and starts multi-tasking */
38  int main(void)
39 {
40 OSTaskCreateExt(task1,
41 NULL,
42 (void *)&task1_stk[TASK_STACKSIZE-1],
43 TASK1_PRIORITY,
44 TASK1_PRIORITY,
45 task1_stk,
46 TASK_STACKSIZE,
47 NULL,
48 0);
49 OSTaskCreateExt(task2,
50 NULL,
51 (void *)&task2_stk[TASK_STACKSIZE-1],
52 TASK2_PRIORITY,
53 TASK2_PRIORITY,
54 task2_stk,
55 TASK_STACKSIZE,
56 NULL,
57 0);
58 OSStart();
59 return 0;
60 }
61
62  

程式解說 

#include "system.h"
#include
<io.h>

system.h記載著SOPC Builder裡各controller的資訊,稍後會討論。
io.h定義了IORD()與IOWR()兩個巨集,可以利用此巨集存取各controller的register。

void task1(void* pdata)
{
while (1)
{
printf(
"Hello uCOS-II\n");
OSTimeDlyHMSM(
0, 0, 3, 0);
}
}

void task2(void* pdata)
{
unsigned
int i;
while (1)
{
// read switch
i = IORD(PIO_SW_BASE, 0);
// write ledr
IOWR(PIO_LEDR_BASE, 0, i);
}
}

i = IORD(PIO_SW_BASE, 0); // 讀取SW目前的值。
IOWR(PIO_LEDR_BASE, 0, i);  // 將SW的值馬上給LEDR顯示。

也就是說,若SW為ON時,LEDR會亮,若SW為OFF時,LEDR就不亮

我們是怎麼做到的呢?

我們透過IORD()巨集,去讀取pio_sw controller目前register的值,然後透過IOWR()巨集,將值寫入pio_ledr controller的register,讓LEDR顯示。

問題來了!!我們怎麼知道pio_sw與pio_ledr在哪裡?

之前#include <system.h>,我們來看看system.h的內容

開啟C:\DE2-70\hello_ucosii\software\hello_ucosii_1_syslib\Debug\system_description\system.h

459行

#define PIO_SW_NAME "/dev/pio_sw"
#define PIO_SW_TYPE "altera_avalon_pio"
#define PIO_SW_BASE 0x094110c0
#define PIO_SW_SPAN 16
#define PIO_SW_DO_TEST_BENCH_WIRING 0
#define PIO_SW_DRIVEN_SIM_VALUE 0
#define PIO_SW_HAS_TRI 0
#define PIO_SW_HAS_OUT 0
#define PIO_SW_HAS_IN 1
#define PIO_SW_CAPTURE 0
#define PIO_SW_DATA_WIDTH 18
#define PIO_SW_RESET_VALUE 0
#define PIO_SW_EDGE_TYPE "NONE"
#define PIO_SW_IRQ_TYPE "NONE"
#define PIO_SW_BIT_CLEARING_EDGE_REGISTER 0
#define PIO_SW_FREQ 100000000
#define ALT_MODULE_CLASS_pio_sw altera_avalon_pio

 

#define PIO_SW_BASE 0x094110c0 定義了SOPC Builder為pio_sw所規劃的位址,而system.h也是Nios II EDS根據nios_ii.ptf所產生的。

413行

#define PIO_LEDR_NAME "/dev/pio_ledr"
#define PIO_LEDR_TYPE "altera_avalon_pio"
#define PIO_LEDR_BASE 0x094110a0
#define PIO_LEDR_SPAN 16
#define PIO_LEDR_DO_TEST_BENCH_WIRING 0
#define PIO_LEDR_DRIVEN_SIM_VALUE 0
#define PIO_LEDR_HAS_TRI 0
#define PIO_LEDR_HAS_OUT 1
#define PIO_LEDR_HAS_IN 0
#define PIO_LEDR_CAPTURE 0
#define PIO_LEDR_DATA_WIDTH 18
#define PIO_LEDR_RESET_VALUE 0
#define PIO_LEDR_EDGE_TYPE "NONE"
#define PIO_LEDR_IRQ_TYPE "NONE"
#define PIO_LEDR_BIT_CLEARING_EDGE_REGISTER 0
#define PIO_LEDR_FREQ 100000000
#define ALT_MODULE_CLASS_pio_ledr altera_avalon_pio

#define PIO_LEDR_BASE 0x094110a0 定義了SOPC Builder為pio_ledr所規劃的位址。

設定標準輸出為LCD

hello_ucos2_126 

執行結果

hello_ucos2_125

透過μC/OS-II,一個thread在LCD顯示,另一個thread控制SW與LEDR。

完整程式碼下載
Lab1_files.zip (一個未完成的半成品,可以根著本文一步一步完成)
hello_ucosii.7z (最後完整的結果)

Question
(這是我當時給學生的homework,各位有興趣可以自己自做做看)

1.為什麼只有SDRAM的clock需要phase shift -65度?為什其他的硬體的clk都不需要phase shift?

2.可以使用pointer,而不使用IORD()與IOWR()嗎?解釋你的理由?

#define SW (unsigned int *)SW_BASE
#define LEDR (unsigned int *)LEDR_BASE

void task2(void* pdata) {
while (1)
{
*LEDR = *SW;
}
}

3. 試著將Hello World執行在On-Chip Memory,並解釋你所使用的方法。

Conclusion
對一個初學者來說,要讓Nios II能順利的在DE2-70跑起來,需要面臨很陡峭的學習曲線,因為其中有不少小trick很容易忽略而失敗。Nios II就只是這樣嗎?這只是Nios II的起手式,本系列共用4個Lab,此為第1個,第2個Lab以七段顯示器為範例,示範如何寫Slave IP,第3個Lab為Terasic的DE2_70_SD_Card_Audio_Player範例,除了實際體會HW/SW Co-Design外,將學習如何讀取SD卡,第4個Lab將實作一個數位像框,示範如何寫一個Master IP,並可直接從Flash啟動。

See Also
(原創) 如何自己用SOPC Builder建立一個能在DE2-70上跑μC/OS-II的Nios II系統? (SOC) (Quartus II) (SOPC Builder) (Nios II) (μC/OS-II) (DE2-70)
(原創) 如何設計一個七段顯示器Controller? (SOC) (Quartus II) (SOPC Builder) (Nios II) (DE2-70)
(原創) 如何設計一個SD卡Wav Player? (SOC) (Quartus II) (SOPC Builder) (Nios II) (DE2-70)
(原創) 如何設計一個數位相框? (SOC) (Quartus II) (SOPC Builder) (Nios II) (DE2-70)

posted on 2010-08-10 09:46  真 OO无双  阅读(29577)  评论(17编辑  收藏  举报

导航