さて前回、PL領域だけでのLED点滅が終わりました。
これでは今までの普通のFPGAと同じでした。
次は未知なPS領域を使うことにします。
ちなみにツールはVivado+SDKでバージョン2019.1です。
以下のTutorialに沿ってやってみます。
Getting Started with Vivado IP Integrator [Reference.Digilentinc]
Vivado起動
前回詳しく書いたので細かい手順は簡潔に書いていきます。
Create Project
Next
Project nameには Tutorialではblinkyとなってますが、前回のとダブるので blinkyPSとでも変えておきました。
Next
Next
Next
Finish
はい。これで基本の設定が出来ました。
回路作成
回路っていうのかな、構成を作るイメージですかね。
IP Integratorってのを使います。
FlowNavigatorの中の IP INTEGRATOR → Create Block Design をクリック。
名前を変えてもいいですが、ここはデフォルトのまま。
OK
Boardのタブをクリックしてみます。
Z7-10のPSに接続されたペリフェラルの情報が反映されてますね。あー楽ちん。
ペリフェラルはまだ接続されていませんので接続していきます。
まずは4つのボタン。ボタンなのでGPIOですね。ってOは不要ですが。
4 Buttons を右クリック → Connect Board Component
AXI GPIO → GPIOを選択します。
OK。
すると、DiagramペインにAXI GPIOが出てきました。
今度は4つのLEDです。LEDなのでこちらもGPIOですね。こちらはIは不要ですが。
で、同様に4LEDsの方にもGPIO2をアサインします。GPIO2はいくつかありますが、先に作ったaxi_gpio_0の中にあるGPIO2です。
ついでに 2 RGB LEDの方もアサインしておきましょう。
先のAXI GPIOはGPIOが残ってないので、新しいAXIGPIOへのアサインになります。
すると2つのAXI GPIOがDiagramに現れたかと思います。
このDiagramペインの+アイコン(若しくはウィンドウ内で右クリックでAddIPでもOK)をクリックします。
Searchの中にZynqといれればZYNQがすぐに見つかります。
そのZYNQをダブルクリック。
Diagramの中にZYNQが現れたかと思います。
Run Block Automation をクリックします。
このままOK。
DDRとFIXED_IOが接続されたようです。
今度はRun Connection Automation をクリックします。
すると先ほど設置したAXI_GPIOが出てきます。
S_AXIを選択して、Clock sourceをFCLK_CLK0に設定しておきます(2つのS_AXIともに)。
あとはAutoでいいのかな?
で、OK
なんか一気に複雑になりましたね。全部つながったのかな。
追加されたのはAXI Interconnect、ProcessorSystemnReset。
ここでValidate Designアイコンをクリックします(右クリックからでもOK)。
これでRTLも書かずに回路が出来上がったことになります。
SDKへの準備
Sourcesタブのdesign_1を右クリックしてCreate HDL Wrapper。
Optionsの選択はこのままでOK。
これでBitStreamを作ってみます。
Generate Bitstream
問題なければ無事に終了です。
これで、PL領域を使っていないPS領域のみのbitファイルが出来たことになりますかね。
SDKの出番なので、SDKの方に持っていくデータを作ります。
File → Export → Export Hardware
Include bitstreamにチェックを入れてOK
SDK起動
SDKの準備ができたのでSDKの起動します。
VivadoのFileメニューから起動できます
File → Launch SDK
ダイアログには特にデフォルトのままでOK
SDKが立ち上がって勝手にHW情報がインポートされたようです。
これからC Projectを作っていきますので、
File → New → Application Project
プロジェクトの設定はTutorialにならって以下のようにしました。
ちなみにHardware Platformに今インポートした今回のHW情報が選択されてるはずです。
その下はプロセッサ指定で、2個あるCoretexA9の0番目をしていていることになります。
ここでFinishを選択せずにNextをクリックします。
するとテンプレートを聞かれますので、Empty Applicationを選択してFinish
色々なアプリを作る際にはここで最適なテンプレートを選んでいくんでしょうね。
cソース作成
次に実際のCを書いていきます。
ProjectExplorerに現れている先ほど指定したプロジェクト名のzynq-gsgの下のsrcを選択して右クリック New → Source File
ファイル名はmain.cとしてFinish
空のmain.cがviewペインに現れますので、そこに以下のように入力してセーブします。
色々な呪文が出てきました。とりあえず深く考えずに進めてみましょう。
また、Vivadoでの作業時に、RGBのLEDもアサインしたのにCではどう書けばいいの?っていう疑問が出てくるかと思います。
現時点での私も分かりませんので、今回は何もしないでとりあえず進めます。
実機確認
メニューバーから Xilinx → Program FPGAを選択。
現れるダイアログはデフォルトのまま。
Programを押す前に
ボードにUSB接続して電源を入れます。
TeraTerm等のターミナルソフトを起動します。設定は以下の通りです。
ポート番号は各自の環境によりますよ。
Program後、Project Explorerから zynq-gsgを右クリックして、Run As → Launch on Hardware (System Debugger)。
するとプログラムが走り始めたようで、端末には以下のように表示されてました。
ずっと書き換えているようでカーソルは動きっぱなしです。
ここでボードのBTN0~BTN3を押してみましょう。
例えばBTN0を押すと表示が変わるともに:ld0~ld3の4つのledが点灯しました。
これが今回作成したPS部のH/WとCortexで動いているS/Wの実行結果ということになります。
ソースを見てみる
Cのソースはコメントもあるし簡単なので何をやっているのかはわかるかと思います。
わからないのはおまじない部分ですね。
XGpio gpio;
でハンドルを作成。
XGpio_Initialize(&gpio, 0);
で、そのイニシャライズ
ってのはまぁ最初のおまじないですね。
ただ、この0ってのがなんで0なの?何これ?ってわからなくて、色々と調べたらデバイスIDで、GPIOのブロックごとにナンバリングされるのねってのがわかりました。
するとGPIOを何個も置いても使えるってことですね。
ただ、自分が作ったGPIOが2個ありますが、どっちが0でどっちが1なの?っていうか0の次は1ってインクリメントするだけなの?ってのがわかりません。
どのドキュメントを見ればこういうのが載っているのかさっぱりです。
で、ようやく調べて、
.\blinkyPS.sdk\zynq-gsg_bsp\ps7_cortexa9_0\include\xparameters.h
にあることを見つけました。
#define XPAR_XGPIO_NUM_INSTANCES 2
GPIOブロックを2個使ってますよってことなんでしょう。
/* Definitions for peripheral AXI_GPIO_0 */
#define XPAR_AXI_GPIO_0_BASEADDR 0x41200000
#define XPAR_AXI_GPIO_0_HIGHADDR 0x4120FFFF
#define XPAR_AXI_GPIO_0_DEVICE_ID 0
#define XPAR_AXI_GPIO_0_INTERRUPT_PRESENT 0
#define XPAR_AXI_GPIO_0_IS_DUAL 1
/* Definitions for peripheral AXI_GPIO_1 */
#define XPAR_AXI_GPIO_1_BASEADDR 0x41210000
#define XPAR_AXI_GPIO_1_HIGHADDR 0x4121FFFF
#define XPAR_AXI_GPIO_1_DEVICE_ID 1
#define XPAR_AXI_GPIO_1_INTERRUPT_PRESENT 0
#define XPAR_AXI_GPIO_1_IS_DUAL 0
あ、0と1でいいんですね。ってわかります。
なので、
XGpio_Initialize(&gpio, 0);
と、書くよりも
XGpio_Initialize(&gpio, XPAR_AXI_GPIO_0_DEVICE_ID );
の方がいいのかなって思います。
続いてソースのこちらの部分。
XGpio_SetDataDirection(&gpio, 2, 0x00000000); // set LED GPIO channel tristates to All Output
XGpio_SetDataDirection(&gpio, 1, 0xFFFFFFFF); // set BTN GPIO channel tristates to All Input
まぁこれはコメントもあるのでわかりやすいですね。
GPIOは文字通りInputにもOutputにも使えますので、その方向の定義です。
2つを見比べると、0を設定すると出力、1を設定すると入力になっているようです。
2番目の引数の1とか2というのはGPIOブロックの1個目のポート、2個目のポートという意味でしょうか。
AXI GPIOv2.0のプロダクトガイドを見るとチャネルが2個あることがわかります。
なので、2チャネル使っている方は、XPAR_AXI_GPIO_0_IS_DUALが1に設定されているんでしょうね。
なので、GPIOのチャネル2の方はすべて出力、チャネル1はすべて入力っていう設定を行っているってことなんでしょう。
4bitしか使ってないのに32bit分全部設定しなくてもいいような気もしますけどね。
以上が最低限の設定であとはwhile(1)で無限ループの中で、
btn = XGpio_DiscreteRead(&gpio, 1);
GPIOのチャネル1の状態を読み出してled出力をセットしています。
if (btn != 0) led = 0xFFFFFFFF;
else led = 0x00000000;
どこのボタンが押されていても全点灯させるための処理ですね。
XGpio_DiscreteWrite(&gpio, 2, led);
それをGPIOに出力(点灯)。
xil_printf(“\rbutton state: %08x”, btn);
printfのXilinx版でしょうかね。UG643に載ってました。printfの軽量版なようです。これで、コンソールにも出力します。
っていう処理ということですね。
こういうXGpio_*な関数の説明がどこかに載ってるんでしょうね。
DocNavっていうドキュメントシステムはあるんですがうまく探せません。
ググってもXilinxよりも普通の人のページがヒットします。その方々はどこから情報を得たのかって書いてないのでわかんないです。ひょっとして常識???
で、Xilinxオフィシャルっぽいものとしては、ここが唯一ヒットしました。
ですが、gpioじゃないトップに行けないし、gpioだけでこのページがあるのかな?
とまだまだ謎が多いです。
RGBのLED制御とかしたいけど、まずはそれを探してからです。
と、チュートリアルに沿ってPS動かしてみました。
次はVitisでやってみるかな。
コメント