LoginSignup
18
10

More than 5 years have passed since last update.

ZYBO (Zynq) 初心者ガイド (4) PLのAXI GPIOでPSからLチカ

Last updated at Posted at 2018-01-07

この記事の内容を4分で見る ( https://www.youtube.com/watch?v=WF7jMu78uwc )

環境

  • 開発用PC: Windows 10 64-bit
    • Vivado 2017.4 WebPACKライセンス
    • Xilinx SDK 2017.4
  • ターゲットボード: ZYBO (Z7-20)

Windows環境は1回目を参照。

PLのAXI GPIOでPSからLチカ

ややこしいタイトルです。前回は、PSのGPIOをPSのCPUから制御しました。今回は、PLのGPIOをPSのCPUから制御して、LEDをチカチカさせます。PLでGPIOを使うには、AXI GPIOというIPを使います。
まずVivadoでAXI GPIOをPL上に搭載して、それをPSから制御するようなソフトをSDKで実装します。

対象のLED

前回説明したように、MIOはPSからのみアクセスできます。今回はPLのGPIOなので、MIO以外のIOにつながっているLEDを使います。LD0~LD3(M14、M15、G14、D18)を使います。これは、Z7-20の場合です。他のボードだと異なるかもしれません。

ハードウェアの作成 (Vivado)

プロジェクトの作成

前回、または前々回に作成したプロジェクトをそのまま使います。ZYBO(Z7-20)ボード用のプロジェクトで、PSだけを搭載したブロックデザインが既にあるものとします。

AXI GPIOの配置

Block DesignのDiagramビューを開きます。現状、PSのみが配置されていると思います。
01.jpg

これに、AXI GPIOを追加します。AXI GPIOはXilinxによって用意されているIPで、AXIをインターフェースに持つGPIOです。AXI GPIOを追加して、それをLED用のIOに接続するようにします。そして、PSとAXIで接続させます。具体的には、以下のようにします。ほぼ自動で行われます。

  • Diagramビュー上で右クリック->Add IP->AXI GPIOを選択
  • Run Connection Automationをクリック
  • 下記の設定画面で、axi_gpio_0にチェックする
  • GPIOのSelect Board Part Interfaceにleds_4bitsを選ぶ

02.jpg

すると、以下のように自動的に接続してくれます。また、必要なIPを自動的に追加してくれます。AXI InterconnectはAXIバスを調停してくれる人です。今回はマスター(PS)とスレーブ(AXI GPIO)が1つしかありませんが、接続されるIPが増えると重要になります。Processor System Resetは、名前通りリセット管理をしてくれるのだと思います。
また、GPIOはleds_4bitsに接続されています。leds_4bitsは外に出ているピン(Exeternal Interface)になります。プロジェクト作成時にボードを指定しているので、わざわざピン番号を指定しないでも、leds_4bitsを指定することで適切なピンに割り当てることが出来ます。
03.jpg

設定を確認してみる (見るだけ)

この状態で、AXI GPIOをダブルクリックすることで、詳細を確認したり設定変更が出来ます。以下のようにGPIO(省略されているが、GPIO1ということ)は、leds_4bitsに接続されています。また、今回は使用していませんが、GPIO2があることから一つのAXI GPIOで2チャネル持てることが分かります。また、図は張りませんが、隣のIP Configurationタブを見ると、GPIO Widthも自動的に4になっています。
04.jpg

Address Editorタブで、各IPのレジスタのアドレスを編集出来ます。ここでは確認するだけにします。これを見ると、今回作ったAXI GPIO(axi_gpio_0)のアドレスは0x41200000のようです。
05.jpg

ビットストリームとhdfを作る

2回目でやったように、論理合成、配置配線をして、ビットストリームとhdfを作ります。その後、hdfをエクスポートします。

  • Sourcesタブでdesign_1を右クリック、Generate Output Products、その後、Create HDL Wrapper
  • Flow Navigator上で、Generate Bitstream
  • メニューバー -> File -> Export -> Export Hardware -> include bitstreamにチェックをつけてOK

結果を確認してみる (見るだけ)

ここまでやったら、次はSDKでソフトウェアの実装をするのですが、その前に作られたハードウェアの詳細をちょっと見てみようと思います。

Flow Navigator -> RTL ANALYSIS -> Open Elaborated Design をクリックします。すると、以下のように、Packageビューが表示されます。今回は、Block Designの所でピンアサインをしましたが、この画面から割り当てることもできます。
06.jpg

他にも、Schematicでブロック図を見れたり、Deviceタブでフロアマップを確認することが出来ます。

ソフトウェアの実装 (SDK)

前回からの続きでやっている場合は、Vivado上でhdfをエクスポート完了した時点で、SDK上で「更新しますか?」みたいなことを聞かれるので、OKをしてください。新しくプロジェクトを始めた場合は、VivadoからLaunch SDKしてください。これで、作成したハードウェアをベースにしたSDKプロジェクトが用意できました。

前回のPSのGPIOと同様に、レジスタ直叩きバージョンと、ドライバAPIを使うバージョンをやってみようと思います。

レジスタ直叩きでAXI GPIOを制御する

今回使用しているGPIOは、AXI GPIOというXilinxから提供されているIPです。そのため、仕様などはXilinxが提供しているドキュメントにあります。AXI GPIO v2.0 LogiCORE IP Product Guideを確認することで、レジスタオフセットアドレスや、設定すべき値が分かります。ベースアドレスは、Vivadoで自由に決めることが出来ますが、今回はVivadoが自動で割り当てたものを使用します。このベースアドレスは先ほど確認しました。

関係するレジスタを以下に挙げます。今回配置したAXI GPIOでは、Channel 1をLEDに接続しています。Channel2は未使用です。

  • AXI GPIOのベースアドレス: 0x41200000 (Vivadoで確認。変更可能)
  • GPIO_DATA (Channel 1 AXI GPIO Data Register)のオフセット: 0x0000
  • GPIO_TRI (Channel 1 AXI GPIO 3-state Control Register.)のオフセット: 0x0004

コード

GPIO_TRIに0を設定することで、出力モードにします。GPIO_DATAに0x0F/0x00を出力することで、4つのLEDを全部On/Offさせます。ちなみに、ベースアドレスは値直打ちではなくて、xparameters.hで定義されているXPAR_AXI_GPIO_0_BASEADDRを使用すべきです。

helloworld.c
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"

#define REG(address) *(volatile unsigned int*)(address)

#define GPIO_BASE (0x41200000)  /* XPAR_AXI_GPIO_0_BASEADDR */
#define GPIO_DATA (GPIO_BASE + 0x0000)
#define GPIO_TRI  (GPIO_BASE + 0x0004)

int main()
{
    init_platform();

    print("Hello World\n\r");

    /* Set all of 4 pins(LEDs) as output */
    REG(GPIO_TRI) = 0x00;
    while(1) {
        /* Set all of 4 pins(LEDs) as High */
        REG(GPIO_DATA) = 0x0F;
        sleep(1);
        /* Set all of 4 pins(LEDs) as Low */
        REG(GPIO_DATA) = 0x00;
        sleep(1);
    }

    cleanup_platform();
    return 0;
}

今回は、PLの実装もあるので、メニューバー -> Xilinx -> Program FPGAでビットストリームを書き込んでから、ソフトウェアをRunします。 すると、4つのLEDが1秒間隔でチカチカするはずです。

Xilinx SDK Driver APIでAXI GPIOを制御する

前回と同様に、ドライバAPI(関数)でAXI GPIOを制御してみます。今回のプロジェクトではAXI GPIOを使っています(前回はGPIO PSでした)。そのため、SDKでBSPプロジェクトを作った時に、gpioというライブラリも用意されています(前回はgpiops)。

コード

使い方はほとんどgpiopsと同じですが、微妙に異なります。とはいえ所詮GPIOなので、雰囲気で実装できると思います。LEDはAXI GPIOのChannel 1に接続しているので、XGpio_SetDataDirectionとXGpio_DiscreteWriteの第2引数(Channel)には1を設定しています。

helloworld.c
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "sleep.h"
#include "xgpio.h"

int main()
{
    init_platform();

    print("Hello World\n\r");

    XGpio instXGpio;
    XGpio_Initialize(&instXGpio, XPAR_AXI_GPIO_0_DEVICE_ID);
    /* Set all of 4 pins(LEDs) as output */
    XGpio_SetDataDirection(&instXGpio, 1, 0);

    while(1) {
        /* Set all of 4 pins(LEDs) as High */
        XGpio_DiscreteWrite(&instXGpio, 1, 0x0F);
        sleep(1);
        /* Set all of 4 pins(LEDs) as Low */
        XGpio_DiscreteWrite(&instXGpio, 1, 0x00);
        sleep(1);
    }

    cleanup_platform();
    return 0;
}

参考資料

18
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
10