Sigma-Delta A/D変換
原題:AN008 Sigma-delta Analog to Digital Conversion
状態:この文書は現在翻訳中です
原文:
翻訳者:caskaz
対象読者:A/D変換したい人
P8X32Aの任意のCogで2本のI/Oピンと安価な受動素子を使ってSigma-Delta A/D変換を実現します。
この簡単な技術は校正はもちろん、マルチ・アナログ入力、マイクなどの交流信号、入力電圧範囲の拡張など様々に応用できます。
Propellerの8個のCogはそれぞれが2つの多機能カウンターモジュールを内蔵しており、このモジュールは外部に幾つかの受動素子をつけることによってSigma-Delta技術を使ったA/D変換を設定できます。
これは
アナログ回路を設計する人なら図1のような反転オペアンプをよく知ってると思います。
図1に於いてオペアンプの出力はマイナス入力ピンとプラス入力ピンの電圧が等しくなるように動作します。
アナログ入力電圧がゼロの場合、Vdd/2が印加されたプラス入力とマイナス入力が等しくなるように働きその結果オペアンプの出力はVddに等しくなります。
仮にアナログ入力がVddならオペアンプ出力はバランスを維持するようにその出力をゼロとなるよう動作します。
さてオペアンプの代わりにCMOSのDフリップフロップに高い周波数のクロックを入力します。(図2)
オペアンプのようにフリップフロップの負帰還(コンデンサにより取り出される)はD入力のスレッショルド(Vdd/2)付近になるように働きます。
アナログ入力がゼロの時、/Q出力はVdd(論理値:1)を維持しなければなりません。
逆に、アナログ入力がVddの時は/Q出力はVss(論理値:0)を維持しなければなりません。
中間点では/Q出力はD入力がVdd/2で平衡するのに必要な補正量に比例したduty cycleのパルス列を出力します。
例えばアナログ入力がVdd/4なら、/QはD入力がVdd/2を保持するようにduty cycle75%のパルスを出力する必要があります。
アナログ入力電圧値を測定するには補正する/Q出力のduty cycleを知る必要があります。しかし、/Qは反転されてるのでQ出力のduty cycleがアナログ入力電圧に比例しています。
そしてQ出力はクロック数と同義なのでこのduty cycleはフリップフロップに加えられたクロック数を数えることで簡単に測定できます。
これがSigma-Delta A/D変換の根本的要素です。
PropellerはSigma-Delta A/D変換を簡単に実現するためのハードウェア(Cogのカウンタとsystem conter register,CNT)を持っています。
system conter registerは内部クロックによって1ずつ増加します。このカウンタは$FFFF_FFFF(2の32乗ー1)を越すと又ゼロからカウントアップします。
80MHz内部クロックの場合、CNTの1周期は大体53秒です。
各々のCogは2つのカウンタを持ち、特殊機能レジスタCTRx,FRQx(このxは参照するカウンタによってA又はBを使用します)によって構成されています。
CTRxレジスタはカウンタモードを決定し、カウンタが使う外部ポートを割り当てます。
Signa-delta動作ではカウンタモードは"positive and feedback"を使います。
これはカウンタがその入力の論理レベルが"high"の間にクロック周期毎に+1増加する動作をし、そして又出力ピンがクロックで遅延された入力ピンの反転状態と等しくなります。
図3はSigma-delta動作で使用するCTRxレジスタのビット配置図です。
PHSxレジスタは入力ピンのレベルがHiの間FRQxレジスタの値が加えられその値をクロック毎に積算します。
大抵、Signa-delta動作ではFRQxレジスタには1がセットされます。
この書式で設定するとカウンタは図2のDフリップフロップの様に動作します。ここで/Q出力はフィードバックピンに相当しQ出力はカウンタの増加を制御します。
カウンターをSigna-delta動作させるために以下の手順でセットアップします。
1. FEQxレジスタに1をセット
2. CTRxを図3のようにセット
3. feedback pinが出力設定となるように相当するビットを1にDIRAをセット
A/D変換の為に以下をPASMで書く
1. CNTを変数timeにコピーして16を加算する
2. intervalをtimeに加算する(WAITCNT time, interval )
3. PHSxを負数にしてaccに記録
4. 2.でセットした時間まで待つ(WAITCNT time, interval )
5. PHSxの値をaccに加算する
intervalのクロック数の間にPHSxの値が増加する。この増加分は入力電圧(オフセットも含む)に比例する。
以下のPASM(Propeller Assembly)が上記のコーディング例です。
説明の為にコメント欄を日本語にしています。
CON INP_PIN = 8 FB_PIN = 9 ADC_INTERVAL = 512 'サンプリング時間=512 X 0.0125nsec DAT org 0 adc_cog mov frqa,#1 'frqaに1をセット movi ctra,#%0_01001_000 'ctraモードをpositive w/feedbackにセット movd ctra,#FB_PIN 'ディストネーションフィールドに出力ピンをセット movs ctra,#INP_PIN 'ソースフィールドに入力ピンをセット mov dira,fb_mask 'feedback pinを出力でマスク mov result_addr,par '@valueをresult_addrに保存 'spinコードで@value(valueアドレス)をparにセット main_loop call #adc 'A/D変換スタート wrlong acc,result_addr '変換結果をHubRAMに保存 jmp #main_loop '次のA/D変換 adc move time,cnt '現在のcntをtimeにコピー add time,#16 '少し先の時間(16クロック)をtimeにセット waitcnt time,interval 'timeまで待機してtimeがsystemcounterと等しくなったらtimeにintervalを加算してtimeに格納する。そのあと次の命令を実行 neg acc,phsa '現在のphsaの負数を取得 waitcnt time,#0 'timeまで待機 add acc,phsa '現在のphsaにacc(A/D変換スタート時のphsaの負数)を加算 adc_ret ret fb_mask long 1 << FB_PIN 'feedback pinをマスク result_addr long 0-0 interval long ADC_INTERVAL acc res 1 'General-purpose accumulator. time res 1 'Time variable use for waitcnt.
セットアップが完了したらmain_loopはadcをくり返しコールしてA/D変換結果を予め設定したHubRam?に書きこむ。cognewによってCogが起動された時、parレジスタはこの位置を示している。
cognew(@adc_cog, @value)
offsetの大きさと結果に対するスケールはintervalで使われる数に比例する。intervalの数量はA/D変換の確度を決定する。8bitsは256,9bitsは512,10bits以上も同様である。
言い換えるとPHSxレジスタは