Qsysというのは、Alteraのシステム統合ツールの名前です(AlteraのQsysのページ)。以前あったSOPC Builderの後継となる開発ツールです。CPUやRAMを含んだシステムをFPGA上に簡単に構築できます。EclipseとCコンパイラもあってソフト開発も簡単にできます。
Qsysを使ってみたので使い方を簡単に紹介します。使った開発ツールはQuartus II 11.0sp1のweb editionです。FPGAボードはDE0 nanoを使いました。
おおまかな流れは以下のようになります
1. インストール
Quartus II ver11.0 sp1 web editionをインストールします。以前はsp1なしをインストールしないとsp1をインストールできませんでしたが、11.0からはsp1だけインストールすればいいです。また、以前はNios IIのソフトウェア開発ツールを別途インストールする必要がありましたが、これも必要なくなりました。ライセンス認証もありません。
2. Qsysを使う前にやっておくこと
Quartus IIを使った普通のFPGA開発と同じように以下を行います。
- プロジェクトの作成
- デバイスの設定
- ピン配置の設定
- SDCファイルの作成
今回は手抜きで、DE0 nanoのCD-ROMに入っているDE0_Nano_GOLDEN_TOPというプロジェクトをコピーしました。適当なフォルダを作ってDE0_Nano_GOLDEN_TOPというフォルダの中身をコピーするだけです。DE0_Nano.qpfというプロジェクトのファイルをダブルクリックすることでQuartus IIが起動します。
3. Qsysでシステムを作る
これは後述します。
4. 論理合成の前にやっておくこと
- できあがったQsysのファイルをプロジェクトに追加します。
- Qsysのモジュールを呼び出すようにメインのDE0_Nano.vを修正します。
5. 論理合成
Quartus IIの普通の論理合成を行います。
6. FPGAボードへの書き込み
できあがったDE0_Nano.sofファイルをDE0_Nanoに書き込みます。
7. ソフト開発
Nios II 11.0sp1 Software Build Tools for Eclipseを立ち上げてソフト開発します。
8. プログラムの実行
Eclipse内からプログラムを実行します。
以上になります。今回は3.を中心に書きます。
一応、今回の話はやってみたら、なんとなくできたというレベルなので間違った情報が含まれている危険性がたぶんにあります。ここは違うみたいなところはぜひとも教えてください。
3. Qsysでシステムを作る
(1) Qsysの起動
というわけで、まずはQsysの起動です。Quartus IIのツールボタンから起動できます。
(画像はクリックすると大きくなります。元の記事に戻るときはブラウザの戻るボタンで戻ってください)
(2) プロジェクト名を決める
Qsys起動直後の画面です。SOPC Builderはプロジェクト名を聞いてくるダイアログが最初に出ましたが、Qsysでは聞いてきません。プロジェクト名はモジュール名にもなるので、後で必要になります。どうやって決めるのかというと、セーブするときのファイル名がそのままプロジェクト名(= モジュール名)になります。ctrl+SもしくはFileメニューからSaveでセーブしてやると何もセーブされていない一番最初はファイル名を聞いてきます。とりあえずNiosSystemという名前でセーブしました。拡張子はqsysになるのでNiosSystem.qsysというファイルができます。
(3) システムの概要
今回作るのは、コンソールにHello, worldを表示してLEDチカチカするだけのシステムにします。RAMはDE0 Nanoに搭載されているSDRAMにして100MHzで動作させることにします。追加するコンポーネント以下の6つになります。
- Avalon ALTPLL (PLL) ... 倍速クロックとメモリ用クロック
- Nios II Processor (Processors) ... CPU
- System ID Peripheral (Peripherals → Debug and Performance) ... 必須
- JTAG UART (Interface Protocols → Serial) ... デバッグ通信用、必須
- PIO (Peripherals → Microcontroller Peripherals) ... LED用のPIO
- SDRAM Controller (Memories and Memory Controllers → SDRAM) ... RAM
クロックコンポーネントは最初から入っているので計7つになります。かっこの中はComponent Libraryのツリービューの中での位置になります。
(4) Qsysでの作業の概要
基本は画面左側のComponent Libraryから追加したいコンポーネントをダブルクリックしてシステムに追加し、パラメータを決めていきます。パラメータはコンポーネントそのもののダイアログで決めるものの他に以下が必要になります。
- Connection クロックやリセット、バスとの接続を決めます
- Name コンポーネントの名前を決めます。
- Export 外部信号の名前を決めます。これはQsysのモジュール(今回はNiosSystem)のパラメータに反映されます。
- Base cpuから制御するためのメモリマップドI/Oのアドレスを決めます。
SOPC Builderだと、ConnectionやBaseはデフォルトの動作である程度自動入力してくれていましたが、Qsysは全部手動で入力する必要があります。
(5) コンポーネントの追加 ALTPLL
Component LibraryのツリービューからPLL→Avalon ALTPLLを追加します(ダブルクリックもしくは+Add...ボタン)。
ALTPLLのダイアログが表示されます。
page 1/11では、speed gradeを6に、入力クロックを50MHzにします。
page 6/11ではPLLの出力クロックc0の倍率を2倍にします(入力は50MHzなので100MHz)
page 7/11では、Use this clockのラジオボタンをチェックして出力クロックc1を有効にします。それからc1の倍率を2倍にして位相(Clock phase shift)を-60度にします。
この-60度というのは、DE0のサンプルプロジェクトが-60度だったので、それにあわせました。全く根拠はありません。たまたま動いているのでこの値にしていますが、本当はちゃんと決めなければいけないはずです。残念なことに決め方はさっぱり分かりません。
ダイアログ内の設定は以上なのでFinishボタンを押して完了します。
c0はシステム全体のクロック、c1はSDRAM専用のクロックです。
ALTPLLを登録した直後のQsysの画面です。
Errorが2つとWarningが4つ出ています。ConnectionsとExportを決めてErrorとWarningを減らします。BaseはまだCPUがいないので入力できません。後で入力します(というか、最初にCPUを追加すればよかったと少し反省)
- clk_0コンポーネントのclk出力をinclk_interfaceに接続(Connectionsのあたりにマウスを持っていくと接続の絵が出るので白丸をクリックして黒丸に変えます)
- clk_0コンポーネントのclk_reset出力をinclk_interface_resetに接続
- altpll_0_c1のExport名を決定(シングルクリックで候補名が出るので必要なら修正してEnterを押します。今回は修正していません)
- 同じくareset_conduitのExport名を決定
- 同じくlocked_conduitのExport名を決定
- 同じくphasedone_conduintのExport名を決定
編集中の画面です。Connectionsのあたりにマウスカーソルを持っていくと表示される接続の図です。白丸をクリックして黒丸に変えます。また、Export名も決めています。
以上が完了したときのQsysの画面です。
警告が1つに減っています。ALTPLLのAvalon-SlaveをAvalon-MM masterにつないでいないという警告が出ています。CPU(マスター)がまだいないので、この警告は後で消します。
※Qsysはすべてのエラーと警告を消すようにしてください。消さないと大抵動作しません。
(6) コンポーネントの追加 Nios II Processor
Component LibraryのProcessorsにあるNios IIを追加します。
コンポーネント専用ダイアログでは、Nios II CoreをNioss II/eを選択します。ここで間違ってNios II/sやNios II/fを選ぶと、時間制限付きのコアになってしまって後が面倒です。また、後でNios II/eに戻しても時間制限付きのまま元に戻せなくなるので注意が必要です。
エラーが出ていますが、ここでは消せないのでFinishを押してダイアログを終了します。
Qsysの画面で(5)と同じようにConnectionsをつなぎます。
- nios2_qsys_0のclkをalt_pll_0のc0に接続します
- nios2_qsys_0のreset_nをclk_0のclk_resetに接続します
- altpll_0のpll_slaveをnios2_qsys_0のdata_masterに接続します((5)でつなげていなかったのでここで接続)。
6個のエラーと1つの警告が4個のエラーと警告なしになります。リセットベクターと例外ベクターを設定していないというエラーは、まだメモリがないので消せません。
各コンポーネントのほにゃ_slave(たとえばpll_slave)はnios2のdata_masterにつなぎます。resetはclk0のclk_resetにつなぎます。clkはaltpll_0のc0につなぎます。
(7) コンポーネントの追加 System ID Peripheral
Componet LibraryのPeripherals → Debug and PerformanceからSystem ID Peripheralを追加します。
Connectionsは以下の3つです。
- clkをalt_pll_0のc0に接続します
- resetをclk_0のclk_resetに接続します
- control_slaveをnios2_qsys_0のdata_masterに接続します
今回は、Connectionsの他にBaseも決めなければいけません。メモリマップドI/Oの番地がaltpll_0と重なっているからです。altpll_0が0x00000000~0x0000000fを占有しているので0x00000010ということにしました。変更はBaseの0x00000000の所をダブルクリックして編集します。
編集後の画面です。
(8) コンポーネントの追加 JTAG UART
Componet LibraryのInterface Protocols → SerialからJTAG UARTを追加します。
Connectionsは以下の3つです(System IDと一緒です)。
- clkをalt_pll_0のc0に接続します
- resetをclk_0のclk_resetに接続します
- control_slaveをnios2_qsys_0のdata_masterに接続します
Baseは重ならないように0x00000020にしました。
編集後の画面です。
(9) コンポーネントの追加 PIO
専用ダイアログではビット長や入出力を選択できます。デフォルトでは8ビット出力なのでそのままFinishします。
Componet LibraryのPeripherals → Microcontroller PeripheralsからPIO (Parallel I/O)を追加します。
Connectionsは以下の3つです。
- clkをalt_pll_0のc0に接続します
- resetをclk_0のclk_resetに接続します
- s1をnios2_qsys_0のdata_masterに接続します
Baseは重ならないように0x00000030にしました。
Exportで出力ポートを指定してやります。
編集後の画面です。
(10) コンポーネントの追加 SDRAM Controller
Componet LibraryのMemories and Memory Controllers → SDRAMからSRAM Controllerを追加します。
専用ダイアログでは、SDRAMのパラメータを設定します。
- PresetsはCustom
- データ幅は16bit
- Rowアドレスビットは13bit
- Columnアドレスビットは9bit
2ページ目ではタイミングの設定をしますが、今回は何もしなくてもそのまま動きました。本当はデータシートをちゃんと見て設定しなければいけません。
Connectionsは以下の4つです。
- clkをalt_pll_0のc0に接続します
- resetをclk_0のclk_resetに接続します
- s1をnios2_qsys_0のdata_masterに接続します
- s1をnios2_qsys_0のinstruction_masterに接続します(他と違う点です)。
Nios IIは命令(instruction)をSDRAMからfetchするので、instruction_masterにも接続してやる必要があります。他のペリフェラルからは命令を読み込まないのでinstruction_masterに接続する必要はありません。
Baseは0x02000000にしました。
Exportで出力ポートを指定してやります。
ようやっとメモリができたので、Nios IIのリセットベクタと例外ベクタを設定することでエラーを消してやります。
編集後の画面です。
エラーも消えています。
以上でコンポーネントの追加はおしまいです。
(11) システムの生成
まずは今までの結果をセーブしておきます(ctrl+S等)。
システムの生成はGenerationタブでGenerateボタンを押します。
システム生成中はダイアログが出ます。
問題がなければ以下のような画面になるはずです。
Warningが2つでています。このWarningの消し方はまだ分かっていません。ご存知の方は教えていただけるとありがたいです。
Warning: system: "No matching role found for jtag_uart_0:avalon_jtag_slave:dataavailable (dataavailable)"
Warning: system: "No matching role found for jtag_uart_0:avalon_jtag_slave:readyfordata (readyfordata)"
以上でQsysでシステムを作ることができました。
コンポーネントの名前の変更ですが、名前の場所をクリックしてからF2キーを押して編集します。
4. 論理合成の前にやっておくこと
まずは、できあがったQsysのファイルをプロジェクトに追加します。Settings(Assignmentメニュー→SettingsもしくはツールバーのSettingsボタン)のFiles Category(左側のペインの上から2番目)でNiosSystem.qsysを追加します(今回はNiosSystem.qsysというファイル名でセーブしました)。ついでにDE0_Nano.vも追加しておきます。
次にQsysのモジュールを呼び出すようにメインのDE0_Nano.vを修正します。QsysのHDL ExampleというタブにQsysのモジュールの呼び出し例ができています。
CopyボタンでクリップボードにコピーしてDE0_Nano.vに貼り付けてから修正します。以下が修正結果です。
//======================================================= // Structural coding //======================================================= NiosSystem u0 ( .clk_clk (CLOCK_50), // clk.clk .reset_reset_n (KEY[0]), // reset.reset_n .altpll_0_areset_conduit_export (1'b0), // altpll_0_areset_conduit.export .altpll_0_locked_conduit_export (), // altpll_0_locked_conduit.export .altpll_0_phasedone_conduit_export (), // altpll_0_phasedone_conduit.export .altpll_0_c1_clk (DRAM_CLK), // altpll_0_c1.clk .pio_0_external_connection_export (LED), // pio_0_external_connection.export .sdram_0_wire_addr (DRAM_ADDR), // sdram_0_wire.addr .sdram_0_wire_ba (DRAM_BA), // .ba .sdram_0_wire_cas_n (DRAM_CAS_N), // .cas_n .sdram_0_wire_cke (DRAM_CKE), // .cke .sdram_0_wire_cs_n (DRAM_CS_N), // .cs_n .sdram_0_wire_dq (DRAM_DQ), // .dq .sdram_0_wire_dqm (DRAM_DQM), // .dqm .sdram_0_wire_ras_n (DRAM_RAS_N), // .ras_n .sdram_0_wire_we_n (DRAM_WE_N) // .we_n );
以上で論理合成前にやっておくことは完了です。後は論理合成してから、できあがったDE0_Nano.sofをDE0 Nanoに書き込んでやります。
一つ注意点としてはsofファイルを書き込んだ後でprogrammerを終了しておかないと、programmerがUSB Blasterをつかんだままになって、Nios II Software Build Tools for EclipseがUSB Blasterを見つけられなくなることです。programmerは書き込みが終わったら終了しておきましょう。
7. ソフト開発
Nios II Software Build Tools for Eclipseを立ち上げます。起動はいくつかの方法があります。windowsのスタートメニュー、インストール時に作られるテスクトップのショートカット、Quartus IIのToolsメニュー、QsysのToolsメニュー等から起動できます。
Eclipseなので最初はworkspaceの場所を聞いてきます。場所は、今回のプロジェクトの一階層下にworkspaceというフォルダを掘って、そこにしました。9.0の頃はプロジェクトのフォルダそのものにすることもできましたが、10.0以降は一階層下にフォルダを作らなければいけなくなりました。
Fileメニュー → New → Nios II Application and BSP from Templateを選ぶと次のダイアログが表示されます。
- SOPC Information File Name欄。自分のプロジェクトフォルダにできているNiosSystem.sopicinfoを選びます
- CPU nameはsopcinfoファイルから読み取られて自動で入力されます。
- Project nameは今回はHelloSmallにしました。
- TemplateはHello World Smallにしました。
このまま実行すればHello from Nios II!というメッセージが見れます。今回はLEDチカチカもするのでソース(hello_world_small.cを修正します。
#include <stdint.h>
#include "sys/alt_stdio.h"
#include "system.h"
#define led (*(uint8_t *)PIO_0_BASE)
int main()
{
volatile uint32_t t;
alt_putstr("Hello from Nios II!\n");
led = 0x00;
while (1){
for(t = 0; t < 20000; t++) ;
led++;
}
return 0;
}
修正したらctrl+Sでファイルをセーブしておきます。
pio_0のI/OアドレスはQsysでは0x30番地にしました。system.hの中ではPIO_0_BASEが0x30で#defineされています。Qsysの中でモジュール名をpio_0でなくたとえばLEDとかにしておくとsystem.hの定義もPIO_0_BASEでなくLED_BASEという名前になります。PIO関連はソフト使用時にも影響があるので、ちゃんと名前を定義しておく方がいいです。
8. プログラムの実行
EclipseのProject Explorerでプロジェクト名(今回はHelloSmall)をクリックして灰色にしてから、Runボタンを押すとRun Asダイアログが表示されます。
Nios II Hardwareを選んでからOKを押すと実行開始です。
初めての実行のときや何かエラーがあるときはRun Configurationの画面が出ることがあります。Target ConnectionのタブでRefresh Connectionsのボタンを押すとエラーが取れて通信可能になる場合があります。Refresh Connectionsボタンは、FPGAボードに書き込まれているNios IIのシステムと通信してSystem IDの照合を行います。
何らかの理由でシステムが死んでいたり、programmerがJTAGをつかんでいて通信できなかったりといったときはRefresh Connectionsボタンを押しても復活しません。
また、Qsysでシステムの修正を行ってGenerateをやり直すとタイムスタンプが一致しなくなるのでRefresh Connectionsでエラーが出ます。この場合はGenerate BSPを行ってBSPを作り直してやると直ります。Generate BSPはBSP Editorの中や、Project Explorerのbspプロジェクト名を右クリックして出るメニューのNios IIにあります。BSP EditorはNios IIメニュー等にあります。
というわけで、やたら長い記事になってしまいました。間違いや、ここはこうした方がいい等コメントを頂けるとありがたいです。特にSDRAMに関してはデータシートもろくに見ずにやってみたらたまたま動いているという状況なので、ちゃんとしたパラメータはこうだ、というのを教えていただけるとありがたいです。
AlteraのAppNote
http://www.altera.co.jp/literature/an/an632.pdf
を見ると、以前のAvalon-MMにはあったフロー制御関連の信号、readyfordataとdataavailableが無くなったみたいです。代わりにAvalon-STを使うように、という感じですね。
IPによってはこの変更が追いついていないのでしょう。使っていなくても信号だけは宣言してるとか、よく見かけます。
今のところ無視で良さそうです。
丁寧な解説と貴重な情報ありがとうございます。今後のバージョンに期待ですね。SOPC builderの頃はとにかくwarningを消さないとひどい目にあっていたので恐怖症になっています^^
2点教えて下さい。
1.assign led=switch;でSW0でLED60をON/OFF 出来る事判りましたが、
A.LED60を100msでON/OFFしたいのですが、どの 様にCodeingするのでしょうか?
(softのWaitをLogicで作成する必要が有ると
思うのですが?)
B.module endmodule間はル-プしますか?
2.目標は16x2のCharctorLCD表示ですが
下記参考URLを見つけました。
これは、VerilogHDL記述なのでしょうか?
http://www.fpga4fun.com/TextLCDmodule.html
1.の方は基本中の基本です。たぶん探せば見つかると思います。ヒントは状態を記憶するためにはフリップフロップを使うが、verilogでフリップフロップを記述するにはどう書けばよいか、といったあたりになります。
2.はちらっと見てみましたが、verilogはverilogなのですが、PCから受け取ったデータをLCDに垂れ流しているだけです。タイミングを取って初期化したりとかは全部PC側がやっているみたいでした。
お返事ありがとうございます。
verilog少し解かりかけてきました。
今ちょうど、FlipFlopが動作しました。Timer
(非同期回路、同期回路)のProgramを入力しましたが、動作しませんでした。私は、QuartusⅡ
11.0sp1を使用していますが、著者は10.0を使用している?のか、Errorが出てしまいます。
勉強したばかりなのでErrorの外し方の検討が付きません。英語の勉強よりも、記述の基本を学ぶ必要が有ると考えています。
optimizeさんからEPM570T100C6を購入してあり
SampleでLEDのON/OFFが例題が組んで有りました
FlipFlopかCounterが組んで有るみたいでした。じっくり勉強してみるつもりです。
ご返事ありがとうございました。
DE0-NanoとQsysを使い始めたばかりで,丁寧な解説がとても参考になります.
手順通りに進めていった際に気づいたことが2点ほどあります.
ネットで調べて解決しましたが,今後参照される方のために,情報を残しておきます.
1.(8)のJTAG UART追加の際に,IRQのコラムで,Nios IIと接続し,IRQの値を設定する必要があるかと思います.
2.(10)のSDRAMの説明で,Nios IIのリセットベクタと例外ベクタを設定する画像が,SDRAMパラメータ設定のものになっています.
実際には,nios2_qsys_0を開き,vector memoryにSDRAMを選ぶことになるかと思います.
おかげさまで,無事にLEDの点滅までたどりつけました.
次は,自分のコンポーネントへのアクセスにチャレンジしてみたいと思います.
フォローありがとうございます。とても助かります。特にJTAG UARTの件は全く気づいていませんでした。
技術評論社の「FPGAボードで学ぶ組込みシステム開発入門 ~Altera編~」という本にQsysの話がちらっと載っていたりします。
http://gihyo.jp/book/2011/978-4-7741-4839-7
今後ともよろしくお願いします。
こちらを参考に DE0 nano で Qsys と NIOS II を動かすことが出来ました。
ただ、Quartus II 13.0 では、サンプル・プログラムのヘッダー・ファイルが参照されず、Eclipse のサーチ機能でパスを調べ、パスを追加したところ無事に動きました。
ここに変更したパスの画像があります。
http://sdr-de-bcl.blog.so-net.ne.jp/2013-12-12
それと、Terasic のサイトにある付属 CD-ROM の最新版には、Qsys を使って NIOS II の組み込みとプログラムの作成を行うチュートリアルの PDF が入るようになりました。 ただし、内容に不備が多く、気をつけないと完動しません。
今となっては古いバージョンの情報ですが、お役に立てたようで幸いです。
ブログ記事、拝見しました。色々と新しい情報があって、とても参考になりました。ありがとうございます。
今後ともよろしくお願いします。
warningも出ずに、コンパイルできるのですがEclipseの方で、sopcファイルを読み込んでもcpu nameが出ないという問題に苦しんでいます。
何か思い当たるところはありますでしょうか?