公開日:2021/05/29
title.png

16th Season


#16-4 24MHz 8chロジックアナライザの制作

 FPGAボードを使って作成したオリジナル16ビットCPUコアMoscoviumはまだ強化開発の途上です。

 ですが、FPGAボードの真骨頂はユーザ論理、なのです。既存のマイコンチップと変わらない「マイコン」なんて作っても、あまり嬉しいことは無くて、単に苦労しただけ無駄、みたいなところがあります。数100円で買えるマイコンチップと同じことをするのに、数1,000円のFPGAボードを使うなんて、もったいないでしょ?

ar94_atmega328p.jpga151_fpga.jpg

 既成マイコンには搭載されていない論理機能を自分で設計してFPGAボードに焼き込んでこそ、のFPGAボードな訳です。そこで今回のテーマは、FPGAボードにユーザ論理を書き込んで8chロジックアナライザを制作してみます。

ソフトウェア(Logiscope)の限界

 実は、ソフトウェアで実現した1chロジックアナライザライクなシステム、Logiscopeは、本HP初期のころに開発して何度もデバッグに使用してきました。
 ですが、ソフトウェアで実現しているだけに、キャプチャ可能なチャンネル数は1chに限定されているし、動作周波数72MHzのSTM32をもってしても、3〜4[μs]幅のパルスを何とかギリギリキャプチャ可能なレベルでした(詳細は以下リンクより)。

  「#4-2 Logiscopeの拡張」: STM32のサンプリングレート

ar42_pwm4.png

 例えば、デューティ50%のクロックの様な波形をキャプチャしようとするなら、HIGH幅が3〜4[μs]でLOW幅も3〜4[μs]が必要となるので、クロック周期としては、6〜8[μs]となります。周波数換算では、1/(6〜8[μs])≒125〜167[kHz]と言う所です。

 I2C標準モード(100kHz)のSCL波形は何とかキャプチャできますが、高速モード(400kHz)のSCL波形はキャプチャできず、刃こぼれします。まして、SPI等8〜10[MHz]クロックSCKのキャプチャなんて到底無理と言う話です。
 円形配置RGB LEDを制御した時、シリアルRGBチップWS2812Bとの通信信号線の動作波形をデバッグしたかったのだけど、HIGH幅、LOW幅共、nsオーダの高速なPWMだったため、Logiscopeではデバッグ不可能でした。

 STM32 @72MHzのCPUパワーをもってしてもこの程度(↑)なのは、ソフトウェアの限界です。

ハードウェアでロジックアナライザを作る

 極端な話、フルハードウェアでロジックアナライザを作って見ると、どうなるでしょうか?単に、高速なクロックで端子状態をキャプチャして、RAM等のバッファにデータを蓄積するところまでは簡単に作れるかもしれません。
 しかし、キャプチャを開始するトリガ条件の設定や、キャプチャしたデータをPC等のホストに送信する手続きなどをフルハードウェアで設計するのはかなり困難を伴います。

 実例は「#15-2 論理回路を設計する」で解説してあります。

 まして、今回作るのは8chロジックアナライザです。特に、ユーザインターフェイス(U/I)周りの処理をハードウェアだけで設計するのは至難の業となります。

 そこで登場するのがマイコンなのです。

 ほらね、FPGAボード上にマイコンを実装することが必要となりました。
 FPGAボード(Lichee Tang Primer)では、RISC-Vと言う選択肢もありだったけど、筆者は自分でマイコンを作るという選択肢を選びました。そして今、手元にはオリジナル16ビットCPUコアMoscoviumを搭載したMoscoviumマイコンがあります。MCOC115のI/Oユニットとして、8chロジックアナライザアクセラレータを設計して、所謂ロジアナを制作して行きます。

8chロジックアナライザの目標仕様

 以下に目標仕様をまとめます。

ロジックアナライザアクセラレータの設計

 MCOC115IP0408をベースに、ロジックアナライザアクセラレータLOGA8CHを追加して、MCOC115LA0408として開発します。
 キャプチャ対象の8chデータ入力ポートは、PORT8I8Oの入力ポートport_inp[7:0]と共有します。入力信号を分岐して、同時にPORT8I8OとLOGA8CHに接続するだけですので、両I/Oユニットの共存が可能です。

キャプチャ動作

 入力ポートport_inp[7:0]の中で、<tmsk_hex>で1を設定した端子データ(port_inp[7:0]&<tmsk_hex>)を監視し、値が<tcnd_hex>に一致したところからキャプチャを開始します。

  トリガ条件: port_inp[7:0]&<tmsk_hex>==<tcnd_hex>&<tmsk_hex>

 キャプチャ中、入力ポートport_inp[7:0]の中で、<cmsk_hex>で1を設定した端子データ(port_inp[7:0]&<cmsk_hex>)の変化を監視し、変化を検出すると、前回変化からの経過時間(24MHzクロックカウント、16ビット)と、その時の端子データ値(8ビット、port_inp[7:0]&<cmsk_hex>)をFIFO(RAM)に書き込みます。

 経過時間は、16ビットカウンタ(captck[15:0])で24MHzクロックをカウントするので、65,536/24MHz≒2.7msでオーバフロウします。経過時間カウンタcaptck[15:0]がオーバフロウした場合も、一旦、その時点の端子データ(8ビット)と経過時間captck[15:0]=16'hffff値(16ビット)をFIFOに書き込みます。
 従って、キャプチャ対象端子データ(port_inp[7:0]&<cmsk_hex>)が変化しなかった場合でも、約2.7ms毎にFIFOのデータ領域を消費して行きます。
 トリガ条件成立からの経過時間が<capture_ms>[ms]に到達するか、FIFOがフルになった時点でキャプチャを終了します。キャプチャ対象端子に変化が有れば、その都度FIFOのデータ領域を消費してデータを記憶して行くので、FIFO容量が、最大キャプチャ可能時間を決定するパラメータとなります。

FIFOマクロ

 FIFOバッファには、TD IDEのIP Generatorによる、FIFOマクロを使います。ビット幅や制御信号などの設定が合わせてあれば、FIFOサイズは、ユーザが任意に設定可能であるとします。ユーザが作成するFIFOマクロのサイズに依存して、キャプチャ可能なデータ量が変化することとなります。

a164_fifotck.pnga164_fifodat.png

 上図は、経過時間用FIFO(左側)と、データ用FIFO(右側)の推奨設定画面サンプルです。

 本ページでは2,048ワード(上図でWrite Depth欄)に設定しました。必要なRAM容量としては、合計で(8+16[ビット])×2,048ワード=6Kバイトとなります。もっとRAMを潤沢に使って、より多くのデータをキャプチャしたい場合は、ワード数を増加させてFIFOマクロを作成してください。
 データ用と経過時間用FIFOの内、いずれか先にフルとなった時点でキャプチャが停止するので、2つのFIFO段数は同じ数値に設定しておかないと意味を成しません。

ブロック図

 以下図にブロック図を示して、動作を説明します。

a164_loga8ch.png

  各ブロックの動作説明:

I/Oレジスタ仕様

 以下表にI/Oレジスタ一覧を示します。

Addr Name R/W Bit:15〜0 Memo
0xf070 logactl RW LA
EF
DA
VL
TA
VL
FR
ST
AB
T
ST
A
logic analyzer control
0xf072 logacmsk RW CMSK[7:0] channel mask
0xf074 logatmsk RW TMSK[7:0] trigger mask
0xf076 logatcnd RW TCND[7:0] trigger condition
0xf078 logamaxc RW MAXC[15:0] maximum capture time [ms]
0xf07a logactck R CTCK[15:0] captured time [count]
0xf07c logacdat R CDAT[7:0] captured data
0xf07e reserved

  I/Oレジスタ仕様:

設計データ

 完成したデザインデータは、以下のリンク先に保管してあります。

btn_moscovium.png

 プロジェクトファイルMCOC_LA.alと、ディレクトリMCOC115下の全ファイルをダウンロードして、TD IDEでプロジェクトファイルMCOC_LA.alを開き、コンパイル(論理合成・配置配線)してFPGAボード(Sipeed Lichee Tang Primer)へ書き込んでください。


  コンパイル(論理合成・配置配線)結果:

 乗算コプロセッサは何かと使い勝手が良いので、有効にしておきました。除算コプロセッサは、論理規模が大きく、ロジアナには用途が無かったので外してあります。`defineの設定で変更可能なので、カスタマイズしてお使いください。

MCOC115(Moscovium)側ソフトウェア

 Moscovium側で動作させるプログラムを作ります。基本的には、Arduino+C言語で作ったlogiscope.inoのサブセットにすべきなのですが、オリジナルのMoscoviumにはC言語のサポートが無いので、アセンブラでプログラムする必要があります。
 はっきり言ってしまうと、logiscope.inoがサポートする全コマンドを実装するのはしんどいのです(1^^;)。

 そこで今この場では、目標仕様で宣言した通り8chロジックアナライザ機能を実行する【vcdc】コマンド以外のコマンドは実装しません。そのうち気が向いたら、実装すれば良いし、気が向かなければ、無くてもそんなに困らないハズ……。

 完成したプログラムをリンクしておきます(以下)。

  完成プログラム:logiscope.asm

 アセンブルするには、Moscovium用のアセンブラが必要です。アセンブルしてMIFファイルを作成したら、インストラクション用ROMマクロを作成した時に指定したパスとファイル名でMIFファイルを保管して下さい。

PC側ソフトウェア

 PC側でFPGAボード上のMoscoviumコア+ロジアナアクセラレータを制御するソフトウェアは、Logiscopeを使います。Logiscopeの【trg】コマンドによる表示は、例えば以下図のような感じです。

ar23_am2302.png

 100kHz程度のサンプリングレートで1信号のLogiscopeであれば、何とかデバッグには使える表示だとは思いますが、さすがに、ロジアナアクセラレータを使い、24MHz 8chの信号波形をキャプチャできるとなると、上図の様な波形表示では心もとないです。

 そこで、LogiscopeがMoscoviumから受信したデータは、VCDファイルに変換します。変換したVCDファイルをGTKWaveで読み込んで波形表示させることとします(例えば以下の様)。

a164_serprg.png

 GTKWaveは、Windows用のiverilogシミュレータをインストールした時に一緒にインストールされた、Verilogシミュレーション波形の表示ツールです。インストールの詳細はこちらをご参照ください。
 VCD(Value Change Dump)ファイルはテキスト形式のデータなので、iverilogが出力したVCDファイルをテキストエディタなどで開いて、中身を眺めてみるだけで、大体のフォーマットは理解可能です。以下リンクから検索すると、もう少し詳しく解説したページも見つかるでしょう。

  VCD(Value Change Dump)ファイルについて検索する(別ウインドウが開きます)

 Moscoviumから受信したデータからVCDファイルに変換するスクリプトをOlive+で作って、logiscope.olvに追加しました。【vcdc】コマンド対応版のLosgiscope(Olive+のスクリプト)を以下にリンクしておきます。

  Logiscopeスクリプト:logiscope.olv

 使い方については、「#2-3 ロジアナもどきを作る」の説明をご覧ください。

「これがハードウェアの実力」ってところを見せてあげるわ

 すべての準備が整いました。本ページここまでの作業で、以下の準備が済んでいます。

 FTDI(下図)の様なシリアル⇔USB変換モジュールを使って、FPGAボードとPCを接続します。

ar41_ftdi.jpg

FPGAボード 接続 FTDI
R7(uart_rxd) TXD
T7(uart_txd) RXD
GND GND
  × VCC(ジャンパ:3.3V側)

 以下、実験中の様子です。

a164_expr.jpg

※FPGAボード(EG4S20BG256チップ)は3.3V I/Oですので、UNOの5V信号を直接接続するのはご法度です。ここでは、レベルシフタ(L/S)を使用して、3.3VにレベルダウンしてからFPGAボードに繋いで実験しています。


 Logiscopeを起動して、FTDIのCOMポートを選択したら、Logiscopeのコマンドウインドウで以下の様に操作します。

  実験サンプル:【 】内はLogiscopeからの送信データ
  【vcdc,03,02,00,1】

※↑データチャンネルdch0とdch1を取り込む(<cmsk_hex>=03)。トリガはdch1(<tmsk_hex>=02)で、dch1=1→0の変化(<tcnd_hex>=0)で取り込みを開始する。最大取り込み時間は1ms(<capture_ms>=1)。コマンドの説明はこちら

 すると、logiscope.olvと同じディレクトリに、logiscope.vcdと言うファイルが完成します。もし、logiscope.vcdファイルが存在していた場合、上書きされますので、注意して下さい。このlogiscope.vcdファイルをGTKWaveで開くと、波形を表示することが出来ます。

I2C(400kHz)の通信波形

 まずは小手調べに、400kHzの通信波形を取り込んでみました。UNOに接続するのは12ビットDA変換器MCP4725です。UNOとの接続方法や評価用のプログラムについては、「#8-3 シュミットトリガ入力バッファを設計する」でご確認ください。

  実験サンプル:【 】内はLogiscopeからの送信データ
  【vcdc,03,03,01,1】
    …… 受信待機中に、UNOから以下コマンドを実行する。

  実験サンプル:【 】内はUNOシリアルモニタからの送信データ
  【daco,291】 …… 291=0x0123
  OK: DAC=291(355[mV]) port=0

a164_mcp4725.png

 【vcdc】コマンドパラメータの意味は:

 上図は、「#8-3 シュミットトリガ入力バッファを設計する」で使ったシステムにおいて、UNOと12ビットDA変換器MCP4725をI2C(400kHz)で接続した時の通信波形を、MCOC115LA0408を使った手作りロジックアナライザでキャプチャした波形です。
 dch0がSCL、dch1がSDAです。解る方には解ると思いますが、最初のSTARTコンディションから、スレーブアドレス、データ(8ビット×2回)の送信が有って、最後のSTOPコンディションまで、綺麗に取り込めています。
 サンプリング周波数は24MHzですので、400kHzのSCLクロックなんて楽勝です。

 上のキャプチャ画像だけではイメージ湧かないかもしれませんので、取り込んだVCDファイルを以下にリンクしておきます。GTKWaveを使って閲覧できますので、お手元でご確認ください。

  MCP4725の通信波形: logiscope_mcp4725.vcd

SPI(4MHz)通信波形

 続いて、UNOからシリアルプログラムモードで、328duino(第一形態) @25MHzに接続した時の波形を取り込んでみました(下図)。

a164_serprg.png

 SPI通信ですので、今度の信号線は少し速くなって、SCK(dch0)が4MHzです。残り2本はMISO(dch1)、MOSI(dch2)という対応です。25MHzにクロックアップした328duinoでも、SPIクロック周波数4MHzを超えると、通信できませんでした。
 前節のI2C(400kHz)波形と見比べてみると、横軸のフルスケールが約100μsだったI2Cに対して、今度のSPI(4MHz)は約10μsなので、一桁高速なのです。それでも、24MHzサンプリングロジックアナライザの手に掛かると、まだまだ余裕があります。

 上の波形には、8ビットのSPI通信が4回ほど見えています。この通信は、ATmega328のシリアルプログラミングモードでエクステンドヒューズ(ヒューズE)を読み出すコマンドを実行しているところです。
 まず、SCK(dch0)とMOSI(dch2)に注目すると、ヒューズE読み出しコマンドである、0x50,0x08,0x00がMSBファーストで送信されていることが解ります。最後の4バイト目はATmega328からの応答なので、今度はSCK(dch0)とMISO(dch1)に注目すると、データ0xfeが返ってきました。328duinoのヒューズEに書き込んでおいた値と一致しています。

 以下にVCDファイルをリンクしておきます。

  シリアルプログラムの通信波形: logiscope_serprg.vcd

 他にもSDカードI/Fとか、8〜10[MHz]のSPI通信するモジュールもあったのですが、こっちは、取り込んだところで期待値が解らなかったので試していません。理論上、12MHzまでは刃こぼれ無しで取り込めるはずなので、機会が有ればお試しください。

WS2812Bとの通信波形

 速度のみならず、長時間のキャプチャにも対応可能なことを確かめるため、もっと長い通信信号をキャプチャしてみました。以下図は、円形配置RGB LEDモジュール(WS2812B)の制御波形です。

a164_ws2812b.png

 「#11-2 円形配置RGB LED(WS2812B)を使う」で作成したプログラム(test_ws2812b.ino)を使って、WS2812Bと通信した時の波形です。通信波形の仕様についてはこちらに解説があります。
 上の図で、HIGH幅の広い波形が"1"を送信している部分で、HIGH幅の狭い波形が"0"を送信しています。0〜23まで24個あるピクセルの内、最後の第23ピクセルに0x00(G),0xff(R),0x00(B)を送信した一部分のクローズアップです(RとBデータの所しか見えていない)。
 全体を取り込んでおいて、上図の様に必要な部分にクローズアップして観測できるのは、GTKWaveのお陰です。

 なお、狭い方のHIGH幅は実測で375nsしかありません。UNOでの狙い値は6クロック@16MHzでしたので、ピタリ375nsで正解でした。

a112_expr.jpg

 RGBデータが8ビット×3値×24ピクセル分の、計576ビットも送信しているのですが、それでもわずかに720μsにしかなっていませんでした。……ゴメンナサイ。長いと言っても、1ms未満でした……。取り込み可能な時間はFIFO容量で決まりますので、各自お試しください。
 仕様上は、最大65s程度までの長時間取り込みが可能となっています。

 以下にVCDファイルをリンクしておきます。

  WS2812Bの通信波形: logiscope_ws2812b.vcd

まとめ

 念のため書き添えておきますが、GTKWaveで表示しているとは言えど、シミュレーションした波形ではなく、今回自作したロジックアナライザを使って実際に通信中の波形を取り込んだものです。

 24MHzサンプリングの結構高速な波形データなのだけど、VCDの波形表示ツールGTKWaveが使えることで、少し長めにキャプチャしておいて、後から目的の時間にズームイン/アウトしながら確認できるので、すごく便利(1^ー^)v。

 ソフトウェアでは、STM32 @72MHzでもキャプチャ不可能だった高速信号波形ですが、たったの24MHz動作ロジックアナライザアクセラレータ(ハードウェア)を使うと、余裕でキャプチャできました。もっとサンプリング周波数を上げたい場合は:

 等々、ハードウェアなら、まだまだ限界には程遠く、余裕で動作しているレベルです。動作速度に関しては、ソフトウェアを小指でねじ伏せてしまった感がありましょう?


 ソフトウェアも大切なのですが、こと処理速度を追求する場面でハードウェアを設計できると、全く違う世界が見られますよ〜🔭


btn_arduino.png

btn_prev.png btn_next.png

home