INtimeドキュメンタリトップへ

アナログデータ変換値取得スレッド完成!!

課題
アナログボードと格闘し、やっとアナログデータ変換値を取得することができるようになりました。
アナログのデータは100msのポーリング周期で取得します。
スレッドの流れとしては、

ボード検出(アナログボードを検出)→初期処理(アナログボードの初期化→アナログデータ取得準備)→サンプリング開始→データの取得

となります。

10月17日・・・割り込み処理 (割り込みハンドラ・割り込みスレッド)

仕様では、100ms毎にアナログデータ取得のため"サンプリング開始"コマンドを出力し、0~7CHの"データを取得する"ことでアナログデータ取得スレッドは完成します。


●ボード検出処理

  FindAnalogBord()

●アナログボード初期処理

  InitAnalogBoard()

アナログデータ取得スレッドはvoid GetADataThread(void)で、このスレッドの主なタスク(仕事)は100ms毎にアナログボードのサンプリング開始コマンドを出力し、8CH分の変換データを取得することです。100msのポーリング周期を作るということは・・・

下記のようになります:
while(1){
	RtSleep(100);	//100msスリープ
}

トラブル発生

変換データを取得部でトラブルが発生しました・・・・・。

「変換データの取得割り込みが発生しない!!」


割り込み要因は設定しているのに・・・。
割り込みというものがよく分からない私は、何をどのように調査してよいものか分かりませんでした。

必要なものはボードのIRQと、そのボードの割り込み要因の特定

 
●IRQ(割り込み番号):0~15までの割り込み番号があり、それぞれのハード機器は割り込み番号が
 割り振られています。                    
●割り込み要因の特定:上記の割り込み 

トラブルの解決

どういう状態が割り込みが入った状態なのか分からなかったため、混乱してしまいました。

まったく動いていない状態がその状態と早とちりし、「動かない=割り込みが入らない」と考えていましたが、WaitForRtInterrupt()でエラーチェックをしてみると・・・返ってきたエラーの内容は・・・

・・・・割り込みハンドラを作っていない!!
≪・・・・・これじゃ割り込み入らない・・・・・≫

「割り込みハンドラは特定の割り込みレベルの信号入力をうけ起動します。
割り込み信号が発生時、スレッドを起動すべき割り込みかどうかを判別し、スレッド起動をかける・・・ということでした。」


その後、割り込みハンドラをつくりましたが数々の失敗がありました。

代表的なものは:


●アナログボードの初期化に失敗していたため、割り込みの設定がうまくいかなかった

  アナログボードのアクセスのために、先頭アドレスからのオフセット値を宣言したヘッダを作成しました。 この作成したヘッダの値が10進数の値を16進表記するときにそのまま10進表記していた事により設定した内容が指定のアドレスに書き込まれていませんでした。
(BaseAddress + 12 ⇔ BaseAddress + 0x12 としていた)以前にもベンダーID、デバイスID指定部この失敗をしました。

●設定したIRQ値が違っていたため、割り込みの設定がうまくいかなかった

  アナログボードの検出関数で割り込みレベル値を戻していたものを、途中で関数の型を変更し、戻り値をTRUE/FALSEとしました。しかし、そのまま戻り値を割り込みレベルと設定していたため、1(TRUE)という値で割り込みハンドラを設定していました。

上記の失敗を踏まえ、ボード検出処理FindAnalogBoard(アナログボードの検出)の結果、ボード検出OKの場合、CreateRtThreadによりGetDataThread(アナログデータ取得スレッド)が生成されます。

GetDataThreadの開始部で、アナログボードの初期処理InitAnalogBoard()をコールします、同時に、割り込み要因(Data Read Enabled)の割り込み時にイベントを受け取り、そのタイミングでサンプリングを行わなければいけませんので、割り込みハンドラを設定しました。

割り込みハンドラのコードはINtimeウィザードで割り込みハンドラとスレッド、を指定することにより、コードは出力されますので、処理をその中に記述しました。

以下が割り込みハンドラの設定APIです:
  SetRtInterruptHandler(wLevel, 1, Int1Handler))

INtime HelpからSetRtInterruptHandlerを調査すると、上のシステムコールは「割り込みレベルwLevelの割り込みが1度入力するとInt1Handlerに処理を渡します(Int1Handlerをコールします)」と読むことができます。
すでにウィザードによりコードができていますので、ハンドラの呼び出し部分はよし。

割り込みハンドラ側(Int1Handler)で割り込み要因の特定を行わなければなりません。
割り込みレベルを設定したハンドラには、そのレベルの割り込みがすべてはいります。
割り込みの入力時にある特定の状態時のみ処理を行う場合、割り込みハンドラ内でその条件を判別し、条件成立時はSignalRtInterruptThread(wLevel)で割り込みスレッド起動をし、それ以外はSignalEndOfRtInterrupt(wLevel)で抑制します。


割り込みハンドラの記述部分:
__INTERRUPT void Int1Handler(void)
{
   __INTERRUPT_PROLOG();	//割り込みハンドラの範囲開始

    // 割り込みレベルを設定します
   EnterRtInterrupt(wLevel);

	
   //割り込み要因の特定:
  if ((inbyte(strInfo.analogAdd + 0x0c & 0x02 != 0x02) 
          SignalEndOfRtInterrupt(wLevel);//特定の割り込み条件以外はシグナル発信を停止
	
   else
          SignalRtInterruptThread(wLevel);//特定の割り込み条件成立時はシグナルを発する

   __INTERRUPT_RETURN();	//割り込みハンドラの範囲終了
}                   
割り込み要因が確定した場合のみ出力する(SignalRtInterruptThread)によりWaitForRtInterrupt()で割り込み待ち処理以下の処理が実行されます。

実コードは以下のようになるでしょう:

スレッドの記述:
while(1){
    RtSleep(100);	//100msスリープ

	
    //変換データが設定されるまで(割り込みが発生するまで)待つ:
    wLevelはアナログボードの割り込み番号
    if(WaitForRtInterrupt(wLevel,WAIT_FOREVER) != TRUE){
		
            //ブロック
    }

   アナログ変換データを取得する

}


本日の感想

割り込みスレッドとは、割り込みハンドラを設定し、ハンドラにより起動されるスレッドで、それ以外は特に通常のスレッドと変わりがないということが分かりました(スレッドの生成方法など・・・)。