KiNOKO-DAQ 関連情報 掲示板

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

VME同時にマルチ割り込み発生
2004 年 4 月 23 日 15 時 28 分
投稿者: 呉仕強

はじめまして宜しく、台湾の呉です。
今使ってるすべてのADCは各別割り込みを請求できる(同じlevelで違うvector)。違うADCからのIRQ請求の時間が違ったら別に問題はありませんが、問題はもし同時に複数のADCがイベントをキャッチしIRQを請求したら最初にCPUに送り込まれるIRQしか反応されません(BUS ANALYZERから見たら、確かに請求の数は稼動されたADCの数と同じ)。これを解決するために、vmedrv.cにある”acknowledge_vme_interrupt()”に手を加えました。IACK処理にループを加え、モジュールの数と同じ回数のIRQ処理で、すべてのvectorを確認しトリガーされるADCを記録してから、IRQ_HANDLERを稼動してデータを収集そるようになりました。今までのテストは順調ですがスピードご落ちてしまいました。これについてコメントを頂きたいと思っています。



2004 年 4 月 27 日 21 時 58 分
投稿者: 榎本 三四郎


遅くなって申し訳ありません.
ご指摘のとおり、現在の vmedrv の多重割り込みのサポートは不完全です.
ただし,「同じ IRQ で異なる Vector の割り込みが同時に起こると最初の割り込みしか
処理されない」という表現はあまり正確ではないので,すこし補足したいと思います.

同時割り込みのテストをするため,2つのインタラプタモジュールを使い,それらにに
同じ IRQ (IRQ=3) と異なる Vector (0xff20 と 0xff30) を割り当て,
ほぼ同時(100ns以下の差)に割り込みを発生させるようにして,2つの vmeintwait を
走らせて,それぞれの割り込みを取得するようにしました.
(vmeintwait は,IRQ と Vector を実行時に指定できるように改変しました).
すなわち,片方の vmeintwait で IRQ=3, Vector=0xff20 を,もう片方で
IRQ=3, Vector=0xff30 の割り込みを取得するようにして,それらを同時に実行しました.

その結果,それぞれの vmeintwait は,完全に正常に動作しました.
そのときのロジックアナライザの表示の写真を添付しておきます.
少し見にくいですが,1つの IRQ に対して,2回の Acknowledge サイクルが実行
されていることを見ることができます.

このテストにより,同時発生の割り込みにドライバが対応していないということは
ないと言えると思います.ただ,問題なのは,1つのプロセスで(同時とはかぎらない)
複数の割り込みを取得しようとした場合に,ドライバからプロセスに割り込み元を分別
して伝達する洗練された方法が提供されていないことです.

vmeintwait.c のように,ioctl(..., VMEDRV_IOC_WAIT_FOR_INTERRUPT, ...) を
使うと,対象の割り込みが発生するまで実行をブロックしてしまうので,割り込みを
それが起きた順に処理したいというような用途には不便です.タイムアウトを設定して
ループを回せば擬似的にそのような処理が可能ですが,リアルタイム性が失われてしまい
ます.スレッドを使えばブロックの問題は回避できますが,スレッドに頼りたくない
情况も多いかと思います.

vmeint.c のように,シグナルを用いれば,それぞれのモジュールに別々の SignalID を
割り当てることにより,複数の割り込みを分離して扱うことができます.ただし,利用できる
シグナルの数は通常それほど多くはないので,例えばクレート内の全てのモジュールが
割り込みを発生するような情况では破綻してしまいます.

私に思いつく範囲で,いちばんまともな解決方法は,select() システムコールへの
インターフェースを提供することだと思います.いまはちょっと多忙のためすぐに
というわけにはいかないのですが,近いうちに実装し,新しいバージョンとしてリリース
したいと思います.

呉さんの記事では,全ての割り込み要求を処理してからハンドラを呼び出すと
なっていますが,具体的にはどのようにして複数の割り込み要求の情報をプロセスに
渡しているのでしょうか? もしその方法が select() よりも優れているようならば,
そちらを実装したいと思います.


添付ファイル: dscf0252.jpg (400 kb)



2004 年 4 月 28 日 14 時 18 分
投稿者: 呉仕強(台湾中央研究院)

台湾の呉です
返事有難う御座いました。これから榎本さんの言う通に試しようと思っています。添附のプログラムはvmedrv/Linux2.4_Bit3_617/vmedrv.cを書き変えたものです。内容はほぼ同じですが、vmedrv_ioctl()とacknowledge_vme_interrupt()にちょっと手を加えました。変更されたコードの後には説明を付けました。従ってvmedrv/Linux2.4_Bit3_617/vmedrv.hにも「#define VMEDRV_IOC_IRQ_MAP _IO(VMEDRV_IOC_MAGIC,11)」のコードを追加しました。これで、元のinterrupt_client->vectorの用途が変ってIRQを請求出来るモジュールの數となります。つまり最初のシステム設定ではIRQを請求出来るモジュールの數に合わせてIRQを処理するループの回数も同じように設置するのです。もし榎本さんはもっと簡単で速く処理する方法を考えたらぜひ頂きたいと思います。宜しくお願いします。

添付ファイル: vmedrv.c (47.1 kb)



2004 年 4 月 29 日 18 時 51 分
投稿者: 榎本三四郎


今回のような情况では,呉さんのコードでいいのですが,多重割り込みに対する
一般的な実装としてはいくつか問題があるように思います.例えば,2つの割り込み
が近接して発生したような情况では,1つめの割り込みでドライバが v を設定して
プロセスに通知しても,プロセスがそれに応答して ioctl() で v を読む前に
次の割り込みがドライバに取得されてしまうと,それにより v の値が更新されてしまい,
1つめの割り込みの情報が失われてしまいます.v を単純な変数ではなく,キュー
みたいなものにすればとりあえずこの問題は回避できますが...

もう一つの問題は,この実装だと複数のプロセスが割り込み処理を行なうような場合に
対応できないということです.正しくは,プロセスごと(vmedrv の open() ごと)に
v のキューを持たせるようにすることだと思うのですが,私の印象としては,これは
結局のところ select() や poll() に対するインターフェースを実装することになる
のではないかと思います.

スピードに関しては,複数の割り込みを処理するためには,おそらくこの方法が
最速だと思います.通常は割り込みの発生ごとにプロセスに通知し,プロセスが
1つづつそれを処理するため,割り込みごとにコンテキストスイッチが発生して
しまいます.呉さんのようにドライバの中でループを回せば,このオーバヘッドが
さけられます.

もし情况が許すなら,モジュールの構成を変えて割り込み元を1つにまとめるのがいちばん
簡単で高速だと思います.すなわち,インタラプトレジスタなどを用いて,どの ADC に
データがあるのかという情報と割り込みを同時に送れば,多重割り込み処理に伴う
オーバーヘッドとタイミングの問題による不安定さを避けられるのではないかと思います.
このへんは実験装置の詳細によるので一概には言えませんが...



2004 年 5 月 6 日 13 時 7 分
投稿者: 呉仕強(中央研究院)

台湾の呉です。
トラベルが発生しました。昨日D32の読み出しのコードをDMA伝送で入れ替えてみましたが読み出したデータは間違いました。それにもう一つの問題が起こった。DMAのプログラムを終了した後、元の正しいプログラム(伝送方は一般のI/O)を稼動した後、コーアから読み出す”ADCヴェクターマップ”の数値も間違いました。それでREBOOTしたら、XWINDOWでさえ作動できなくなりました。「TEXTモード」で元の正しいDAQコードをリメックし動かしたが結果が同じ、VECTOR MAPの部分で間違いました。ですからDMAの影響範囲(KERNELとか)について聞きたいと思います、よろしくお願いします。



2004 年 5 月 6 日 18 時 34 分
投稿者: 榎本三四郎


vmedrv の DMA は,インターフェースカード上のレジスタを設定して
kmalloc(GFP_KERNEL) で確保したカーネルメモリにデータをDMA転送し,
それを copy_to_user() でユーザ領域に再びコピーしているだけです.
DMA バッファの確保は prepare_dma() で,レジスタの設定は initiate_dma() で,
DMA の実行は start_dma() で,ユーザ領域へのコピーは dma_read() で
それぞれ行なっています.Makefile の CPPFLAGS に -DTRACE_DMA を追加して
コンパイルしなおせば,これらの処理をトレースできます.

ハードウェアの仕様により,DMA 転送中はいかなる VME アクセスも禁止
されていることに注意してください.マニュアルには,これをした場合の動作は
予測できないと書かれています.vmedrv の DMA はすでに多くの場所で使われており,
DMA 単体では比較的安定しているように見えます.VME アクセスのロジックが複雑に
なって,DMA 転送中に他のプロセスが VME アクセスをした場合には仕様どおり
問題を引き起こしているようですが...それから,DMA とシグナルの組み合わせには,
デバッグが不完全な部分があるかもしれません.時間があれば調べてみます.

DMA 処理は,タイミングとレジスタ周りが複雑とは言え,カーネルインターフェース部分は
それほど複雑ではないので,vmedrv がシステムを破壊するということは考えにくいです
(ファイルシステムは特に).リブートの際に VME の電源を入れ直さないと,もしかしたら
VME のデバイスが起動時になにか影響を与えるかもしれません.


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