UIOを用いてLinuxからIPコアへアクセスする
LinuxからIPコアへアクセスする方法は3つある。そのうち上位2つの方法は簡単に使用できるので重宝されているらしい。
ただ、dev/mem
を用いる方法は、物理アドレスに直接アクセスできることから、予期せぬメモリ領域にデータを書き込んでしまい、カーネルやプロセスのメモリを破壊する恐れがある。実際に使ったことないのでわからないが。
そのため、上記の中ではUIOを使用する方法が良いらしいので、UIOの使い方の調査と実機を使った動作確認を行う。調査内容と実機確認内容を記載するとブログが長くなるので、理解編と実践編と2回に分ける。この記事は理解編である。
目次
UIOとは
UIO(User space I/O)は物理アドレスへアクセスするための仕組みで、Linux2.6.22から追加された機能らしい。UIOは割り込みハンドリングが可能であり、かつデバイスドライバ開発が不要であるという利点がある。その一方で、DMA転送には対応していないのが欠点らしい。
使用手順
UIOを用いてのIPコアアクセスは、以下の手順が必要となる。
UIOドライバを有効化する
コンフィグのデフォルト設定ではUIOドライバが有効であるので、ここは読み飛ばしてもよい。
- 以下のコマンドを実行し、カーネルコンフィグレーション画面を表示
make xilinx_zynq_deconfig #MPSocの場合は、下記コマンド #make xilinx_zynqmp_deconfig make menuconfig
- UserspcaeI/O platform driverwith IRQ handoling を有効化にする Device Drives > Userspace I/O drivers まで移動する。UserspaceI/O platform driver with generic IRQ handling にチェック、またはM<モジュール>が付いていればよい。
IPコアをUIOデバイスに設定する
今回は既存の.dtbファイルを.dtsファイルに逆変換し、UIOデバイスの設定を行う。そして、設定した.dtsファイルを.dtbファイルに変換し、デバイスツリーを再生成する 。
- .dtbファイルを.dtsファイルへ逆変換 以下のコマンドを実行し、.dtsファイルをdtsファイルに変換する。
$ dtc -I dtb -O dts -o system.dts system.dtb
- UIOデバイスの設定
下記のように、IPコアの
compatible
をgeneric-uio
に変更する。
Gpio@a0020000{ - compatible = "xlnx,GpioIP-1.1"; + generic-uio = "generic-uio"; reg = <0x 0xa0020000 0x0 0x1000>; };
$ dtc -I dts -O dtb -o system.dtb system.dts
Linuxから実行できるプログラム作成する
mmapはUNIX OSシステムコールの一つで、ファイルに連続した仮想アドレス空間にマッピングする関数である。LinuzからFPGAのアドレス空間にアクセスするには、mmap関数とUIOを使用して、FPGAのアドレス空間を仮想アドレス空間にマッピングするプログラムを作成する。
手順
1. open関数を用いてデバイスをオープンする
open関数の戻り値と引数は以下である。
int open (const char *pathname, int flags) /* * @param pathname :オープンするファイルを指定する文字列 * @param flags : O_RDONLY(0x),O_WRONLY(0x), O_RDWR(0x) のいづれかが入る。 * @return * - 正常:正の整数を返す * - 異常:-1を返す /*/
void *mmap (void *addr, size_t len,int prot, int flags, int fileds, off_t off); /* * @param *addr : マッピングするアドレスを指定する。NULLを指定した場合、 * カーネルがマッピングするアドレスを決める。 * @param size_t len :マッピングするデータサイズを指定する。 * @param int prot : マップ領域のアクセス権限を設定する。 * @param int flags : マップ領域の扱いを設定する。MAP_PRIVATE とMAP_SHAREDの2つのフラグがある。 * MAP_SHAREDがよく使用される。 * @param int fileds : opne関数でオープンしたファイルを指定する。 * @param off_t off : ファイルのどこからマッピングしたいのか、オフセットを指定 * @return * - 正常:マップ領域のポインタを返す * - 異常:MAP_FAILEDを返す /*/
- close関数により、オープンしたファイルディスクリプタを閉じる。
close(fd); /* * @return * - 正常:0を返す * - 異常:-1を返す */
- munmap関数により、mmapでマップしたメモリを解放する。 munmap関数の引数と戻り値は以下である。
munmap(void *addr, size_t len); /* * @return * - 正常:0を返す * - 異常:-1を返す */
以上が理解編である。次回は、実践編でUIOを用いてLinuxからIPコアへアクセスできるか動作確認する。