割り込みルーチンの記述

割り込み処理ルーチンは "dc_int.c" という名前のファイルに記述してください。 デバイスドライバの make の際に自動的にインクルードされます。 実際には、実験のセットアップ毎に適当なファイル名 (例えば hogehoge.c) を付け、

      % ln -s hogehoge.c dc_int.c
によってシンボリックリンクを張るのが便利でしょう。 配付パッケージでは dc_test.c というファイルに リンクが張られています。

メインの割り込みハンドラは dc_int() という関数で、 概ね以下の事柄を記述します。

  1. デバイス識別子のチェック (IRQ を共有している場合)
  2. LAM のチェック (CC/7000 の場合のみ)
  3. バッファ残量のチェック
  4. CAMAC からバッファへのデータの読み込み
  5. モジュールのクリア
  6. 必要ならば処理終了を合図するパルスの出力
LAM で割り込みをかけているのだから LAM のチェックは不要…、 という考えは、CC/7700 に関しては正しいのですが、 CC/7000 の場合、割り込みが発生した直後はデータがアクセス出来ず、 LAM も読めない (0 が返る) という事が起こります。 昔の PC-9801 用 C bus インターフェースで使っていた頃は こんな経験をした記憶が無いので、 CC/7000-AT/IF のバグか、 CC/7000 側が ISA の 8 MHz の動作に追従できていないのではないかと 思われます。 "dc_test.c" の例題では ad hoc な解決として、 LAM をチェックして 0 が返って来たら 何もせずに割り込みルーチンを抜けるようにしています。 LAM がクリアされないので再び割り込みがかかり、 データが読めるようになるまで再帰的に待つ事になります (これが無限ループに陥る…、という経験は今までの所有りません)。
[追記] クロックの高いマシン (>500MHz?) では、 上記の判断のタイミングが微妙になるためか、 データのエラーが無視できない確率で起こるようです。 既に製造中止の機種ですので、 このエラーがクリティカルになる場合には、 CC/7700の使用を検討された方が良いでしょう。

例題として "dc_test.c" というファイルを用意しましたので、 あまり内部に立ち入りたくないという人は、 その中の

    #define TDC1      6
    #define OUTREG    4
    #define LAM_N     TDC1
    #define LAM_A     0
          .....

        /* Data AcQuisition for 1-event */
        /* User should modify from here */
        for (i=0;i<8;i++)             /* read 8 channels of TDC1 */
          camacCcycle2(TDC1,i,0,&dc_evbuff[(dc_wp++)%EV_MAX],&stat);
        /* ------------------ to   here */
          .....

      /* Also user should modify from here */
      camacCcycle2(TDC1,0,9,0,&stat);  /* clear module */
          .....
辺りを書き換えて使うのが簡単です。 camacCcycle2 等のインライン関数の類の説明は "dc_aux.h" の後半部分か、 こちらを参照してください。 この例では、 ステーションナンバー 6 にある TDC のサブアドレス 0〜7 のデータを 順次読み込んでバッファにストアしているだけです。 最後にモジュールをクリアしますが、 この例では F=9 を使って個別にクリアしています。 camacCc() によって バスにクリア信号を送出する方法は処理が短時間で済みますが、 スケーラを使ったり Output Register のレベル出力を使っている場合には、 これらも一緒にクリアされてしまうので不適当です。

例題では更に、 イベントデータを以下のレコード形式に整えて バッファに書き込んでおり、 後述のデータ収集システムのサンプル に適合させています。

          +--1--2--+------------------L-+---L+2-+
          | EVTLEN |      Contents      | DELIM |
          +--------+--------------------+-------+
EVTLEN はバイト単位のイベント長 (ここでは L+2)、 DELIM は区切り子 (0x8001) です。

dc_int() 以外に、 ioctlDC_INTON (データ収集の開始) および DC_INTOFF (データ収集の停止) から各々呼び出される dc_int_on() および dc_int_off() という関数を与える必要があります。 "dc_test.c" の例題が充分簡単だと思いますから、 以下に再掲します。 それぞれ LAM の enable/disable および output register のレベル出力 ON/OFF を行っています。

    static void dc_int_on() {
      int stat;
    # if (defined(LAM_N) && defined(LAM_A))
      camacCcycle2(LAM_N,LAM_A,26,NULL,&stat);
    # endif
    # if defined(OUTREG)
      dc_outreg |= 0xff00; /* set   higher 8-bit */
      camacCcycle2(OUTREG,0,16,&dc_outreg,&stat);
    # endif
    }

    static void dc_int_off() {
      int stat;
    # if defined(OUTREG)
      dc_outreg &= 0x00ff; /* clear higher 8-bit */
      camacCcycle2(OUTREG,0,16,&dc_outreg,&stat);
    # endif
    # if (defined(LAM_N) && defined(LAM_A))
      camacCcycle2(LAM_N,LAM_A,24,NULL,&stat);
    # endif
    }

戻る


以下は、自分でもっと便利なルーチンを書きたい、 或いは、通常と異なる凝った処理をしたいという人向けですので、 深入りしたくない方は読み飛ばしてください。

データ収集ルーチンとは言え、 Linux のような汎用 OS のデバイスドライバの一部を書くわけですから、 次のような一般的注意が考えられます。

例えば、 インテリジェント補助クレートコントローラ (ACC) で 割り込みを記述する場合には、 (Interrupt Register や ACC への直接のシグナル等によって) 出来るだけ早いタイミングで割り込みを発生させ、 割り込みルーチンの中では Q を見ながら ADC/TDC の変換終了を待って、 データ読み出しを行なうのが一般的と思います。 これは、データ収集の dead time を最小に抑えようとする配慮の結果ですが、 ACC が割り込み処理以外に重要な仕事をしていないからこそ 許される方法と言えます。

一方 Linux (を含む汎用 OS) では、 システムの他のサービスに対する遅延を防ぐために、 個々の割り込み処理を出来るだけ短時間に終了させたいという要請が有ります。 データ収集の効率は多少犠牲になりますが、 システム全体の有効な運用としては、 例えば以下のような方法が薦められます。

また、カーネルの一部である事から次のような注意も加えられます。 普通はあまり気にする必要は無いと思いますが、 簡単なデバッグ情報を printf() で出力させたいという事は 有るでしょう。 この場合には printk() という関数を使います。 使用法は printf() と同様ですが、 出力先は syslogd で指定されたファイル (通常は /var/log/messages 等) となります。 この出力は、 万が一カーネルパニックが起こった時も最期の断末魔の記録を残すため、 バッファされません。 従って、頻繁に printk() を行なうとシステムの負荷が グッと増える事に注意してください。 通常、/var/log/messages と言ったログファイルは、 セキュリティのために root のみが読み出せるように 設定されている事が多いですが、 末尾部分に関しては同等の情報を dmesg によって得る事ができます。

最後の注意は当たり前の事ですが、

繰り返しますがカーネルの一部なわけですから、 これらの異常動作はカーネルパニックの引金となり、 リセットスイッチを押さないといけなくなるかも知れません (無限ループの場合は確実にそうなります)。

戻る