ADコンバータとDTC転送(ソフトウエアトリガ、スキャン、ワンショット変換)で他の端子のアナログデータを読み込む

アナログAN3-AN9の7CHをスキャンモードでDTC転送で読み込んでいます。

メインループで、タイマー1msec割り込みを利用し、2msec毎にADスタート、DTCスタートしております。

AD変換終了割り込みでCHを切替ていますが、CS+のウオッチで変換データbuffer3~9を見ていると、

たまにbuffer3にbuffer4のデータが読み込まれたり(ほかのCHも同じことがおこっている)

しています。

ADスタートかDTC転送のどこを修正したらよいか困っており、ご教授をお願い致します。

 

ソース

メインループ r_main.c

while (1U)
{

---

if(timer_2msec == 0) /****** 2m sec 周期 *****/
{
timer_2msec = 2; 
NOP();
R_ADC_Start(); //A/Dコンバータスタート
R_DTCD0_Start(); // DTC enabled
}

 

割り込み処理 r_cg_adc_user.c

static void __near r_adc_interrupt(void)
{
/* Start user code. Do not edit comment generated here */

R_ADC_Stop(); //ADCS = 0U


if(ad_ch_fg == 0){
buffer3 = (g_ad_value[0U] & 0xFFC0U) >> 6U;
buffer4 = (g_ad_value[1U] & 0xFFC0U) >> 6U;
buffer5 = (g_ad_value[2U] & 0xFFC0U) >> 6U;
buffer6 = (g_ad_value[3U] & 0xFFC0U) >> 6U;

NOP();
ADS = 0x07; // AN7-AN10に切替
NOP();
NOP();
NOP();
R_ADC_Start(); //ADCS = 1U
R_DTCD0_Start(); //DTCスタート
}
else if(ad_ch_fg == 1){
buffer7 = (g_ad_value[0U] & 0xFFC0U) >> 6U;
buffer8 = (g_ad_value[1U] & 0xFFC0U) >> 6U;
buffer9 = (g_ad_value[2U] & 0xFFC0U) >> 6U;
bufferA = (g_ad_value[3U] & 0xFFC0U) >> 6U;

NOP();
ADS = 0x03; // AN3-AN6に切替
NOP();
NOP();
NOP();
ad_fin_fg = 0;
}

ad_ch_fg ^= 0x01;
NOP();

/* End user code. Do not edit comment generated here */
}

 

  • チョコさん、NoMaYさん、こんにちは。ご回答ありがとうございます。

    ・「CS+のウオッチで変換データbuffer3~9を見ている」のは、
    デバッグツールにE1を使用しており、デバッグツールの設定→実行中のメモリアクセス→実行中に表示更新を行うを「はい」に設定。表示更新間隔を200msにして、リアルタイムで数値を見ております。
    (10bitの値を10進数で表示している)


    ・ AN3-AN6にそれぞれ100、1023、200、300を入力した状態 (値はたまに違うアナログ端子のデータが表示されるが、だいたいは正常な値が表示されるので、この値にボリュームで調整した)にし、
    異常値の時に、カウンタをカウントアップさせてみました。

    if(ad_ch_fg == 0){
    buffer3 = (g_ad_value[0U] & 0xFFC0U) >> 6U;
    buffer4 = (g_ad_value[1U] & 0xFFC0U) >> 6U;
    buffer5 = (g_ad_value[2U] & 0xFFC0U) >> 6U;
    buffer6 = (g_ad_value[3U] & 0xFFC0U) >> 6U;

    if(buffer3 > 200 | buffer4 < 900 | buffer5 >300 | buffer6 >400){
    NOP();
    test16++;
    }

    これで、test16の値がカウントアップしていることを確認しました。
    上記のNOP();でブレークポイントを設定すると、STOPすることも確認しました。
    (その時、例えばbuffer3に1023が表示されたり、buffer6に101が表示されたりする)

    現在は、R_ADC_Start();とR_DTCD0_Start();の順番を(R_DTCD0_Start();が先でR_ADC_Start();が後)にしておりますが、症状は改善していない状況です。

    ・メインルーチンの2msタイマのところ(DTCスタート、ADCスタートの前)にブレークポイントを設定してGo/Breakを繰り返すと、 AN3-AN6にそれぞれ100、1023、200、300を入力した状態 で、異常な数値は表示されないことを確認しました。
    (下位の数ビットは振れているので、データは更新されていると思います、例えばAN3が、100とか101が表示される)

    このような状況から、DTCかADのタイミング?がずれたりしているのか・・・と考えております。
  • まゆみ さん、こんにちは。チョコさんも、こんにちは。NoMaYです。

    振り子のように(というか螺旋階段?)アッチを疑いコッチを疑い再度アッチを疑い、という具合ですみませんが、添付されていたソースとここまでのやり取りを見直していて気になったのですが、リピート転送の場合、毎回、R_DTCD0_Start();する必要ってあったんでしょうか?(実は、リピート転送を実際に使ったことが無くて、デバイスのマニュアルを確認しようと思い始めたところです。あと、R_DTCD0_Start();の中身はどうなっていたかな、と自分のHDDの中の他のプロジェクトを確認してみようと思います。それから、似た感じのシミュレータのプロジェクトを作ってみようかなぁ、とも思います。)
    [訂正] すみません、リピートモード割り込みを使わないといけないので、毎回、R_DTCD0_Start();しないといけないのですね。失礼しました。

  • まゆみ さん、こんにちは。チョコさんも、こんにちは。NoMaYです。

    RL78/G14で似た感じのプロジェクトを作ってGo/Break/Stepとかさせていて思い浮かんだのですが、A/Dとタイマの割り込み以外にも割り込みは動いているとは思っているのですが、他の割り込みの影響で、「A/Dスキャン変換のDTC転送リピートモード割り込み要求」のCPU受け付けタイミングがミリ秒オーダー(かつ、不運にも、絶妙なタイミング)で遅延したりしていないでしょうか?例えば、試しに以下のようなソースにするとどうなるでしょうか?(他にも気になる点を2つほどコメントに書き込んでいます。)

        timer_2msec = 0;
        ad_fin_fg = 0;
        ad_ch_fg = 0;
        while (1U)
        {
            // タイマ割り込み周期は ちゃんと 1m sec か?
            // 以下の判定処理は 200usec に 1回 程度は確実に行われるか?
            if(timer_2msec == 0) /****** 2m sec 周期 *****/
            {
                if (ad_fin_fg == 0) // A/Dスキャン変換完了済み
                {
                    timer_2msec = 2;
                    ad_fin_fg = 1;

                    NOP();
                    R_DTCD0_Start(); // DTC enabled
                    R_ADC_Start(); // A/Dコンバータスタート
                }
                else // 未完(DTC転送リピートモード割り込みが m sec オーダーで保留された?)
                {
                    timer_2msec = 1; // もう 1m sec 待つ(それでも未完なら更に待つ)
                }
            }
        }

    気になったのは、その様な状況ですと、以下のR_ADC_Stop();が何か悪影響を与えるのではないかと思ったのです。(メインでR_ADC_Start()したA/Dスキャン変換を、途中で、受け付けが遅延した割り込み内でR_ADC_Stop()してしまっていないだろうか?)

    static void __near r_adc_interrupt(void)
    {
        /* Start user code. Do not edit comment generated here */

        R_ADC_Stop(); //ADCS = 0U

        if(ad_ch_fg == 0)
        {
            buffer3 = (g_ad_value[0U] & 0xFFC0U) >> 6U;
            buffer4 = (g_ad_value[1U] & 0xFFC0U) >> 6U;
            buffer5 = (g_ad_value[2U] & 0xFFC0U) >> 6U;
            buffer6 = (g_ad_value[3U] & 0xFFC0U) >> 6U;

            NOP();
            ADS = 0x07; // AN7-AN10に切替
            NOP();
            NOP();
            NOP();
            R_DTCD0_Start(); //DTCスタート
            R_ADC_Start(); //ADCS = 1U
        }
        else if(ad_ch_fg == 1)
        {
            buffer7 = (g_ad_value[0U] & 0xFFC0U) >> 6U;
            buffer8 = (g_ad_value[1U] & 0xFFC0U) >> 6U;
            buffer9 = (g_ad_value[2U] & 0xFFC0U) >> 6U;
            bufferA = (g_ad_value[3U] & 0xFFC0U) >> 6U;

            NOP();
            ADS = 0x03; // AN3-AN6に切替
            NOP();
            NOP();
            NOP();
            ad_fin_fg = 0;
        }

        ad_ch_fg ^= 0x01;
        NOP();

        /* End user code. Do not edit comment generated here */
    }

    また、この話は、以下の話とも関係があるかも知れません。

    > ・メインルーチンの2msタイマのところ(DTCスタート、ADCスタートの前)にブレークポイントを設定してGo/Breakを繰り返すと、 AN3-AN6にそれぞれ100、1023、200、300を入力した状態 で、異常な数値は表示されないことを確認しました。
    > (下位の数ビットは振れているので、データは更新されていると思います、例えばAN3が、100とか101が表示される)

    [追記]

    すみません、1つ書き忘れました。AN3~AN10のA/Dスキャン変換では、AN3-AN6の組とAN7-AN10の組とで、合計2回の「A/Dスキャン変換のDTC転送リピートモード割り込み要求」が発生しますが、シミュレータで試していると、各組のA/Dスキャン変換には150usecほどの時間が掛かるようで、1回目の割り込みと2回目の割り込みの間には少なくとも150usecほどの間が開くのですが、1回目の割り込みの受け付けが2msec弱ほど遅延した後、2回目の割り込みの受け付けが2msecをごくわずかオーバーしてしまった、というような状況が頭に思い浮かびました。

  • NoMaYさん、こんにちは。チョコさんも、こんにちは。ご回答ありがとうございます。

    下記のソースで確認してみました。

      if(timer_2msec == 0) /****** 2m sec 周期 *****/
    {
    NOP();
    P9_bit.no0 ^= 1;
    if (ad_fin_fg == 0)    // A/Dスキャン変換完了済み
    {
       timer_2msec = 2;
       ad_fin_fg = 1;
       NOP();
       R_DTCD0_Start();  // DTC enabled
       R_ADC_Start();   // A/Dコンバータスタート
    test16++;
    }
     else // 未完(DTC転送リピートモード割り込みが m sec オーダーで保留された?)
      {
      timer_2msec = 1; // もう 1m sec 待つ
    }

    この場合、ad_fin_fgが0にならなくなり、AD変換が止まってしまいました。
    test16というカウンタ値が30とかの数値で止まって(毎回同じカウントではない)しまいます。
    ブレークしているわけではなく、メインループの他の処理は走ってます。

    タイマ割り込み周期については、2msタイマのところでポートP90を反転して、オシロで波形を確認し、
    2msであることを確認しました。他の割り込みの影響?で数10μsは、ずれたりします。

    if (ad_fin_fg == 0)    // A/Dスキャン変換完了済み
    {・・・・・
    の条件を追加すると、なぜかad_fin_fg が0にならないことがあるので、
    割り込み処理の最初、R_ADC_Stop();が影響しているのでしょうか・・?
    もう少し確認してみます。
  • まゆみ さん、こんにちは。NoMaYです。

    その後、どうでしょうか?進展はありましたでしょうか?

  • NoMaYさん、こんにちは。
    その後、時間の問題もあり、DTC転送でのスキャンモードは一旦あきらめ、セレクトモードにて
    1ch毎に切り替えてAD変換値を読み込む方法に変更して、進めておりました。
    ただ、10個のアナログ入力値を読みたいため、変換時間が結構かかるなぁと思い、DTC転送でのスキャンモード
    を再確認したところ、

    ADコンバータの変換時間を遅くすると、解消するのではないかということがわかりました。
    もともと、CPUのシステムクロック8MHz、AD変換時間4.75μs(38/fclk)としていましたが
    これを、変換時間19μs(152/fclk)とすると、AD値が異常の時にカウントアップさせていたカウンタが
    カウントしなくなるこを確認しております。
    (CS+のウオッチで確認)
    この変換時間以上に早くすると、AD異常のカウントがカウントされます。


    2ms毎でのAD変換完了済みフラグの確認は、そのまま残した状態で、
    AD変換終了割り込みの最初R_ADC_Stop();は削除したり、その他、少し変更しているところもありますが、
    多分この変換時間の設定が原因だったのではと思っております。

    もう少し確認できたら、最終結果を書き込みします。

    ご確認ありがとうございます。
  • まゆみ さん、こんにちは。NoMaYです。

    > ADコンバータの変換時間を遅くすると、解消するのではないかということがわかりました。
    > もともと、CPUのシステムクロック8MHz、AD変換時間4.75μs(38/fclk)としていましたが
    > これを、変換時間19μs(152/fclk)とすると、AD値が異常の時にカウントアップさせていたカウンタが
    > カウントしなくなるこを確認しております。

    これは、他のDTC転送にざっくりと 4.75μs/125ns=38バイト ぐらい以上のDTCブロック転送があって(DTCコントロールデータの読み込みや書き戻しの分もあるのでもうちょっと少なくても起きるかも)、その転送中に各A/D変換終了割り込み要求の1つ(or 複数)をDTCが受け付け損ねてしまったのかな、、、あるいは、DTC保留命令で構成された何かのフラグ待ちループが4.75μs以上継続してしまって、同じことが起きてしまったとか、、、

    それでは最終結果の書き込みを待つようにします。

  • まゆみ さん、こんにちは。NoMaYです。

    その後、どうでしょうか?最終結果に関してのまとめは出来上がりそうでしょうか?

  • NoMAYさん、こんにちは。
    すいません。その後他の仕事に忙殺されておりまして。。
    今のところ、4月末か連休明けぐらいで再開する予定です。

    気にかけて頂き、ありがとうございます。
    少し先になりますが、また再開しましたら、書き込みします。
  • まゆみ さん、こんにちは。NoMaYです。

    その後、どうでしょうか?再開することは出来ましたでしょうか?