KiNOKO-DAQ 関連情報 掲示板

このスレッドに記事を投稿する
前のスレッド | 次のスレッド | 掲示版ホーム

vmedrvでのDMA転送
2016 年 4 月 26 日 22 時 19 分
投稿者: 増田

榎本様、

はじめまして。岡山大学の増田と申します。
現在、vmedrvを使わせていただいてCAENのTDC V1290A を読み出しているのですが、DMAでの読み出しができず、ご相談させていただきます。

サンプルプログラムでの挙動ですが、/dev/vmedrv32d32(dma)を用いて、V1290Aのstatus register を読み出す場合、
$ ./vmeread 0x1002 0x4
30 38 00 00
read size: 0x4
$ ./vmeread 0x1002 0xF
ERROR: read(): Invalid argument
$ ./vmedmaread 0x1002 0x4
ERROR: read(): Input/output error
$ ./vmedmaread 0x1002 0xF
ERROR: read(): Invalid argument
となります。(PIO転送でargv[2]を0xFにするとエラーが出る理由もよくわかっておりません。)
また、DMA転送モードでwrite()を使うとその時点でフリーズし、PC自体の再起動が必要となります。

PIO転送やメモリマップではあまり速度が出なかった(~1.6MB/s程度)ので、DMAならもっと速いのではないかと期待していたのですが、転送自体がうまくいかないため評価できない状況です。
通常のPIOやメモリマップでの転送はできているのですが、DMA転送の場合、なにか別途設定が必要なのでしょうか?
対処法をご教示いただけると助かります。よろしくお願いいたします。

環境は以下の通りです。
vmedrv version 1.2.1
SBS Bit3 Model 618
Sientific Linux 6.7
カーネルバージョン:2.6.32-573.22.1.el6.x86_64

dmesg での出力:
vmedrv: SBS(Bit3) Model 618/620 VME-PCI Bus Adapter is detected at ioport 0xa000 on irq 11.
I/O Mapped Node at 0xa000.
Memory Mapped Node at 0xf8010000.
Mapping Register at 0xf8000000.
Remote Memory at 0xf6000000.
vmedrv 0000:0c:00.0: enabling device (0000 -> 0003)
vmedrv 0000:0c:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16
vmedrv: successfully installed at 0xa000 on ira 16 (major = 246).



2016 年 4 月 27 日 15 時 38 分
投稿者:

/dev/vmedrv32d32(dma) は、アドレス幅32ビット、データ幅32ビットでアクセスします。このとき、データ転送ブロックの開始アドレスも終了アドレスも、ともに4バイト(32ビット)の倍数でなければなりません。これはDMAに限ったことではなく、すべてのVME転送モードに共通することです。(そして、おそらくVME以外のほとんどのバスでもそうだと思います。)

開始アドレスの 0x1002 も、サイズの 0xF も、4の倍数ではないので、エラーはそのために出ているのだと思います。

DMAのトラブルは別の原因かもしれませんが、とりあえず開始アドレスとサイズを4の倍数にして試してみてもらえないでしょうか?

なお、16進数で4の倍数は、最下位の数字が0、4、8、Cのいずれかになるものです。



2016 年 4 月 28 日 11 時 28 分
投稿者: 増田

榎本さま(ですよね?)

お世話になります。

アドレス、サイズとも4の倍数にして試した結果を添付いたします。
アドレス0x1000はControl register, 0x0はOutput bufferです。
PIO転送でも0x1000の読み出しはうまくいきません。0x0ですとサイズ0x1000までは読み出せるようで、それ以上のサイズを指定するとConnection timed outのエラーになります。
DMA転送ですと全てInput/output errorとなってしまいます。

$ ./vmeread 0x1000 0x4
ERROR: read(): Connection timed out
$ ./vmeread 0x1000 0x8
ERROR: read(): Connection timed out
$ ./vmeread 0x0 0x4
0000 0000: 00 00 00 c0
read size: 0x4
$ ./vmeread 0x0 0x8
0000 0000: 00 00 00 c0 00 00 00 c0
read size: 0x8
$ ./vmedmaread 0x1000 0x4
ERROR: read(): Input/output error
$ ./vmedmaread 0x1000 0x8
ERROR: read(): Input/output error
$ ./vmedmaread 0x0 0x4
ERROR: read(): Input/output error
$ ./vmedmaread 0x0 0x8
ERROR: read(): Input/output error



2016 年 4 月 30 日 10 時 39 分
投稿者: 榎本三四郎

すいません,名前を書き忘れていました.

VME ドライバに渡すアドレスは,VME バス上での絶対アドレスです.これは,モジュールのベースアドレスにモジュール内でのオフセットアドレスを足したものです.例えば.モージュールのベースアドレスを 0x00240000 にセットしていたあとして,モジュール上の 0x1000 のレジスタを読みたければ,
$ vmeread 0x00241000 0x04
とすることになります.

それから,V1290 のマニュアルによれば,0x1000 以降のレジスタ群にアクセスするには D16 モード (/dev/drv/vmedrv32d16)を使わなければならず,0x0000 から 0x0ffc までの範囲にあるデータバッファには D32 モード (/dev/drv/vmedrv(dma)32d32) を使わなければいけないようです.このへんの設定が合っていないと,モジュールが応答しないので,Timeout だったり Input/Output Error だったりが出たりします.

念のため,マニュアルの該当ページを添付しておきます.


添付ファイル: v1290_rev11_p68.pdf (106 kb)



2016 年 5 月 2 日 11 時 39 分
投稿者: 増田

榎本様

マニュアルのD16というのは、単にレジスタの16bitを使用しているという意味かと勘違いしておりました。読み出しサイズも表しているんですね。

ご指摘いただいたように /dev/drv/vmedrv32d16 を使うと、0x1000のレジスタの読み出しもできるようになりました。
ベースアドレスは 0x0 と設定しております。読み出したレジスタの値からも、アドレスの指定自体は正しいと思われます。
一方、/dev/drv/vmedrv32d16dma を使うと、まだInput/output errorが出て読み出せないようです。PIO転送とDMA転送を切り替えるための設定なども必要なのでしょうか?


$ ./vmeread 0x1000 0x4
0000 1000: 20 00 30 38
read size: 0x4
$ ./vmeread 0x1000 0x8
0000 1000: 20 00 30 38 00 00 00 00
read size: 0x8
$ ./vmeread 0x101C 0x4 (マニュアルによるとD32のレジスタ)
ERROR: read(): Connection timed out
$ ./vmedmaread 0x1000 0x4
ERROR: read(): Input/output error
$ ./vmedmaread 0x1000 0x8
ERROR: read(): Input/output error
$ ./vmedmaread 0x101C 0x4
ERROR: read(): Input/output error



2016 年 5 月 5 日 8 時 38 分
投稿者: 榎本三四郎

DMA 読み出しには,VME のブロック転送モード(BLT Access)を使用します.
V1290 モジュールのマニュアルの,前回添付したのと同じページには,BLT 転送ができるのは
オフセットアドレス 0x0000 から 0x0ffc の範囲だけと書いてあります.
DMA 転送でエラーが出るのはこれが原因ではないでしょうか?



2016 年 5 月 6 日 20 時 12 分
投稿者: 増田

アドレスオフセット0x0000に /dev/vmedrv32d32(dma) を用いてアクセスしてみた結果ですが、

PIO転送ですとサイズ0x1000まで読み出せて、それを越えると Connection timed outのエラーが返ってきます。
DMA転送ですと、lseek64()まで進んでread()でフリーズし、電源長押しで再起動が必要になるという結果でした。
(4/28の報告ではDMA転送の場合 input/output error が返ってきていたのですが、これは /dev/vmedrv32d16dma を間違って使っていたようです。申し訳ありません。)

V1290Aを正しく設定していないなど、モジュール固有の問題なのでしたら、こちらの掲示板で聞くのはあまりふさわしくないかと思いますが、問題ないでしょうか?


以下、PIO転送での結果を添付いたします。DMA転送はフリーズするので、添付できる結果はありません。
$ ./vmeread 0x0 0x1000
0000 0000: 67 4d 13 00 61 8d 19 00 68 cd 1f 00 62 0d 06 00 gM..a...h...b...
0000 0010: 62 4d 0c 00 61 8d 12 00 5f cd 18 00 4a 0d 1f 00 bM..a..._...J...
...
0000 0fe0: f0 4a 01 00 f9 8a 07 00 e5 ca 0d 00 fa 0a 14 00 .J..............
0000 0ff0: f3 4a 1a 00 f4 8a 00 00 f2 ca 06 00 d7 0a 0d 00 .J..............
read size: 0x1000
$ ./vmeread 0x0 0x1004
ERROR: read(): Connection timed out
$ ./vmeread 0x0 0x1008
ERROR: read(): Connection timed out



2016 年 5 月 9 日 17 時 12 分
投稿者: 榎本三四郎

問題の所在がモジュールなのかドライバなのかを切り分けるのは簡単ではないので、そのへんはあまり気にしないで質問してもらっていいです。ただ、もしモジュールの方である可能性を考えるなら、可能であればもっと単純なメモリボードのようなもので比較テストをしてみると、解決へのヒントになることが多いです。

サイズが 0x1000 を超えるとエラーになる件については、0x0000 からスタートして 0x1000 以上読むと、読み出しアドレスが 0x1000 のレジスタになってしまって、これは D16 アクセスしか受け付けないアドレスなので、それでエラーになっているのだと思います。DMA の方は別の問題かもしれませんが、とりあえず読み出しサイズを 0x1000 以下、できれば 0x100 くらいでテストしてみるのがいいと思います。



2016 年 5 月 11 日 9 時 5 分
投稿者: 増田

アドレスオフセット0x0000に /dev/vmedrv32d32(dma) を用いてアクセスしてみた結果ですが、

PIO転送ですとサイズ0x1000まで読み出せて、それを越えると Connection timed outのエラーが返ってきます。
DMA転送ですと、lseek64()まで進んでread()でフリーズし、電源長押しで再起動が必要になるという結果でした。
(4/28の報告ではDMA転送の場合 input/output error が返ってきていたのですが、これは /dev/vmedrv32d16dma を間違って使っていたようです。申し訳ありません。)

V1290Aを正しく設定していないなど、モジュール固有の問題なのでしたら、こちらの掲示板で聞くのはあまりふさわしくないかと思いますが、問題ないでしょうか?


以下、PIO転送での結果を添付いたします。DMA転送はフリーズするので、添付できる結果はありません。
$ ./vmeread 0x0 0x1000
0000 0000: 67 4d 13 00 61 8d 19 00 68 cd 1f 00 62 0d 06 00 gM..a...h...b...
0000 0010: 62 4d 0c 00 61 8d 12 00 5f cd 18 00 4a 0d 1f 00 bM..a..._...J...
...
0000 0fe0: f0 4a 01 00 f9 8a 07 00 e5 ca 0d 00 fa 0a 14 00 .J..............
0000 0ff0: f3 4a 1a 00 f4 8a 00 00 f2 ca 06 00 d7 0a 0d 00 .J..............
read size: 0x1000
$ ./vmeread 0x0 0x1004
ERROR: read(): Connection timed out
$ ./vmeread 0x0 0x1008
ERROR: read(): Connection timed out



2016 年 5 月 11 日 10 時 0 分
投稿者: 増田

(ブラウザリロードの際に同じ文章が再投稿されてしまいました。)

お手数お掛けしてすみません。現在手元にV1290AしかVMEモジュールがないため、これでテストするしかない状況です。

転送サイズを減らしてみても結果は一緒でした。試してみた転送サイズは
0x4, 0x8, 0x10, 0x100, 0x200, 0x400, 0x800, 0x1000
です。また /dev/vmedrv32d32nbdma でもやってみたのですが、
結果は一緒で、lseek64()まで実行され、read()でフリーズするというものです。
vmedmareadを実行するとモジュールのLED indicator "DTACK"は点灯しますので、モジュールへのアクセス自体は行われていると思います。
(マニュアルには "it lights up green whenever a VME read/write access to the board is performed." とあります。)

関係あるかわからないのですが、PC再起動後にvmedmareadを走らせると、何も表示せずに終了する場合があります。main()開始直後に printf()を入れても何も表示されないので、プログラム自体が正常に始まっていないようです。その場合、
$ touch vmedmaread.c; make
としてもう一度走らせると、フリーズするようになります。具体的に書くと以下のような状況です。何かお心当たりがあれば幸いです。

- PC起動
- VME Crate 起動

$ cd ~/work/vmedrv/Linux2.6_Bit3_617/
$ sudo make install
[sudo] password for ???:
/sbin/insmod vmedrv.ko vmedrv_major=0 vmedrv_name=vmedrv target_card_number=0
vmedrv, MAJOR=246
making nodes on /dev...
done
$ cd ../
$ ./vmedmaread 0x0 0x100
$ ./vmedmaread 0x0 0x10
$ make
make: Nothing to be done for `all'.
$ touch vmedmaread.c
$ make
gcc -g -Wall -I/usr/include -c vmedmaread.c
gcc -g -Wall -I/usr/include -o vmedmaread vmedmaread.o
$ make
make: Nothing to be done for `all'.
$ ./vmedmaread 0x0 0x100

- ここでPCフリーズ



2016 年 5 月 17 日 23 時 33 分
投稿者: 榎本三四郎

返信が遅くなってしまい申し訳ありません。

DMA でフリーズするのは、データが記録されていない状態でバッファから読み出しを行うと、モジュールの設定次第ではデータ転送前にモジュールから BERR が発行されるのが理由かもしれません。ただ、もしそのような設定になっていないのであれば、ドライバの方の問題の可能性もあります。実際に、最近の一部の PC と一部のディストリビューションの組み合わせで DMA がフリーズすることが報告されています。現在その問題を再現して原因を調べようとしているところですが、手持ちの機器で問題を再現できないこともあり、その場合であれば、申し訳ありませんが、すぐに解決することはできない状況です。もし可能であれば、別のPCや別のディストリビューションを試してみれば、もしかしたら解決するかもしれません。



2016 年 5 月 20 日 17 時 50 分
投稿者: 増田

ご指摘いただいた通り、別のPCにインストールしたUbuntuを試してみたところ、無事DMA転送ができるようになりました。転送速度も21.6MB/s出ております。
VMEの設定についても色々ご助言いただき、大変参考になり、助かりました。ありがとうございます。
お役に立つか分かりませんが、変更前後の簡単なPC環境を記入しておきます。

変更前:
Mother board GIGABYTE GA-X79-UD3 Rev.1.0
CPU intel Core i7
OS Scientific Linux 6.7
カーネルバージョン:2.6.32-573.22.1.el6.x86_64

変更後:
Mother board Intel G45M03
CPU Core2Duo CPU E7400 @ 2.8GHzx2
OS Ubuntu 14.04 LTS
カーネルバージョン 3.13.0-85-generic



2016 年 5 月 25 日 21 時 40 分
投稿者: 榎本三四郎

問題を解決できてよかったです。また、動作環境の報告、ありがとうございます。不用意なことは言えませんが、不具合が発生する組み合わせが見えてきたような感じがします。今後の開発に参考にさせてもらいます。


このスレッドに記事を投稿する