FPGAボードを使って作成したオリジナル16ビットCPUコアMoscoviumはまだ強化開発の途上です。
ですが、FPGAボードの真骨頂はユーザ論理、なのです。既存のマイコンチップと変わらない「マイコン」なんて作っても、あまり嬉しいことは無くて、単に苦労しただけ無駄、みたいなところがあります。数100円で買えるマイコンチップと同じことをするのに、数1,000円のFPGAボードを使うなんて、もったいないでしょ?
既成マイコンには搭載されていない論理機能を自分で設計してFPGAボードに焼き込んでこそ、のFPGAボードな訳です。そこで今回のテーマは、FPGAボードにユーザ論理を書き込んで8chロジックアナライザを制作してみます。
実は、ソフトウェアで実現した1chロジックアナライザライクなシステム、Logiscopeは、本HP初期のころに開発して何度もデバッグに使用してきました。
ですが、ソフトウェアで実現しているだけに、取り込み可能なチャンネル数は1chに限定されているし、動作周波数72MHzのSTM32をもってしても、3〜4[μs]幅のパルスを何とかギリギリ取り込み可能なレベルでした(詳細は以下リンクより)。
「#4-2 Logiscopeの拡張」: STM32のサンプリングレート
例えば、デューティ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ロジックアナライザアクセラレータを設計して、所謂ロジアナを制作して行きます。
以下に目標仕様をまとめます。
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バッファには、TD IDEのIP Generatorによる、FIFOマクロを使います。ビット幅や制御信号などの設定が合わせてあれば、FIFOサイズは、ユーザが任意に設定可能であるとします。ユーザが作成するFIFOマクロのサイズに依存して、取り込み可能なデータ量が変化することとなります。
上図は、経過時間用FIFO(左側)と、データ用FIFO(右側)の推奨設定画面サンプルです。
本ページでは2,048ワード(上図でWrite Depth欄)に設定しました。必要なRAM容量としては、合計で(8+16[ビット])×2,048ワード=6Kバイトとなります。もっとRAMを潤沢に使って、より多くのデータを取り込みたい場合は、ワード数を増加させてFIFOマクロを作成してください。
データ用と経過時間用FIFOの内、いずれか先にフルとなった時点で取り込みが停止するので、2つのFIFO段数は同じ数値に設定しておかないと意味を成しません。
以下図にブロック図を示して、動作を説明します。
各ブロックの動作説明:
以下表に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レジスタ仕様:
完成したデザインデータは、以下のリンク先に保管してあります。
プロジェクトファイルMCOC_LA.alと、ディレクトリMCOC115下の全ファイルをダウンロードして、TD IDEでプロジェクトファイルMCOC_LA.alを開き、コンパイル(論理合成・配置配線)してFPGAボード(Sipeed Lichee Tang Primer)へ書き込んでください。
コンパイル(論理合成・配置配線)結果:
乗算コプロセッサは何かと使い勝手が良いので、有効にしておきました。除算コプロセッサは、論理規模が大きく、ロジアナには用途が無かったので外してあります。`defineの設定で変更可能なので、カスタマイズしてお使いください。
Moscovium側で動作させるプログラムを作ります。基本的には、Arduino+C言語で作ったlogiscope.inoのサブセットにすべきなのですが、オリジナルのMoscoviumにはC言語のサポートが無いので、アセンブラでプログラムしてください。
はっきり言ってしまうと、logiscope.inoがサポートする全コマンドを実装するのはしんどいのです(1^^;)。
そこで今この場では、目標仕様で宣言した通り8chロジックアナライザ機能を実行する【vcdc】コマンド以外のコマンドは実装しません。そのうち気が向いたら、実装すれば良いし、気が向かなければ、無くてもそんなに困らないハズ……。
完成したプログラムをリンクしておきます(以下)。
完成プログラム:logiscope.asm
アセンブルするには、Moscovium用のアセンブラが必要です。アセンブルしてMIFファイルを作成したら、命令フェッチ用ROMマクロを作成した時に指定したパスとファイル名でMIFファイルを保管してください。
PC側でFPGAボード上のMoscoviumコア+ロジアナアクセラレータを制御するソフトウェアは、Logiscopeを使います。Logiscopeの【trg】コマンドによる表示は、例えば以下図のような感じです。
100kHz程度のサンプリングレートで1信号のLogiscopeであれば、何とかデバッグには使える表示だとは思いますが、さすがに、ロジアナアクセラレータを使い、24MHz 8chの信号波形を取り込みできるとなると、上図の様な波形表示では心もとないです。
そこで、LogiscopeがMoscoviumから受信したデータは、VCDファイルに変換します。変換したVCDファイルをGTKWaveで読み込んで波形表示させることとします(例えば以下の様)。
GTKWaveは、Windows用のiverilogシミュレータをインストールした時に一緒にインストールされた、Verilogシミュレーション波形の表示ツールです。インストールの詳細はこちらをご参照ください。
VCD(Value Change Dump)ファイルはテキスト形式のデータなので、iverilogが出力したVCDファイルをテキストエディタなどで開いて、中身を眺めてみるだけで、大体のフォーマットは理解可能です。以下リンクから検索すると、もう少し詳しく解説したページも見つかるでしょう。
VCD(Value Change Dump)ファイルについて検索する(別ウインドウが開きます)
Moscoviumから受信したデータからVCDファイルに変換するスクリプトをOlive+で作って、logiscope.olvに追加しました。【vcdc】コマンド対応版のLogiscope(Olive+のスクリプト)を以下にリンクしておきます。
Logiscopeスクリプト:logiscope.olv
使い方については、「#2-3 ロジアナもどきを作る」の説明をご覧ください。
すべての準備が整いました。本ページここまでの作業で、以下の準備が済んでいます。
FTDI(下図)の様なシリアル⇔USB変換モジュールを使って、FPGAボードとPCを接続します。
FPGAボード | 接続 | FTDI |
R7(uart_rxd) | ← | TXD |
T7(uart_txd) | → | RXD |
GND | ⇔ | GND |
× | VCC(ジャンパ:3.3V側) |
以下、実験中の様子です。
※FPGAボード(EG4S20BG256チップ)は3.3V I/Oですので、UNOの5V信号を直接接続するのはご法度です。ここでは、レベルシフタ(L/S)を使用して、3.3VにレベルダウンしてからFPGAボードに繋いで実験しています。
Logiscopeを起動して、FTDIの通信ポートを選択したら、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で開くと、波形を表示することが出来ます。
まずは小手調べに、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
【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
続いて、UNOからシリアルプログラミングモードで、328duino(第一形態) @25MHzに接続した時の波形を取り込んでみました(下図)。
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までは刃こぼれ無しで取り込めるはずなので、機会が有ればお試しください。
速度のみならず、長時間の取り込みにも対応可能なことを確かめるため、もっと長い通信信号を取り込んでみました。以下図は、円形配置RGB LEDモジュール(WS2812B)の制御波形です。
「#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で正解でした。
RGBデータが8ビット×3値×24ピクセル分の、計576ビットも送信しているのですが、それでもわずかに720μsにしかなっていませんでした。……ゴメンナサイ。長いと言っても、1ms未満でした……。取り込み可能な時間はFIFO容量で決まりますので、各自お試しください。
仕様上は、最大65s程度までの長時間取り込みが可能となっています。
以下にVCDファイルをリンクしておきます。
WS2812Bの通信波形: logiscope_ws2812b.vcd
念のため書き添えておきますが、GTKWaveで表示しているとは言えど、シミュレーションした波形ではなく、今回自作したロジックアナライザを使って実際に通信中の波形を取り込んだものです。
24MHzサンプリングの結構高速な波形データなのだけど、VCDの波形表示ツールGTKWaveが使えることで、少し長めに取り込んでおいて、後から目的の時間にズームイン/アウトしながら確認できるので、すごく便利(1^ー^)v。
ソフトウェアでは、STM32 @72MHzでも取り込み不可能だった高速信号波形ですが、たったの24MHz動作ロジックアナライザアクセラレータ(ハードウェア)を使うと、余裕で取り込みできました。もっとサンプリング周波数を上げたい場合は:
等々、ハードウェアなら、まだまだ限界には程遠く、余裕で動作しているレベルです。動作速度に関しては、ソフトウェアを小指でねじ伏せてしまった感がありましょう?
ソフトウェアも大切なのですが、こと処理速度を追求する場面でハードウェアを設計できると、全く違う世界が見られますよ〜🔭。