Zynqでプログラミング(2) - GPIO -
開発環境
開発環境は以下の通り。
開発用PC
- Windows10 64bit
- メモリ:32GB
- SSD:512GB
環境
ZYBO Z7-20
参考サイト:XILINX公式 ZYBO Z7-20
- Vivado 2018.2
- TeraTerm ver4.90
ZYBOの汎用I/O(GPIO)
ZYBOには、以下のような入出力素子が搭載されている。これらをPL部のFPGAとPS部のアプリケーションを組み合わせて使えるようにしていく。
-
入力(項目:接続されている場所)
- スイッチ(SW0~SW3):PL部
- ボタン(BTN0~BTN3):PL部
- ボタン(BTN4, BTN5):PS部(MIO)
-
出力(項目:接続されている場所)
- LED(LD0~LD3):PL部
- LED(LD4):PS部(MIO)
スイッチ操作でのLEDの点灯
PL部のスイッチ(SW0~SW3)とLED(LD0~LD3)使うアプリケーションを作成し、実行する。
AXIバスや、PS部からドライバ使用するプロジェクトなので、これから非常に重要になる。
参考サイト:ZYBO (Zynq) 初心者ガイド (4) PLのAXI GPIOでPSからLチカ
1. プロジェクトの作成~ビットストリーム生成まで
Zynqでプログラミング(1) - Helloworld -と同様の方法で、Vivadoプロジェクトを「gpio」という名前で作成し、ブロックデザインを作成する。
ブロックデザインに、「ZYNQ7 Processing System」のIPコアを追加し、「Run Block Automation」しておく。
さらに、「AXI GPIO」のIPコアを追加して、そのIPコアをダブルクリックして設定を開く。
GPIO:sws 4bits/GPIO2:leds 4bitsに設定し、「OK」。これでFPGAとSW、LEDが繋がる。
「Run Connection Automation」でウィンドウ左のチェックを全て入れ、「OK」すると以下のようになる。
よく見ると、勝手にIPコアが追加されている。「Processor System Reset」はその名の通りPS部のリセットに使用される。特に触る必要もないし、今後もあまり触らないと思う。
肝心なのが、「AXI Interconnect」。AXIバスという、PL部(FPGA)とPS部(CPU)のデータの橋渡し機能を持つIPコアである。詳細については、かな~り長くなるので、Google先生に聞いてもらいたい。とりあえず今は、PL部とPS部を繋ぐアドレスバスとだけ覚えておいてほしい。
「Create HDL Wrapper」でwrapperファイルを作成し、「Generate Bitstream」でビットストリームを生成する。これでPL部(FPGA)は作成完了。
ビットストリームができるのを待っている間に、「Diagram」タブから「Address Editor」タブに切り替える。「processing_system7_0」>「Data」>「axi_gpio_0」のOffset Addressが0x4120_0000に設定されていることを覚えておく。
「File」>「Export」>「Export Hardware」でhdfファイルをエクスポート(「Include bitstream」にチェックを入れる)し、「File」>「launch SDK」よりSDKを起動する。
2. アプリケーションの作成
SDKのメニュー「File」>「New」>「Application Project」よりアプリケーション(App)プロジェクトを作成する。
Appプロジェクト名は「gpio_app」とし、「Hello World」を選択して「Finish」。
AXI_GPIOのドライバを使用して、PS部からPL部を介してSWとLEDに接続する。
helloworld.cを編集し、ZYBO上のスイッチとLEDを操作するソースコードを追加する。
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "xparameters.h" /* FPGA設定のヘッダ */
#include "xgpio.h" /* AXI_GPIOドライバのヘッダ */
/* GPIOで設定したCH */
#define SW_CHANNEL 1
#define LD_CHANNEL 2
/* AXI_GPIOドライバのインスタンス定義 */
XGpio gpio_0;
int main()
{
int status;
init_platform();
print("Hello World\n\r");
u32 sw_state;
/* AXI_GPIOドライバの初期化 */
status = XGpio_Initialize(&gpio_0, XPAR_GPIO_0_DEVICE_ID);
if(status != XST_SUCCESS)
{
xil_printf("XPAR_GPIO_0_DEVICE_ID initialization failed.\r\n");
return XST_FAILURE;
}
/* 入出力方向の設定 0:出力 1:入力 */
XGpio_SetDataDirection(&gpio_0, SW_CHANNEL, 0xFFFFFFFF); /* CH1(SW)は入力設定 */
XGpio_SetDataDirection(&gpio_0, LD_CHANNEL, 0x00000000); /* CH2(LD)は出力設定 */
while(1)
{
/* SWの値を読み出し */
sw_state = XGpio_DiscreteRead(&gpio_0, SW_CHANNEL);
/* SWの状態をLDに反映 */
XGpio_DiscreteWrite(&gpio_0, LD_CHANNEL, sw_state);
}
cleanup_platform();
return 0;
}
アプリケーション解説
アプリケーションの気になると所を解説していく。XILINXのドライバに関しては、ヘッダファイルやソースファイルに(英語だが)関数の機能や引数の詳細が書かれているため、そちらも参考にしてほしい。
XGpio gpio_0;
AXI_GPIOドライバを使用するために必要で、「XGpio」は xgpio.hに定義されている。XGpio_Initialize(&gpio_0, XPAR_GPIO_0_DEVICE_ID);
指定されたインスタンスと、デバイスIDを紐づけ。XPAR_GPIO_0_DEVICE_IDはxparameters.hに定義されている。
xparameters.hを見ると、XPAR_GPIO_0_DEVICE_IDは0x41200000。Vivadoで確認したアドレスと同じ。
もし、Vivadoでもう1つAXI_GPIOを追加したら、XPAR_GPIO_1_DEVICE_IDが生成される。XGpio_SetDataDirection(&gpio_0, SW_CHANNEL, 0xFFFFFFFF);
引数の2番目に設定されたCHを入力/出力設定する。引数の3番目のbit単位で0:出力/1:入力。
なので、SWは全て1(入力)の0xFFFFFFFF、LEDは全て0(出力)の0x00000000。XGpio_DiscreteRead(&gpio_0, SW_CHANNEL);
引数2番目のCHから値を読み出し、返り値(u32(unsigned int))にする。XGpio_DiscreteWrite(&gpio_0, LD_CHANNEL, sw_state);
引数2番目のCHに、引数3番目の値を書き込む。SWがONになっていればsw_stateの値が変化し、LEDも点灯する。
3. アプリケーションの実行
ZYBOの電源を入れ、「Program FPGA」でFPGAを焼きこみ、アプリケーションを実行する。
- TeraTermを開いていれば、「Hello World」が表示される
- ZYBO上のSW0~SW3をONにするとLD0~LD3が点灯。SWをOFFにすると消灯。
最後に
これで、XILINX標準のIPコアのドライバを使うところまではできた。
次は、タイマのIPコアを使って、割り込みを作っていく。
Author And Source
この問題について(Zynqでプログラミング(2) - GPIO -), 我々は、より多くの情報をここで見つけました https://qiita.com/L22yk21/items/efe7849a58ba3046f6c3著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .