CC7700とPC-Linuxを用いたCAMACデータ収集システム
(NaoDAQ)

岩佐 直仁

理化学研究所サイクロトロン研究室
基礎科学特別研究員

1998年 (平成10年)11月5日

  1. はじめに
    東陽テクニカ株式会社製CC7700型CAMACクレートコントローラ、 同社製AT互換機PCIバスインターフェースボード、IBM/AT互換機を用いて 安価で比較的高速なCAMACデータ収集システムを開発しました。 このシステムではCAMACサイクル毎に約5μ秒、割込みに約20μ秒の 時間がかかります。
    本プログラムは、freewareで、完全に無保証です。 著作権等はGNU一般公有使用承諾書に準拠します。

  2. データ収集システムの構成
    ハードウェアー
    CC7700型CAMACクレートコントローラとAT互換機PCIバス インターフェースボードについては東陽テクニカ株式会社に問い合せ下さい。 1枚のPCIバスインターフェースホードで8台まで CC7700型CAMACクレートコントローラを制御できます。

    ソフトウェアー
    このシステムのブロックダイヤグラムを下図に示します。
    高速な割込みを実現するため、データ収集プロセスをデバイスドライバーの形で カーネルに組み込みました。 データ収集プロセス内に無限ループを作ったり、LAMのクリアを忘れた場合には AT互換機がハングアップすることがあります。注意して下さい。(この場合、CAMAC の電源を切って下さい。) データ収集プロセスでは、デバイスドライバーに許されたサブルーチンしか callできない。浮動小数点計算やファイル制御はできません。 CAMACでLAMが発生すると、インターフェースボードはIRQ(インターラプトリクエスト) を発生し、割込みルーチン(dc_int.c)に制御を移します。 このルーチンはLAM発生時に行なうCAMACコマンドを書き、読んだデータを イベントバッファ(最長2キロワード)に書き込みます。 イベントは、デバイスドライバーの64キロワードのバッファーにコピーされ、 ブロック化プロセス(dma_control)からREADコマンドで読まれ、 共有メモリー上に作成した8連の16キロバイトのブロックに書き込まれます。 デバイスドライバーの64キロワードのバッファーが一杯になった場合には、 ブロック化プロセスから読まれるまでデータ収集を停止するようにしています。 ブロック化プロセスは、必要な場合にはブロック毎にファイル又はデバイスに 保存します。 共有メモリーのバッファーは、複数のプロセス(オンラインモニターや状況モニター) で読むことができます。 ユーザが指定したコマンドは、I/O制御命令を用いてデバイスドライバーに 送られるため、制御用プロセス(COM)が消えても、データ収集系に影響を与えない ように設計しています。

  3. インストールの方法
    1. Linuxで動かせるIBM PC互換機を1台用意して下さい。
      Aopen社AX6Lマザーボードに東陽テクニカ株式会社製AT互換機PCIバスインター フェースボードを差した場合、起動しないという現象が報告されました。 ASUS社P2L97マザーボードと交換では正常に動きました。 PCIバスインターにはマザーボードとの相性があるようです。
    2. PCにLinuxをインストールしてください。 kernelは2.0系のものを使ってください。
    3. ここをクリックして、 データ収集システムversion 1.1.21ソースプログラムを入手してください。
    4. tarを用いてソースプログラムを解凍します。具体的にはshell上で tar zxvf cc7700-1.1.1.tarとタイプして下さい。 ソースプログラムが cc7700/ ディレクトリーに作られます。
    5. cc7700/ ディレクトリーに移動して下さい。(cd cc7700)
    6. スーパユーザ(root)になり、make devicesとタイプします。 cc7700用のデバイス(/dev/PCIcc7700)が作られます。
    7. 可能であれば、以下のコマンドでinsmod, lsmod, rmmodのコマンドに スーパユーザビットを立てて下さい。 セキュリティ上の問題を生じる可能性があるので、ユーザの判断で行なって 下さい。
      (今後は、スーパユーザビットを立てていることを前提として書きます。 スーパユーザビットを立てない場合にはstart_daqの 実行の度にスーパユーザになる必要があり、不便です。)コマンドは以下の通りです。
      chmod +s /sbin/insmod; chmod +s /sbin/lsmod; chmod +s /sbin/rmmod

    8. 測定毎の準備
      1. cc7700/ ディレクトリに移動します。
      2. dc_int.cを書き換えます。
        このファイルには、5つのサブルーチンがあります。このファイルはデバイスドライバ としてOSに組み込まれるので、無限ループに注意して下さい。また、浮動小数点 演算用のサブルーチン、ファイル制御ルーチン等は使用できません。使用する変数は 必ずstatic型で作成して下さい。auto型で巨大な配列を作成した場合には、システムの スタックを食い潰し、OSをハングアップさせる可能性があります。

        dc_int_init():初期化時、クリアー時に呼ばれます。
        dc_int_start():データ収集開始時に呼ばれます。
        dc_int_stop():データ収集終了時に呼ばれます。
        dc_int(unsigned short *):LAM信号が入る度に呼ばれます。
        dc_int_clear():dc_int終了後と、データ収集開始時、ブロックの終了の スケーラー読み出し後に呼ばれます。 次の事象を読めるようにシステムをクリアーするために使われます。

        dc_intの引き数のbufferには、データを入れて下さい。 buffer[0]には全バッファー長(buffer[0]を含む)を代入して下さい。 このデータは、ブロック化プロセスに渡され、ディスクに書かれ、 解析プロセスで使用されます。

        このサブルーチンでは以下のCAMAC制御コマンドが使用できます。

        void camac_CNAF(int C,int N,int A,int F)
        クレート番号c[0-7]、ステーション番号N[1-23]、サブアドレスA[0-15]に ファンクションF[0-31]を送り、CAMACサイクルを起動させます。
        void camac_write16(short data)
        次のCAMACコマンドの為に16bitのデータを送ります。
        void camac_write24(long data)
        次のCAMACコマンドの為に24bitのデータを送ります。
        short camac_read16()
        前のCAMACコマンドで得られた16bitデータを返します。
        long camac_read24()
        前のCAMACコマンドで得られた24bitデータを返します。

        #include "camack.c"
        
        #define INPUT_REGISTER  1       /* station number of input register   */
        #define INPUT_REG_RF    0       /* read function of input register    */ 
        #define INPUT_REG_RA    0       /* read sub-address of input register  */
        #define INPUT_REG_CF    9       /* clear function of input register   */
        #define INPUT_REG_CA    0       /* clear sub-address of input register */ 
        
        #define ADC             2       /* station number of ADC              */
        #define ADC_RF          0       /* read function of ADC               */ 
        #define ADC_CF          9       /* clear function of ADC              */
        #define ADC_CA          0       /* clear sub-address of ADC            */  
          
        #define SCALER          4       /* station number of scaler           */
        #define SCALER_RF       0       /* read function for scaler           */ 
        #define SCALER_CF       9       /* clear function for scaler          */
        #define SCALER_CA       0       /* clear sub-address for scaler        */
        
        #define OUTPUT_REGISTER 5       /* station number of output register  */
        #define OUTPUT_REG_F    17      /* write function of output register  */
        #define OUTPUT_REG_A    0       /* write sub-address of output register*/
        
        #define LAM_N           ADC     /* LAM source is ADC         */
        #define LAM_F           26      /* function for enable-LAM    */ 
        #define LAM_A           0       /* sub-address for enable-LAM */
        
        static long loop=0,data;
        static int stat;
        
        static void dc_int_init(),dc_int_start(),dc_int_stop(),dc_int_clear();
        
        static void dc_int_init()
        {
          camac_CNAF(0,SCALER,SCALER_CA,SCALER_CF);    /* clear scaler */ 
        }
        
        static void dc_int_start()
        {
          camac_write24(0x0000f0);			
          camac_CNAF(0,OUTPUT_REGISTER,OUTPUT_REG_A,OUTPUT_REG_F);
        				/* send signal to output register A=5-8 */
          dc_int_clear();			/* clear LAM and modules */
          camac_CNAF(0,LAM_N,LAM_A,LAM_F);  	/* enable LAM            */
        }
        
        static void dc_int_stop()
        {
          camac_CNAF(0,LAM_N,LAM_A,24);	/* disable LAM */
          camac_write24(0x000f00);
          camac_CNAF(0,OUTPUT_REGISTER,OUTPUT_REG_A,OUTPUT_REG_F);
        				/* send signal to output register A=9-12 */
        }
        
        static void dc_int_clear()
        {
          camac_CNAF(0,ADC,ADC_CA,ADC_CF);	/* clear data of ADC */
          camac_CNAF(0,ADC,ADC_CA,10);		/* clear LAM  of ADC */
          camac_CNAF(0,INPUT_REGISTER,INPUT_REG_CA,INPUT_REG_CF);
        					/* clear input register */
          camac_write24(0x00000f);
          camac_CNAF(0,OUTPUT_REGISTER,OUTPUT_REG_A,OUTPUT_REG_F);
        				/* send signal to output register A=1-4 */
        }
        
        static int dc_int(unsigned short buffer[])
        {
          long j; 
        
          loop++;
          j=inl(BASE_ADDRESS+4);  /* check LAM */
          if(j==0){
            printk("dc_int: interrupt %d happened, %d, LAM=%lx\n",IRQ,loop,j);
        			/* write warning for illegal LAM to dmesg */
            return(-1);		/* return                             */
          }
          buffer[0]=8;		/* fixed event length (8 words) */
          camac_CNAF(0,INPUT_REGISTER,INPUT_REG_RA,INPUT_REG_RF);
          buffer[1]=camac_read16();   /* first data is bit pattern of input register*/
          camac_CNAF(0,ADC,0,ADC_RF);
          buffer[2]=camac_read16();   		/* second data is ADC A=0 */
          camac_CNAF(0,ADC,1,ADC_RF);
          buffer[3]=camac_read16();   		/* the third data is ADC A=1 */
          camac_CNAF(0,ADC,2,ADC_RF);
          buffer[4]=camac_read16();   		/* the fourth data is ADC A=2 */
          camac_CNAF(0,ADC,3,ADC_RF);
          buffer[5]=camac_read16();   		/* the fifth data is ADC A=3  */
          camac_CNAF(0,SCALER,0,SCALER_RF);
          j=camac_read24();	      
          buffer[6]=j&0xffff;
          buffer[7]=(j>>16)&0xffff;   		/* 24 bit write for scaler    */
          return(0);
        }
        
      3. event.cを自分の測定に合せて書き直します。
        このファイルには、オンライン解析ルーチンからイベント毎に呼ばれる サブルーチンを記述します。これは、通常のプロセスなので、浮動小数点計算や、 ファイル制御を行なうことができます。 この例は、オンライン解析に、CERNライブラリーのPAWを使用しています。 引き数には、イベント毎のバッファ(dc_intで渡した内容)が渡されます。 バッファーは読み出し専用です。書き込むと誤動作することがあります。

        #include "/cern/97a/include/cfortran/cfortran.h"
        #include "/cern/97a/include/cfortran/hbook.h"
        		/* these include files are need for calling HBOOK subroutines
        		   from the C language */
        
        #define HBOOK_SIZE 200000
        
        void analyze_(unsigned short int data[])
        {
          static int loop=0;
          int i,j;
        
          if(loop==0){
            HLIMAP(HBOOK_SIZE,"SAMPLE");	     /* make global section "SAMPLE"*/
            HBOOK1(11,"SSD1R-L",4095,0.5,4095.5,0.0);/* define 1-dim histograms */
            HBOOK1(12,"SSD2R-L",4095,0.5,4095.5,0.0);/* see HBOOK manuals in CERN-lib*/
            HBOOK1(13,"SSD3R-L",4095,0.5,4095.5,0.0);
            HBOOK1(14,"SSD4R-L",4095,0.5,4095.5,0.0);
            HBOOK1(15,"SSD5R-L",4095,0.5,4095.5,0.0);
            HBOOK1(16,"SSD6R-L",4095,0.5,4095.5,0.0);
            HBOOK1(17,"SSD7R-L",4095,0.5,4095.5,0.0);
            HBOOK1(18,"SSD8R-L",4095,0.5,4095.5,0.0);
            HBOOK1(19,"SSDR-L",4095,0.5,4095.5,0.0);
            HBOOK1(21,"SSD1L-L",4095,0.5,4095.5,0.0);
            HBOOK1(22,"SSD2L-L",4095,0.5,4095.5,0.0);
            HBOOK1(23,"SSD3L-L",4095,0.5,4095.5,0.0);
            HBOOK1(24,"SSD4L-L",4095,0.5,4095.5,0.0);
            HBOOK1(25,"SSD5L-L",4095,0.5,4095.5,0.0);
            HBOOK1(26,"SSD6L-L",4095,0.5,4095.5,0.0);
            HBOOK1(27,"SSD7L-L",4095,0.5,4095.5,0.0);
            HBOOK1(28,"SSD8L-L",4095,0.5,4095.5,0.0);
            HBOOK1(29,"SSDL-L",4095,0.5,4095.5,0.0);
            HBOOK1(31,"SSD1R-H",4095,0.5,4095.5,0.0);
            HBOOK1(32,"SSD2R-H",4095,0.5,4095.5,0.0);
            HBOOK1(33,"SSD3R-H",4095,0.5,4095.5,0.0);
            HBOOK1(34,"SSD4R-H",4095,0.5,4095.5,0.0);
            HBOOK1(35,"SSD5R-H",4095,0.5,4095.5,0.0);
            HBOOK1(36,"SSD6R-H",4095,0.5,4095.5,0.0);
            HBOOK1(37,"SSD7R-H",4095,0.5,4095.5,0.0);
            HBOOK1(38,"SSD8R-H",4095,0.5,4095.5,0.0);
            HBOOK1(39,"SSDR-H",4095,0.5,4095.5,0.0);
            HBOOK1(41,"SSD1L-H",4095,0.5,4095.5,0.0);
            HBOOK1(42,"SSD2L-H",4095,0.5,4095.5,0.0);
            HBOOK1(43,"SSD3L-H",4095,0.5,4095.5,0.0);
            HBOOK1(44,"SSD4L-H",4095,0.5,4095.5,0.0);
            HBOOK1(45,"SSD5L-H",4095,0.5,4095.5,0.0);
            HBOOK1(46,"SSD6L-H",4095,0.5,4095.5,0.0);
            HBOOK1(47,"SSD7L-H",4095,0.5,4095.5,0.0);
            HBOOK1(48,"SSD8L-H",4095,0.5,4095.5,0.0);
            HBOOK1(49,"SSDL-H",4095,0.5,4095.5,0.0);
          }
          loop++;
          
          i=data[1]&0x07;			/* the event data are stored in data */
          HF1(11+i,(float)data[2],1.0);		/* fill histograms */
          HF1(19,(float)data[2],1.0);
          HF1(31+i,(float)data[3],1.0);
          HF1(39,(float)data[3],1.0);
          i=(data[1]>>3)&0x07;
          HF1(21+i,(float)data[4],1.0);
          HF1(29,(float)data[4],1.0);
          HF1(41+i,(float)data[5],1.0);
          HF1(49,(float)data[5],1.0);
        }
        
      4. makeと打って全てのプログラムをコンパイルします。

    9. データ収集システムの起動
      1. cc7700 ディレクトリーに移動します。
      2. start_daqと打ちます
        このコマンドは、デバイスドライバーを組み込み、データ収集系で必要な プロセスを起動します。X端末が正常に設定されていれば、2つのウインドが ディスプレー上に現れます。一つはデータ収集系制御のためのウインドで、 もう一つは状況モニターです。これらは、それぞれCtrl-DやCtrl-Cで消すこと ができます。(再起動には、ターミナル上、cc7700 ディレクトリーでcom、staと打ち ます。) もし、``Initialization of PCIcc7700 failed''というメッセージが出た場合には、 I/Oポートや割込み番号がぶつかっている可能性があります。 ``cat /proc/pci'', ``cat /proc/ioports'',``cat /proc/interrups''コマンド で調べ、バイオスで適当なポート番号、IRQ番号を指定して下さい。

    10. データ収集系の制御(COMの使い方)
      1. COMのウインドをクリックし、アクティブにします。
        COMウインドが存在していない場合には、xtermかktermでウインドを作り、 cc7700ディレクトリに移動後、``COM''と打ちます。
      2. 最初にCOMを起動すると、``Scaler??: station number (end=0)''と スケーラのステーション番号を聞いてきます。 スケーラモジュールがクレートに入っている場合には、そのステーション 番号を入力します。指定が終わった時には0を打って下さい。 スケーラは最大10台まで使用できます。 STAウインドに設定したスケーラのステーション番号が表示されます。 間違えた場合には、COMプロンプトが出た後でsetコマンドで再定義して下さい。
      3. ``COM''プロンプトが出た後で、以下のコマンドが使用できます。
      4. reset:スケーラのステーション番号の再設定。
      5. start:データ収集開始
        (STAウインドに開始時間と``acquiring''が表示されます。)
      6. stop:データ収集停止
        (STAウインドに終了時間が表示されます。)
      7. clear:データ収集システムをスケーラのクリアー
      8. set:ファイルに書く場合、ディレクトリとファイル名を指定します。
      9. open:収集されたデータをファイルに書きます
        コメントを入力します。setコマンドで指定した名前に".xxx"(xxxはラン番号) を付けたファイルを開きます。
      10. close:ファイルをクローズします。
        コメントを入力します。
      11. sca:スケーラの値を表示します。
      12. C/r:現在の状態を表示します。

      13. データをファイルに書かない場合
        start
        carrige-return (or sca ....)
        stop

      14. データをファイルシステム上のファイルに書く場合
        set
        path+filename たとえば、/data/test
        open /data/test.runnoというファイルを開く
        comment
        start
        carrige-return (or sca ....)
        stop
        close
        comment

      15. データをdeviceに書く場合
        set
        /dev/device st0: scsi tape, fd0: floppy (upto 89blocks)
        open /dev/st0というファイルが開かれる。
        comment
        start
        carrige-return (or sca ....)
        stop
        close
        comment

    11. オンラインヒストグラムの表示方法(PAW)
      1. xterm、ktermコマンドを使い、新しいウインドを作成します。
      2. ``paw''とタイプする。
      3. ``workstation type''と聞かれるので、X端末を使用している場合には、 1と打ちます。他のX端末に表示したい場合には、setenv DISPLAY xxxx:0で ディスプレーを指定してからPawを起動してください。
      4. グラフィックウインドが表われ、PAWプロンプトが表示されます。
      5. global_sec name
        と打ちます。 nameは``event.c''のHLIMAPで指定した名前を使います。 (この場合は、SAMPLE)
      6. h/listで、使えるヒストグラム番号を表示します。
      7. h/pl numberでヒストグラムを表示します。 numberh/listコマンドで表示したヒストグラム番号です。
      8. ヒストグラムの内容はgreset numberでresetできます。 幾つかのバージョンではPAW側の問題で、gresetでヒストグラムをリセット できません。この場合、sh erase numberと打つと、 ヒストグラムをリセットできます。 number=0の場合全てのヒストグラムをリセットできます。

    12. よくある問題の解決方法
      • COMがハングアップした場合
        dma_controlが動いていることを確認してください。 ``ps -x|grep dma_control|grep -v grep''と叩いて、dma_controlが起動している かどうか調べます。動いていない時にはrestart_dmaと打ち、dma_controlを 起動させて下さい。
        もし、dma_controlが動いている場合には、データ収集システムへのトリガー数を 少なくしてみて下さい。これで解決した場合には、トリガー数を減らした状態で測定 して下さい。
      • データが取られているのに、オンライン解析が動かない。
        ``ps -x|grep analyzer|grep -v grep''と打ち、analyzerが起動しているか調べて 下さい。動いていない場合にはrestart_anaコマンドで再起動して下さい。

謝辞
データ収集システムを開発する機会を与えてくれた 理化学研究所、特にサイクロトロン研究室の矢野主任、 森田さんに感謝します。 PC-LinuxとCC7000を用いたDAQのソースを下さった 東京大学の岡村さんと PC-LinuxのPCIコントロール方法を教えて下さった 高エネルギー研究所の安さんに 謝意を述べさせて頂きます。 本プログラムのdevice driverは岡村さんの開発したものを改良して 使用しています。(再配布を許可して頂いています。) workstationを用いたデータ収集システムについて情報を下さった 理化学研究所放射線研究室の 市原さん渡邊さん、 ミュオン科学研究室の中村さん[2]に感謝します。
APPENDIX
addressBASE ADDRESS+0BASE ADDRESS+4BASE ADDRESS+8
BITwritereadwritereadwriteread
31------
30------
29------
28------
27------
26------
25------
24------
23---LAM station 24 data bit 24data bit 24
22---LAM station 23 data bit 23data bit 23
21---LAM station 22 data bit 22data bit 22
20---LAM station 21 data bit 21data bit 21
19---LAM station 20 data bit 20data bit 20
18--crate Address 04 LAM station 19data bit 19data bit 19
17--crate Address 02 LAM station 18data bit 18data bit 18
16--crate Address 01 LAM station 17data bit 17data bit 17
15--- LAM station 16data bit 16data bit 16
14--- LAM station 15data bit 15data bit 15
13--station number 16 LAM station 14data bit 14data bit 14
12--station number 08 LAM station 13data bit 13data bit 13
11--station number 04 LAM station 12data bit 12data bit 12
10--station number 02 LAM station 11data bit 11data bit 11
9--station number 01 LAM station 10data bit 10data bit 10
8--subaddress 08 LAM station 9 data bit 09data bit 09
7LAM internal LAM internal subaddress 04 LAM station 8data bit 08data bit 08
6reset LAM sum subaddress 02 LAM station 7data bit 07data bit 07
5- online subaddress 01 LAM station 6data bit 06data bit 06
4- done function 16 LAM station 5 data bit 05data bit 05
3enable interruptenable interruptfunction 08 LAM station 4 data bit 04data bit 04
2inhibit inhibit function 04 LAM station 3 data bit 03data bit 03
1initialize no-Xfunction 02 LAM station 2 data bit 02data bit 02
0clear no-Qfunction 01 LAM station 1 data bit 01data bit 01
PCIcc7700クレートコントローラ取り扱い説明書より抜粋

参考文献
[1] T. Ichihara, T. Inamura, T. Wada, M. Ishihara, IEEE Trans. Nucl. Sci. 36 (1989) 1628.
[2] S.N. Nakamura and M. Iwasaki, Nucl. Instr. Meth. A388 (1997) 220.