公開日:2022/01/29
title.png

19th Season


#19-6 FPGAボードのAD変換器を使う(2)

 FPGAボード(Sipeed Lichee Tang Primer)のAD変換器マクロを、オリジナル16ビットCPUコアMoscoviumマイコンに搭載するテーマの続きです。
 前回の記事で、必要な技術検討は終了していますので、詳細設計を進めて行きたいと思います。

AD変換器ユニット目標仕様

 以下図にAD変換器ユニットADC124のブロック図を示します。

a196_adc124.png

 AFEは仕様上最速の16MHzで駆動するので、変換時間1μsが可能ですが、afeifブロック内ステートマシンのオーバヘッドにより、最小変換時間は約1.25μs/チャンネルとなります。

I/Oレジスタ仕様

 次に、I/Oレジスタ一覧を示し、解説を続けます。

Addr Name R/W Bit:15〜0 Memo
0xf0e0 adcctl RW AR
DY
AD
CE
CE
NB
CSEL[3:0] adc control
0xf0e2 adcint RW CENF[3:0] CENE[3:0] interrupt control
0xf0e4 adcperi RW PERI[15:0] conversion period
0xf0e6 reserved
0xf0e8 adcdat0 R DAT0[11:0] conversion data 0
0xf0ea adcdat1 R DAT1[11:0] conversion data 1
0xf0ec adcdat2 R DAT2[11:0] conversion data 2
0xf0ee adcdat3 R DAT3[11:0] conversion data 3

 BUSC出力のセレクト信号はbcs_adcu_nです。上表の範囲でアサートされるので、ADC124ユニット内では、アドレスbadr[3:0]を復号してレジスタを特定しています。このI/Oユニットはバイトアクセス禁止です。必ずワードアクセスしてください。

AD変換器の起動

 リセット解除後、AD変換器マクロはパワーダウン状態、PLLは発振停止🚫状態です。AD変換を実行する前に、AD変換器(とPLL)を起動しておく必要があります。
 adcctlレジスタのADCEビットをセットすると、AD変換器が起動、PLLが発振開始します。AD変換器の動作準備が整うまでの時間規定が無いので、どのくらいの時間を待てば良いかは不明なのですが、PLLは発振開始してから所望の周波数(16MHz)にロックすると、extlockという信号をアサートするので、それまで待つ必要があります。

※PLLのロックにはある程度時間がかかるので、その間にAD変換器も変換可能な状態になっていると仮定します。本来は、Anlogic社がデータシートなどで起動時間を規定しておくべきです(見当たりませんでした)。

 PLLがロックすると、adcctlレジスタのARDYビットに1が立ちます。以下にADC124ユニットの起動コード例を示します。

  // start up adc124
  ldwi r7,adcctl
  ldbiu r0,adc_adce
  stw [r7],r0
  ldw r0,[r7]
  andi r0,adc_adce
  beq error_no_adc  // ERROR:ADC124が搭載されていない。
  // wait ARDY flag
  ldw r0,[r7]
  andi r0,adc_ardy
  beq pcnt-6


 上の処理終了後、AD変換を実行することが出来ます。なお、ADCEビットは一度セットすると、クリアすることはできません。

AD変換モード

 前節までに解説したADC124ユニット仕様の中で、AD変換に関係する物をまとめておきます。

 AD変換器マクロに16MHzクロックを供給して、変換時間は16サイクルですので、仕様上は1μsで変換が終了します。今回のADC124ユニットでは、変換終了後のデータ受け渡しやステートマシンの処理などによってオーバヘッドがあるため、最小変換時間は約1.25μsです。
 adcctlレジスタのCSEL[3:0]フィールドで1を立てたチャンネルが、連続変換され、これを「変換セット」と呼びます。
 adcperiレジスタにμs単位で指定した時間毎に、変換セット(AD変換)が連続実行される「連続変換モード」と、1回変換したら停止して待機状態となる「シングル変換モード」があります。

シングル変換モード

 シングル変換モード(adcperi=0)では、変換セットを1回実行すると、adcctlレジスタのCENBビットが自動クリアされて、待機状態に戻ります。

 以下図は、CENB=1、CSEL[3:0]=0x1、adcperi=0として、チャンネル0だけをシングル変換する様子です。

a196_adc_sngl1.png

 横方向は時間の経過を示しています。「Channel」欄に「#0」と記した箱は、チャンネル0の変換状態を示しており、横幅は1チャンネル分の変換時間約1.25μsです。
 1変換セットの実行が済むと、CENBビットが自動クリアされて待機状態に戻ります。


 下図は、CENB=1、CSEL[3:0]=0xd、adcperi=0として、チャンネル0,2,3をシングル変換する様子です。

a196_adc_sngl3.png

 CSEL[3:0]フィールドで指定したチャンネル0,2,3は、CENB=1となった時に連続して変換が実行されます。adcperi=0なので、1変換セットの実行が済むと、CENBビットが自動クリアされて待機状態に戻ります。

連続変換モード

 変換間隔を指定するadcperiレジスタ>0の設定にすると、連続変換モードとなります。

 下図は、CENB=1、CSEL[3:0]=0x9、adcperi>>1として、チャンネル0,3を連続変換する様子です。

a196_adc_cont2.png

 1回の変換セットで、チャンネル0と3が連続変換されます。変換セットの実行が終了してもCENBビットは自動クリアされず、CENB=1を保ちます。時間を計測するカウンタがadcperi[μs]に達すると、再び変換セットが実行されて、チャンネル0,3が連続変換されます。
 CENBビットがユーザのI/Oレジスタ書き込みによってクリアされるまで続きます。


 下図は、CENB=1、CSEL[3:0]=0xf、adcperi=1として、チャンネル0〜3を連続変換する様子です。

a196_adc_cont4.png

 4チャンネル分の変換時間は約1.25μs×4チャンネル≒5μsですが、adcperi=1μsと、それより短い時間を設定されたため、変換セットの変換が終了すると、直ちに次の変換セットが実行されます。結果、上図の様にチャンネル0〜3の変換が連続して実行されます。

完成したデザイン

 これまで、Moscoviumマイコンは1系統の24MHzクロックだけを使って設計してきたので、タイミング制約はとてもシンプルでした(以下)。

  MCOC.sdc
  #Created Clock
  create_clock -name clk -period 40 -waveform {0 20} [get_ports {clk}]


 上の通り、24MHzにマージンを取って、25MHz(周期40ns)のクロックをclk入力ポートに設定して、以上終了でした。

 今回、PLLを使って16MHzクロックを生成し、AD変換器のアナログフロントエンドと、その制御ブロックafeifに16MHzクロックを供給します。また、16MHz⇔24MHz間は非同期設計していますので、フォルスパス設定が必要となります(↓)。

  MCOC_adc.sdc
  #Created Clock
  create_clock -name clk -period 40 -waveform {0 20} [get_ports {clk}]
  create_clock -name clk16m -period 60 -waveform {0 30} [get_nets {adc/clk16m}]

  #Set False Path
  set_false_path -from [get_clocks {clk}] -to [get_clocks {clk16m}]
  set_false_path -from [get_clocks {clk16m}] -to [get_clocks {clk}]


 16MHzクロックclk16mにもマージンを持たせて、約16.67MHz(60ns)を設定してあります。
 16MHz⇔24MHz間をフォルスパス設定したので、誤って同期的に信号をやり取りしている箇所があっても、タイミングエラーは一切レポートされなくなります。ツールのサポートが期待できない、と言う事なので、非同期設計は慎重に!


 以下リンクより、AD変換器を搭載したMoscoviumマイコンMCOC115AD0408のデザインをダウンロードできます。FPGAボード(Sipeed Lichee Tang Primer)への書き込み手順はこちらを参照してください。

btn_moscovium.png


 以下に、コンパイル(論理合成・配置配線)結果をまとめておきます。

実験かな?

 AD変換器を使った具体的なアプリケーションを作る前に、まずはちゃんと機能する物だか、AD変換器マクロの動作確認を兼ねて実験してみたいと思います。
 TD IDEのデータシートでは、変換精度関係が全く触れられておらず、不明ですので、手持ちの12ビットDA変換器モジュール(MCP4725)(下図)を使い、簡易評価してみます。

ar79_dac12.jpg

 AD変換器の変換精度評価(方法及び指標)については、「#8-2 逐次比較型AD変換器を作る」で解説済みです。
 12ビットAD変換器に対して、同じ12ビットDA変換器なので、DNLやINL等、階段状の変換結果が必要な指標は評価できません。本ページでは、絶対精度、オフセット誤差、フルスケール誤差に関してのみ評価することとします。


 Moscoviumで動作させる評価用プログラムを以下にリンクしておきます。

  評価用プログラム:test_adc.asm

※アセンブルに必要なインクルードファイルは、こちらからダウンロードしてください。

 Moscoviumのシリアルモニタから、以下のコマンドを受け付けるようになっています。


 MCOC115AD0408を書き込んだFPGAボードと、MCP4725を以下表に従って接続してください。

FPGAボード 接続 MCP4725
3.3V VCC
GND GND
N11(adc_ch0) OUT
P2(stws_scl) SCL
R2(stws_sda) SDA


 以下図に実験中の様子を示します。

a196_expr.jpg


  実験サンプル:【 】内はシリアルモニタからの送信データ
  【daco,0】
  OK: daco=0x0000 adc=0x0000 [lsb]

  【daco,2048】
  OK: daco=0x0800 adc=0x07e9 [lsb]

  【daco,4095】
  OK: daco=0x0fff adc=0x0fdc [lsb]

 だいぶ差分が出ていますが(誤差が大きそう……)、なんとなく、期待値に近いデータが返っているようです。一気に全データを取得してみましょう。

  【eval】
  0,0
  1,0
  2,0
  3,0
    :
    : (中略)
    :
  4092,4058
  4093,4062
  4094,4065
  4095,4062
  OK: eval finished

 Excelでデータを取り込んで、グラフ化してみました(下図)。

a196_adceval.png

 横軸に入力アナログ電圧(0〜3.3[V])、縦軸に読み取ったデジタル値(0〜4,095[LSB]、上側)と絶対精度AE[LSB](下側)を取ったグラフです。
 AD変換器の評価指標ではありませんが、一次回帰直線の相関係数R2=1と、直線でした。AD変換器(入力アナログ量に応じたデジタル値を出力する機器)としては機能しているみたいです。

 評価できた指標は以下の通りでした。

  絶対精度: AE=9〜−40[LSB]
  オフセット誤差: OE=11.6LSB
  フルスケール誤差: FE=20.2LSB

 酷いですね、絶対精度AE=−40LSB(MAX)とは……。期待はしていませんでしたが、AE=−40LSBは約5ビット(≒log2 (40))に相当するので、解像度12ビットの内、5ビットは誤差に取られて、正味7〜8ビットAD変換器程度の実力しかありません。「12ビットAD変換器」は、おこがましいです。
 そもそも、逐次比較型で12ビットAD変換器なんて、相当厳しいのですよ……。見た目のスペック「解像度12ビット、変換時間1μs」はカッコ良いですが、全く実力が伴っていませんでした。


 FPGAボード搭載の、AD変換器特性規定も無い様なAD変換器なんて、初めから期待はしていませんでした。まあ、性能としてはこんな所なのでしょう。ただ、約1.25μsで変換終了する高速AD変換器なので、変換精度が必要なアプリケーションでないなら、そこそこ使えるでしょう(1^^;)。


btn_arduino.png

btn_prev.png btn_next.png

home