• ベストアンサー

H83052 ITUタイマ機能 時間の測定について

現在h8/3052でITUタイマを利用して1msecごとに割り込みがかかるようにしてそのときにセンサで測定した値をA/D変換させるプログラムを作成しました。モニタプログラムのGDB-STUBをROM領域に書き込んでおりますので、GDBで実際にデバッグを行ってみました。 その結果、毎回の割り込みごとのA/D変換終了時のタイマカウントの値をその時の時間としてみているのですが、その時間間隔が正確に1msecではなく、タイマのカウントが最大で3クロック分くらいずれが生じてしまう結果になってしまいました。 タイマカウンタには、誤差は全くないと思いますので、他の原因として考えられるのはプログラムの部分でしょうか?A/D変換の変換開始のタイミングや、終了待ちの関係でしょうか。 その誤差の部分についてわかることがありましたら、ご回答よろしくお願いします。 必要であれば、プログラム内容も載せたほうがよろしいでしょうか。

質問者が選んだベストアンサー

  • ベストアンサー
  • R32C
  • ベストアンサー率39% (115/290)
回答No.4

そうでした。 TCRのCCLR0,1がゼロなので、クリアしないので、GRAのセットタイミングを 変えてもタイミングはかわりませんね。 いわゆるクロック時間で0.04usの1~4クロックぐらいはソフトで処理するとどうしても ずれるんじゃないでしょうか? 割込み処理についても、応答時間にぶれがあります。 [ハードウエアマニュアル5.4.3 割り込み応答時間 参照] 特に最終的には、内蔵メモリで実行されると思いますが 外部メモリと実行速度に差がでると思います。

utaibito33
質問者

お礼

<特に最終的には、内蔵メモリで実行されると思いますが <外部メモリと実行速度に差がでると思います。 実際に速度の違いが出てしまうと、最初のGRAの設定の部分でAD変換が終了した時点のTCNTカウンタの値が1msになるようにしているのでまずいかもしれません。その場合は設定しなおすしかないですね。 割り込み処理についての応答時間は確認していませんでした。かなりステート数に差がありますね。これも完全にぶれに含まれていますね。

その他の回答 (3)

  • R32C
  • ベストアンサー率39% (115/290)
回答No.3

誤差が、AD変換時間であるかどうかは、変換前に時間計測して 変換後の時間と比べればよいかと思います。 ---------------------------------追加---- time1_Mae[c] = ITU0.TCNT; ---------------------------------追加---- ITU0.TSR.BIT.IMFA =0; AD.CSR.BIT.ADST=1; while (AD.CSR.BIT.ADF ==0); time1[c]=ITU0.TCNT;

utaibito33
質問者

お礼

そうですね。 と思ったのですが、自分のやり方が、1ms分のカウンタ値をGRAに割り込みごとに足していく方法ですので、1回目はそれで計測できるのですが、2回目の割り込み以降AD変換時間影響がtime1_Mae[c]に入ってしまいます。 素直にAD変換の部分を抜かして測定してみましたが、誤差の範囲はあまり変化しませんでした。割り込みの部分にもそういったタイミングの問題がありそうです。

  • R32C
  • ベストアンサー率39% (115/290)
回答No.2

毎度です。 3クロックのずれぐらいなら、問題になるのもヘンな気がしますが? タイマはそうずれませんが、AD変換時間は、ステート数は常にづれる のではないでしょうか? マニュアルにも 変換時間 266ステート(max) 134ステート(max)とあるようにきっちり した時間ではできないようです。 さすれば、 1)タイマーの再設定をAD変換前にする。  (従来の1ms待って、ではなく、1ms周期になります) 2)スキャンモード それから、スキャンモードにして、常時AD値を変換させて おいて、1ms毎に最新データを読むだけ というやりかたも ありかと思いますが。

utaibito33
質問者

お礼

毎度の回答ありがとうございます。 そうですね3クロックのずれくらいならば、問題にならないとは感じています。 ただ ・その誤差が自分の作成したプログラムの方法によって生じてしまう問題(誤差を減らせる) ・クロックの関係よりくる、タイミングのずれ(誤差は少なくともこれだけ発生してしまう) のどちらに原因があるのか、知りたかったので。。。 タイマーの再設定をAD変換前にする方法の方が周期的にはよいみたいですね。やってみます。 スキャンモードについては、考慮していましたが、最新のデータがちゃんと1ms(誤差の範囲内)のデータであるのか少し微妙な気がします。常時AD変換を行うサイクルとかのタイミングというのも関係してくると思いますが。

  • bug_bug
  • ベストアンサー率78% (36/46)
回答No.1

プログラム設計の仕様が見えないと誤差の原因特定は難しいですね。 タイマ割り込み処理、A/D変換完了割り込み処理、メインループ、各割り込みの優先度辺りの内容が把握できると動作がイメージできますが。 以下、駄文。 例えば前回提示いただいたサンプルの様な実装の場合、タイマ割り込みはカウンターのインクリメントのみ行い、メインループにてA/D変換の完了をポーリングする実装になっています。 while (AD.CSR.BIT.ADF == 0); といった待ち方をした場合、 ポーリングでA/Dの完了フラグをリードする以上、内部レジスタのリードアクセスはクロック同期である為、毎回の完了確認に誤差が発生します。(ポーリングによる誤差) さらにタイマカウンタはφで指定した間隔でインクリメントされますが、A/D変換は同期していませんので、誤差の算出を前回のA/D変換が終了した際取得したTCNT値からの差分で算出しているのであれば、前回のTCNT値取得がインクリメント寸前で取得され、今回のTCNT取得がインクリメント直後で取得されることが原因で1,2クロックズレることも考えられます。(時間の取得方法による誤差) また、A/D変換の完了とタイマのコンペアマッチがほぼ同時に発生した場合、割り込み処理が完了するまでメインのループはCPUを使用できません。 A/D変換完了フラグをリードする処理が待たされ、結果TCNT値の取得も遅延して取得する結果となります。 (優先度による誤差) ぱっと思いつく要因3点ですが、タイマの取得のたびに「揺れ」が発生するのであればここらが原因でしょうか。 逆にA/D変換の完了を割り込みで処理する実装と比較することで、原因の特定が容易になることもありますね。 以上、参考になれば、、、。

utaibito33
質問者

お礼

回答本当にありがとうございます。 やはりwhile文で待った時に誤差が生じる原因になっているとは思いました。現在のプログラムは以下になっており、タイムの取得のたびに微妙にずれが生じています。 やはりwhile文を何回も使用しているのが原因になっているのでしょうか。 #include "H83052-itu.H" int n,c,t; unsigned long time1[201]; unsigned long time2[201]; unsigned long time3[201]; unsigned long time4[201]; unsigned int data[201]; void initITU0(void) { ITU0.TCR.BIT.CCLR0 = 0; //カウンタのクリア要因 TCNTカウンタのクリア禁止 ITU0.TCR.BIT.TPSC = 3; // クロックのφ/8で動作(25MHz=1クロック0.04[μsec] ITU0.TIOR = 0; // コンペアマッチによるITU端子出力の禁止 ITU0.TIER.BIT.IMIEA=1; ITU0.GRA = 3064; //1msecごとの測定が可能になるように調整 1000[usec]/0.32[usec]=3124[クロック]-A/D変換に必要なクロック数 ITU.TSTR.BIT.STR0 = 0; //チャネル0のTCNTの停止を選択 ITU0.TCNT = 0; //タイマカウント値クリア } #pragma interrupt void int_imia0(void) { ITU0.TSR.BIT.IMFA =0; AD.CSR.BIT.ADST=1; while (AD.CSR.BIT.ADF ==0); time1[c]=ITU0.TCNT; data[c] = AD.DRA >> 6; /*下位へ6ビット分ずらす*/ data[c] = data[c] & 0x3ff; /*上位6ビットクリア*/ AD.CSR.BIT.ADF = 0; /*変換終了*/ c++; ITU0.GRA = ITU0.GRA + 3124; if(c==201){ t=0; } } 字数が足りないのでmain関数は、補足に記載します。

utaibito33
質問者

補足

int main(void) { while(1){ PA.DDR = 0x00; Init_AD(); //A/Dconverter初期化 c=1; t=1; initITU0(); //タイマITU0の初期化 EnableInterrupt(); while(PA.DR.BIT.DR0=0); //信号待ち(SW0:PA-0) for(n=0;n<201;n++){ data[n]=0; time1[n]=0; time2[n]=0; time3[n]=0; time4[n]=0; } ITU.TSTR.BIT.STR0 = 1; //TCNTの動作を選択=タイマスタート while (t); ITU.TSTR.BIT.STR0 = 0; //チャネル0のTCNTの停止を選択 for(c=1;c<201;c++){ if(time1[c]>time1[c-1]){ time2[c] = time1[c] - time1[c-1]; } else{ time2[c] = 65535 + time1[c] - time1[c-1]; } time3[c] = (time2[c]+1) * 32; time4[c] = time4[c-1] + time3[c]; } } }

関連するQ&A