« ZYNQのPS/PL通信をやってみた(3) SDKを使う | トップページ | RXduinoをEclipseで使うには »

2013.07.08

ZYNQのPS/PL通信をやってみた(4) GPIOテストコードを書く

ZYNQのPS/PL通信をやってみた(3) SDKを使う」の続きです。

さて、SDKが動いてHello Worldが出たら、アプリケーションを自分用に書き換えてあげましょう。

プロジェクトtestappの中にあるhellow.cはこんな感じ。

#include <stdio.h>
#include "platform.h"

void print(char *str);
int main()
{
    init_platform();
    print("Hello World\n\r");
    return 0;
}

さて次のように修正します。

  • printという関数のプロトタイプを消去(次にincludeするものとぶつかるため)し、print→printfに変更
  • includeに、xparameters.hと、xgpio.hを追加

最初のステップでXPSで生成したAXI_GPIOを操作したいけどアドレスがどこにあるか・・・とかそういうことを調べる必要はありません。それらはxparameters.hをインクルードすることで解決されます。このファイルをインクルードしたらXPAR_まで打てばあとは自動補完されてなんとかなります。

GPIOから値を出力するには、

XGpio xgpout;
XGpio_Config xcfg_out;
xcfg_out.DeviceId = XPAR_AXI_GPOUT_DEVICE_ID;
XGpio_CfgInitialize(&xgpout, &xcfg_out, XPAR_AXI_GPOUT_BASEADDR);
XGpio_SetDataDirection(&xgpout, 1, 0);
XGpio_DiscreteWrite(&xgpout,1,i);

とします。 xgpoutという変数はハンドルみたいなものです。xcfg_outはDeviceIdを設定するためだけに使われるようで、しかもこの値は結局参照されていないようなのですが、上のリストのようにXPAR_AXI_GPOUT_DEVICE_IDでマクロ定義された値を設定します。

そして、XGpio_CfgInitializeでGPIOの特定のポートを初期化します。ここで与えるアドレスはGPIOの実効アドレスなのですが、これもXPAR_AXI_GPOUT_BASEADDRというマクロで定義されています。(実際の値は0x41200000)

XGpio_SetDataDirectionはGPIOの方向を指定する関数ですが、第一引数は先のハンドルを指定します。第二引数はチャネル番号で、通常は1です。最後の0は全ポート出力を意味します。(各ビットが1だと入力になる)

実際に値を出力するのは、XGpio_DiscreteWriteという関数です。第一引数は先のハンドルを指定します。第二引数はチャネル番号でこれも1です。第三引数に出力したい値を指定します。

たかがGPIOからの出力のためにわざわざハンドルを作らなければならないのが面倒ですが、このようにしてソフトウェアからFPGA部分に任意の値を送り込むことができます。

ソフトウェアでGPIOからの入力を行うには次のようにします。

XGpio xgpin;
XGpio_Config xcfg_in;
xcfg_in.DeviceId = XPAR_AXI_GPIN_DEVICE_ID;
XGpio_CfgInitialize(&xgpin, &xcfg_in, XPAR_AXI_GPIN_BASEADDR);
XGpio_SetDataDirection(&xgpin, 1, 1);
printf("%4d ", XGpio_DiscreteRead(&xgpin,1));

出力とだいたい同じ流れです。XGpio_CfgInitializeでハンドルを作成して、XGpio_SetDataDirectionでチャネル番号(1)と方向(1:入力)をセットして、XGpio_DiscreteReadで読み出しを行っています。

このようにして、FPGAの中の回路とソフトウェアが通信できるようになりました。最後にまとめとして、FPGA内に作ったセレクタをGPOUTして切り替えて、8ch ADCの内容をGPINして読みだすというプログラムのコードを示します。

#include <stdio.h>
#include "xparameters.h"
#include "platform.h"
#include "xgpio.h"
#include "xgpiops.h"

int main()
{
    init_platform();

    printf("Hello World\n\r");
    printf("This is nahitafu\n\r");

    XGpio xgpin,xgpout;
    XGpio_Config xcfg_in,xcfg_out;
    xcfg_in.DeviceId = XPAR_AXI_GPIN_DEVICE_ID;
    xcfg_out.DeviceId = XPAR_AXI_GPOUT_DEVICE_ID;

    XGpio_CfgInitialize(&xgpin, &xcfg_in, XPAR_AXI_GPIN_BASEADDR);
    XGpio_SetDataDirection(&xgpin, 1, 1);

    XGpio_CfgInitialize(&xgpout, &xcfg_out, XPAR_AXI_GPOUT_BASEADDR);
    XGpio_SetDataDirection(&xgpout, 1, 0);

    while(1)
    {
        int i;
        for(i=0;i<8;i++)
        {
            XGpio_DiscreteWrite(&xgpout,1,i);
            printf("%4d ", XGpio_DiscreteRead(&xgpin,1));
        }
        printf("\r\n");
        usleep(1000);
    }

    return 0;
}

これは以前作ったZED Board用のADC拡張ボード

Zynq_pspl_33

のデータ読み出しプログラムです。なんとなく動いているような気がします。

Zynq_pspl_32

この一連のやり方がわかるまで、XILINXのチュートリアルや、過去のセミナー資料などを読みながら試行錯誤しました。これらの記事がZYNQで何かをしようとしている皆様のお役に立てば幸いです。

ひととおりやってみて驚いたのは、「PLとPSは完全に独立しているので、どっちを先にコンフィグしてもよい」ということでした。つまり、高性能なCPUとFPGAが別々に存在しているような感じだということです。

また、SDKはよくできています。ほとんど何も(ソフトもハードも)書かなくてもこれだけのことができてしまったということで、XILINXの作りこみのすごさにただただ驚くばかりです。

|

« ZYNQのPS/PL通信をやってみた(3) SDKを使う | トップページ | RXduinoをEclipseで使うには »

コメント

失礼いたします。

今、zedboardを使う機会があって、このサイトを参考にさせてもらっています。

ひとつ質問があります。

このサイトを見る限り、なひたふさんはプロセッサ(PS)とLEDを光らせる専用回路(PL)をつなげていると私は解釈しています。

そこで、ソフトウェアのほうでそのLEDの値をとってきてそれをteraterm等に表示させるにはプログラムではどう書けばよいのでしょうか。
(なひたふさんの作った回路の場合、VHDLのgpinの値をソフトウェアのほうでとってきて表示させたいということです)

投稿: zed初心者 | 2015.11.03 18:18

もう少しいろいろ試行錯誤してみたらいかがでしょうか

投稿: なひたふ | 2015.11.03 20:18

おかげさまでLEDの値をとることができました。

新たな疑問が出てきたのですが、二つのデータをplにソフトウェアのほうから渡したいとき、ソフトウェアのほうではどう書けばよいのでしょうか。

XPSの設定も変える必要がありますかね??

投稿: zed初心者 | 2015.11.04 10:11

繰り返しになりますが、ここは無料のXILINXサポートではありません。

だいいち、どんな回路を作っているかもわかりませんし
匿名の方が作った記事とは関係ない回路のデバッグを手伝う理由もありません。

投稿: なひたふ | 2015.11.04 10:40

コメントを書く



(ウェブ上には掲載しません)




« ZYNQのPS/PL通信をやってみた(3) SDKを使う | トップページ | RXduinoをEclipseで使うには »