ケロロ好きなエンジニアのブログ

サラリーマンエンジニアの電子工作のことをメインに書いていきたいけど電子工作はまとまった時間がないとなかなか難しいから滅多に書けそうもなくてMVNOの話題がメインになりつつあるブログ

ZYBO PS領域に挑戦 SDKの出番

にほんブログ村 スマホ・携帯ブログへ にほんブログ村 スマホ・携帯ブログ 格安SIMカード・MVNOへ

スポンサーリンク

さて前回、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とでも変えておきました。

f:id:keroctronics:20200406173804p:plain

Next

 

f:id:keroctronics:20200406173844p:plain

Next

 

f:id:keroctronics:20200406173957p:plain

Next

 

f:id:keroctronics:20200406174026p:plain

Finish

 

はい。これで基本の設定が出来ました。

回路作成

回路っていうのかな、構成を作るイメージですかね。

IP Integratorってのを使います。

FlowNavigatorの中の IP INTEGRATOR → Create Block Design をクリック。

 

名前を変えてもいいですが、ここはデフォルトのまま。

f:id:keroctronics:20200406174315p:plain

OK

 

Boardのタブをクリックしてみます。

f:id:keroctronics:20200406174356p:plain

Z7-10のPSに接続されたペリフェラルの情報が反映されてますね。あー楽ちん。

 

ペリフェラルはまだ接続されていませんので接続していきます。

まずは4つのボタン。ボタンなのでGPIOですね。ってOは不要ですが。

 

4 Buttons を右クリック → Connect Board Component

f:id:keroctronics:20200406174524p:plain

 

AXI GPIO → GPIOを選択します。

f:id:keroctronics:20200406174632p:plain

OK。

すると、DiagramペインにAXI GPIOが出てきました。

f:id:keroctronics:20200406174715p:plain

 

今度は4つのLEDです。LEDなのでこちらもGPIOですね。こちらはIは不要ですが。

で、同様に4LEDsの方にもGPIO2をアサインします。GPIO2はいくつかありますが、先に作ったaxi_gpio_0の中にあるGPIO2です。

f:id:keroctronics:20200406174749p:plain

 

ついでに 2 RGB LEDの方もアサインしておきましょう。

先のAXI GPIOはGPIOが残ってないので、新しいAXIGPIOへのアサインになります。

f:id:keroctronics:20200406174830p:plain

 

すると2つのAXI GPIOがDiagramに現れたかと思います。

f:id:keroctronics:20200406174913p:plain

 

このDiagramペインの+アイコン(若しくはウィンドウ内で右クリックでAddIPでもOK)をクリックします。

Searchの中にZynqといれればZYNQがすぐに見つかります。

f:id:keroctronics:20200406175003p:plain

そのZYNQをダブルクリック。

 

Diagramの中にZYNQが現れたかと思います。

f:id:keroctronics:20200406175041p:plain

 

Run Block Automation をクリックします。

f:id:keroctronics:20200406175112p:plain

このままOK。

 

DDRとFIXED_IOが接続されたようです。

f:id:keroctronics:20200406175200p:plain

 

今度はRun Connection Automation をクリックします。

すると先ほど設置したAXI_GPIOが出てきます。

f:id:keroctronics:20200406175229p:plain

S_AXIを選択して、Clock sourceをFCLK_CLK0に設定しておきます(2つのS_AXIともに)。

あとはAutoでいいのかな?

で、OK

 

なんか一気に複雑になりましたね。全部つながったのかな。

f:id:keroctronics:20200406175403p:plain

追加されたのはAXI Interconnect、ProcessorSystemnReset。

 

ここでValidate Designアイコンをクリックします(右クリックからでもOK)。

 

これでRTLも書かずに回路が出来上がったことになります。

SDKへの準備 

Sourcesタブのdesign_1を右クリックしてCreate HDL Wrapper。

f:id:keroctronics:20200406175525p:plain

 

Optionsの選択はこのままでOK。

f:id:keroctronics:20200406175554p:plain

 

これでBitStreamを作ってみます。

Generate Bitstream

 

問題なければ無事に終了です。

これで、PL領域を使っていないPS領域のみのbitファイルが出来たことになりますかね。

 

SDKの出番なので、SDKの方に持っていくデータを作ります。

File → Export → Export Hardware

f:id:keroctronics:20200406175749p:plain

 

Include bitstreamにチェックを入れてOK

f:id:keroctronics:20200406175819p:plain

 

SDK起動

SDKの準備ができたのでSDKの起動します。

VivadoのFileメニューから起動できます
File → Launch SDK

f:id:keroctronics:20200406183321p:plain

 

ダイアログには特にデフォルトのままでOK

f:id:keroctronics:20200406183352p:plain



SDKが立ち上がって勝手にHW情報がインポートされたようです。

f:id:keroctronics:20200406183433p:plain

 

これからC Projectを作っていきますので、
File → New → Application Project

f:id:keroctronics:20200406183504p:plain

 

プロジェクトの設定はTutorialにならって以下のようにしました。

f:id:keroctronics:20200406183531p:plain

ちなみにHardware Platformに今インポートした今回のHW情報が選択されてるはずです。

その下はプロセッサ指定で、2個あるCoretexA9の0番目をしていていることになります。

ここでFinishを選択せずにNextをクリックします。

 

するとテンプレートを聞かれますので、Empty Applicationを選択してFinish

f:id:keroctronics:20200406183633p:plain

色々なアプリを作る際にはここで最適なテンプレートを選んでいくんでしょうね。

 

cソース作成

次に実際のCを書いていきます。


ProjectExplorerに現れている先ほど指定したプロジェクト名のzynq-gsgの下のsrcを選択して右クリック New → Source File

ファイル名はmain.cとしてFinish

f:id:keroctronics:20200406183802p:plain

 

空のmain.cがviewペインに現れますので、そこに以下のように入力してセーブします。

f:id:keroctronics:20200406183837p:plain

色々な呪文が出てきました。とりあえず深く考えずに進めてみましょう。

また、Vivadoでの作業時に、RGBのLEDもアサインしたのにCではどう書けばいいの?っていう疑問が出てくるかと思います。

現時点での私も分かりませんので、今回は何もしないでとりあえず進めます。

 

実機確認

メニューバーから Xilinx → Program FPGAを選択。

f:id:keroctronics:20200406184012p:plain

 

現れるダイアログはデフォルトのまま。

f:id:keroctronics:20200406184039p:plain

Programを押す前に

ボードにUSB接続して電源を入れます。

TeraTerm等のターミナルソフトを起動します。設定は以下の通りです。

f:id:keroctronics:20200406184207p:plain

ポート番号は各自の環境によりますよ。

 

Program後、Project Explorerから zynq-gsgを右クリックして、Run As → Launch on Hardware (System Debugger)。

f:id:keroctronics:20200406184330p:plain

 

するとプログラムが走り始めたようで、端末には以下のように表示されてました。

f:id:keroctronics:20200406184352p:plain

ずっと書き換えているようでカーソルは動きっぱなしです。

ここでボードのBTN0~BTN3を押してみましょう。
例えばBTN0を押すと表示が変わるともに:ld0~ld3の4つのledが点灯しました。

f:id:keroctronics:20200406184435p:plain

 

これが今回作成した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: Main Page

ですが、gpioじゃないトップに行けないし、gpioだけでこのページがあるのかな?

とまだまだ謎が多いです。

RGBのLED制御とかしたいけど、まずはそれを探してからです。

 

と、チュートリアルに沿ってPS動かしてみました。

 

次はVitisでやってみるかな。