AD変換について

こんにちは、sol です。

以前、「CS+ for CC のデバッグ・ツールについて」という質問で、一度お世話になりました。

 

最近、マイコンを触り始めたものです。

普段は、CS+ for CC で RL78/G14 の R5F104LE(64pin)、アプリケーション(CC-RL)でプロジェクトを作成して、シミュレータで動作確認を行っています。

現在は、こちら「https://toragi.cqpub.co.jp/tabid/864/Default.aspx」の「絵解き マイコンCプログラミング教科書」というので勉強しています。

こちらにはサンプルコードが載っており、今はそれを読み解く作業を行っております。

(もしダウンロードしてくださるのであれば、

ダウンロード・データ
→関連ダウンロードデータはこちら

という部分からダウンロードできますが、1.2GB もあります。

その中の、02_ボード動作確認用プログラム > C-First_TEST です。

該当のプログラムは、RL78IOlib.c の366行目からになります。)

その中の、AD変換を行っている部分について質問があります。

 

// AD変換割り込み処理
void ad_conv(void) {
static int adsel = 0;
static char test = 0;

if (test) {
test--; //1回目の測定結果を廃棄
return;
}
adout[adsel] = (adout_sum[adsel] + (ADCR >> 6)) / 2;
adout_sum[adsel] = adout[adsel];
adsel++;
if (adsel < 8) {
ADS = adsel;
} else if (adsel < 10) {
ADS = adsel + 10;
} else if (adsel < 12) {
ADS = adsel + 118;
test = 2; //1回目の測定結果の廃棄を指示(1回目どころじゃなくて、1回目と2回目を廃棄していると思います)
} else {
adsel = 0;
ADS = adsel;
ADMK = 1;
ADCS = 0; //AD変換停止
return;
}
ADIF = 0;
}

この ad_conv という関数がAD変換完了後に割り込まれる関数です。

一通り adsel == 11 まで行った後は adsel == 12 の時にAD変換が停止されますが、15kHz 低速オンチップ・オシレータ・クロックをクロックとするインターバルタイマによって 133[us] 間隔で割り込んでいる iv_timer という関数で、またすぐにAD変換が最初から開始されることになります。

ある程度時間を置くと(このプログラムでは rl78iolib_ini 関数内で wait(1000) つまり 約1秒待機しているようですが)adout[番号] にAD変換の結果が入ることになるのですが、その計算方法が独特だと思いました。

 

データシートに書いてあるように、ADCR(16bit)の上位10bitがAD変換の結果となるので、ADCR >> 6 は分かります。

しかし、adout と adout_sum(初期値は0)に分けているのが最初はよくわかりませんでした。

さらに、/ 2 はなぜあるのだろうかと疑問でしたが、上述したようなことが分かってきた結果、意味が分かりました。

AD変換が停止されるまでのワンループを1回とカウントして、n回目に得られたADCRの値を a_(n) とすると、

n 回目で adout に記録される値は、

 a_(n) / 2 + a_(n-1) / 4 + a_(n-2) / 8 + a_(n-3) / 16 + ... + a_(1) / (2^n)

になる(誤差はおいておいて)ということが分かりました。

この値は、ADCR の値が一定であればその値に近づく(無限に行えば収束する)ため、なるほどと思いました。

 

長々と読んでいただいてありがとうございました。

そこで質問です。

上述のように手間をかけて計算しているのは恐らく、ノイズによる影響を抑えるためではないか、と考えているのですが、その考えは正しいでしょうか。

また、AD変換において上述のように計算を行うのは一般的、よく使われる手法なのでしょうか。

 

ご回答、よろしくお願いします。

Parents
  • チョコです。
    これはIIR(無限インパルス応答)でしょう。移動平均とともにノイズ対策で使います。私はよく4回分の移動平均で、初期値は0ではなく、最初の変換結果を埋めていったものを使います。

    C-First で勉強されているのですか。このプログラミングは、基本的にArduino互換の使い方です。RL78では、殆ど使われてこなかった方法です。
    Arduinoは基本的にシングルタスクでのプログラミングです。プログラミングは簡単ですが、リアルタイム制御には少し難があります。それに対して、RL78では所謂ベアメタル型のプログラミングが中心です。複数のリソース(ハードウェアで準備された割り込み)をトリガにして必要な処理を行うことで、効率的な処理が可能です(RTOSを用いたマルチタスクよりは自由度は低いですが、限られたリソースの範囲でよりリアルタイムの処理が可能です)。
    少し話がずれますが、RL78IOlib.cのA/Dの処理には問題があります。A/Dの初期化処理のiniadconv関数で、ADCEN = 1;の前にADM0を設定(しかも無意味な設定ですが)しています。また、ADCE = 1;の直後にADCS = 1;としていますが、これはおかしな処理です(G14のマニュアルでは、「注2. ソフトウエア・トリガ・モード時およびハードウエア・トリガ・ノーウエイト・モード時,A/D電圧コンパレータはADCS ビットとADCEビットで動作制御され,動作開始から安定するまでに,1 μsかかります。このため,ADCEビットに1を設定してから1 μs以上経過したあとに,ADCSビットに1を設定することで,最初の変換データより有効となります。1 μs以上ウエイトしないでADCSビットに1を設定した場合は,最初の変換データを無視してください。」と記載されています)。これを守っていないので、A/D変換の1回目を読み飛ばす処理が必須になっています。A/D変換の起動はiv_timerで行うので、初期化で変換を起動する必要はないはずです。
    また、iv_timerは133us間隔であり、A/D変換は1チャネルで38usかかります。つまり、4チャネル目の変換中にiv_timerが起動して変換開始をトリガしているのは???です。

    言い出すと、際限がないので、ここまでにしておきます。

    以上

  • > 無限インパルス応答
    やはりノイズ対策だったのですね。
    4回分の移動平均をよく使われるとのこと、参考になります。

    > RL78では、殆ど使われてこなかった方法
    そうなんですね。。
    詳しくは書けませんが、教科書と基盤?を与えていただいて、このサンプルプログラムを理解できるまで勉強するように、と言われているので、今はこのプログラムを理解するので精一杯です。

    > RL78IOlib.cのA/Dの処理には問題があります
    おかしなところはいっぱい見つけており、正しいプログラムは何なのかコード生成やデータシートを見ながら確認しているので、その辺りは大丈夫だと思います。
    AD変換のうち、内部基準電圧1.45VをAD変換する場合を例にとると…
    まずAD変換の初期化処理は hdwinit に入れるべきだと思い、その中で
    ADCEN = 1; // AD変換にクロックの供給
    ADM1 = 0x20; // ワンショット変換モードにしてみる
    ADS = 0x81; // 内部基準電圧のAD変換
    ADCE = 1; // AD変換待機状態にする
    としておいて、main で
    ADIF = 0; // 一応やっとく
    ADMK = 0; // AD変換割り込み許可
    ADCS = 1; // AD変換開始
    とするのが正しいと解釈しています。
  • チョコです。

    >教科書と基盤?を与えていただいて、
    C-Firstは、RL78/G14のハードウェア環境としては、ほとんどこれだけで済むので悪くない選択ですよ。
    その上で、教科書の細かな制御は参考にしてみてください。

    >AD変換のうち、内部基準電圧1.45VをAD変換する場合を例にとると…
    この処理(ワンショット変換モード)は間違いです。内部基準電圧は2回変換動作を行い、1回目は無視して2回目の結果を採用するようにマニュアルに記載されています(RL78IOlib.cでは、このために余計にループするようになっています)。
    私が、よくやるのは、連続変換にして、1回目はADIFのポーリングを行い(ADMK=1)、ADIFをクリアしてからADMK=0にして2回目は割り込みで処理します。こうすると、実際に変換値の処理はA/D変換の割り込み処理で共通にできます。
  • ちょこです。
    >この処理(ワンショット変換モード)は間違いです。
    これが間違いですね。日ごろから、連続変換をよく使っていたので前回のコメントになりましたが、G14のマニュアルの「14.7.4 温度センサ出力電圧/内部基準電圧を選択時の設定」には、ワンショット2回での例が載っていますね。
  • ほんとだ、記載がありましたね…
    ADISSをセット(1)したあとの1回目の変換結果を使用できません
    とのことなので、ADISS をセットした後に1回無視すれば十分ですかね。
  • チョコです。
    >ADISS をセットした後に1回無視すれば十分ですかね。
    はい、1回目の変換結果だけを無視すれば十分です。
    (RL78のマニュアルには、結構使い方の情報が記載されていますよ。)
  • ありがとうございます。
    ちゃんと見た上でやってはいるのですが、14.7.1 のソフトウェア・トリガ・モード設定を見てやってしまったので、一回目の変換を捨てるというのが抜けていました。

Reply
  • ありがとうございます。
    ちゃんと見た上でやってはいるのですが、14.7.1 のソフトウェア・トリガ・モード設定を見てやってしまったので、一回目の変換を捨てるというのが抜けていました。

Children
No Data