GPIOの使い方
ZybqBerryのGPIOピン
ZynqBerryには、Rasberry Piと同様、図にあるように40ピンのGPIOが搭載されており、FPGA(PL部)とARMコア(PS部)の両方からアクセスできるようになっています。
また40本あるGPIOのピン配置は次のようになっています。Zynqberryの初期デザインでは、GPIO14とGPIO15ピンは使えない設定になっています。
Xilinxによると、PSからGPIOなどの外部ピンへはMIO(Multiplexed I/O)とEMIO(Extend MIO)を経由してアクセスすることができます。EMIOではMIOの外部ピンに加えて、PLを経由しPLのI/Oピンにアクセスすることができます。今回はEMIOを経由しPLにつながったGPIOをPS部分から制御しする方法を紹介します。
GPIOをつかってLチカ
GPIOのピンにLEDをつなぎ、Lチカをしてみましょう。GPIO 2ピンにLEDの+端子をGNDへ-端子を接続します。
GPIOをPSから制御するための仮想ファイルが/sys/class/gpioに用意されています。基本的にはRasberry PiでGPIOを制御する方法と同様に行うことができます。しかし Zynqで使えるGPIOは全部で118ピン分あり、それぞれ/sys/class/gpio/gpio906~/sys/class/gpio/gpio1023までに割り振られています。その中でも906~959まではMIOを経由したGPIO、960~1023はEMIOを経由したGPIOに割り振られているようです。今回はEMIO経由でGPIOの2番ピンへアクセスします。
GPIOのピン番号と制御用仮想ファイルの番号の対応は、
- ピン番号が 2~13の場合:"ピン番号+958"番の仮想ファイル
- ピン番号が16~26の場合:"ピン番号+956"番の仮想ファイル
となります(繰り返しになりますが、GPIO 14と15のピンへのアクセスはZynqberryの初期デザインではできません)。
端末からの制御
/sys/class/gpioディレクトリの中身を確認してみます。
root@zynqberry ~$ ls /sys/class/gpio
export gpiochip906 unexport
このexportへ使いたいGPIOの番号を書き出すと、そのGPIOを使うための仮想ファイルが用意されます。今回はGPIO2へのアクセスなので960番を書き出します。
root@zynqberry ~$ echo 960 > /sys/class/gpio/export
root@zynqberry ~$ ls /sys/class/gpio/
export gpio960 gpiochip906 unexport
新しくできた/sys/class/gpio/gpio960の中身は
root@zynqberry ~$ ls /sys/class/gpio/gpio960
active_low device direction edge power subsystem uevent value
となっています。directionはGPIOの入出力の制御、valueはGPIOの値(1ならHigh、0ならLow)の制御に使います。まずGPIO 2を出力用にするため
root@zynqberry ~$ echo "out" > /sys/class/gpio/gpio960/direction
root@zynqberry ~$ cat /sys/class/gpio/gpio906/direction
out
となればOKです。この状態でvalueに1や0を書き出すと、GPIOに接続したLEDを点滅させることができます。
root@zynqberry ~$ echo 1 > /sys/class/gpio/gpio960/value
root@zynqberry ~$ echo 0 > /sys/class/gpio/gpio906/value
プログラムからの制御
C言語からGPIOを制御する方法を紹介します。この方法は2種類あり、1つは/sys/class/gpioの仮想ファイルをC言語からアクセスする方法、もう1つは/dev/memからGPIOの物理アドレスへアクセスする方法です。
/sys/class/gpioを使う方法
Linuxのシステムコールを使い、/sys/class/gpioにある仮想ファイルを操作します。以下にC言語のソースコードを示します。
/dev/memを使う方法
/dev/memを使い、GPIOの物理アドレスに直接データを書き込む方法を紹介します。GPIOマップされているアドレスは
root@zynqberry ~$ cat /proc/iomem | grep gpio
e000a000-e000afff : /amba/gpio@e000a000
で確認できます。XilinxのドキュメントによるとGPIOは0XE000A000にマップされていますが、上で得た結果と同じです。このアドレスをベースとしてGPIO制御に必要なレジスタがいくつか用意されています。詳しくは参考文献2をご覧ください。このうち今回必要なものは以下の通りです。
レジスタ名 |
機能 |
オフセット値 |
DIRM_2 | GPIO入出力。0が入力、1が出力 | 0x00000284 |
OEN_2 | 出力イネーブル。 | 0x00000288 |
DATA_2 | GPIOピンへの出力値。 | 0x00000048 |
これらのレジスタは32ビットとなっており、各ビットごとにGPIOピンが割り当てられています。今回のようにGPIO 2ピンを操作する場合、上記レジスタの(下から)1ビット目を操作します。この他にもDIRM_0やOEN_3といったレジスタが用意されています。*_0と*_1のレジスタはGPIOをMIOから操作する際に、*_2と*_3のレジスタはEMIOからGPIOを操作する際に使います。次のソースコードはGPIO 2に接続したLEDを10回点滅させるプログラムです。注意点として、/dev/memからGPIOを制御する際は、/sys/class/gpioで制御したいGPIOをexportしておかなければなりません。つまり、下のコードを使ってLEDを点滅させるには、/sys/class/gpio/exportに960を書き込んでからプログラムの実行が必要になります。
#define DIRM_1 0x00000091
#define DIRM_2 0x000000A1
#define DIRM_3 0x000000B1
参考文献
https://japan.xilinx.com/video/soc/mio-emio-configuration-zynq-7000.html
https://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf