MAX II CPLD Windows11チュートリアル
MAX II CPLDをWindows11で開発する一連の流れについてです。
小規模なFPGAのようなもので、任意の回路に書き換えることができる半導体です。
古いものですが、枯れて安定しているため、適当な用途にはバッチリです。
現在最新のWindows11上で開発をしてみましょう。
基板設計方法
基本的には3.3Vの単電源で動作しますので、3.3Vの出力が行える電源回路、 そして動作の基準となるクロック(非同期回路としてしか使わないなら必要ないです)、 そして書き込みを行うためのJTAGポートだけ準備すれば最低限動作はします。
JTAGポートは以下の情報のように、2.54mmの2*5ピンボックスヘッダを使用します。
- Intel® FPGA Download Cable User Guide - 2.2. Cable-to-Board Connection
- Intel® FPGA Download Cable II User Guide - 2.3. Intel® FPGA Download Cable II Plug Connection
ボックスヘッダの切り欠きが外側になるような向きで配置します。(切り欠きのほうに書き込み機が接続されます)
MAX II CPLDは単体で動作するので、基本的に電源とクロック、JTAGポートさえ接続されていれば動きます。
JTAG周りの回路はTDI,TMSを10kΩで3.3Vにプルアップ、TCKを1kΩでGNDにプルダウンしましょう。
初期化処理のためにどこかリセットピンを決めてリセット信号も入れておきましょう。
クロック入力はGlobal Clock Networkに接続するため、GCLKピンに接続しておきます。
その他の詳細情報は「MAX II Device Handbook」を参考にしましょう。
USB-Blasterの調達
書き込みを行うのに専用のダウンロードケーブルが必要になります。
純正品は「Altera USB-Blaster(Intel FPGA Download Cable)」または「Altera USB-Blaster II(Intel FPGA Download Cable II)」です。
ほぼ同じものとして、Terasic社の「Terasic USB-Blaster」もあります。
どちらにしても1万円以上は必ずするため、安価に済ませたい場合は、中国製のUSB-Blasterクローンがあります。
1000円前後で購入できますので、とりあえず書き込みが行えればいい場合はこちらでも良いとは思います。
マイコンでUSB-Blasterを作ることもできます。
開発環境の整備
MAX IIの開発を行うには、Intel(旧Altera)より提供されているQuartusというソフトウェアを使用します。
Windows11上で使用するにあたって、正式サポートをしているのは有償版のProEditionのバージョン22.3~です。
無償版ではサポートされていないバージョンしか公開されていないので自己責任で行うこととします。
Quartusのインストールを行うと、書き込みをするためにJTAGServerというプロセスが常駐します。
新しいWindows11上ではドライバーの関係もありますので、複数バージョンのQuartusをインストールする場合は、必ず古いものからインストールします。
最後にインストールしたバージョンに含まれるJTAGServerプロセスが常駐する形になると思います。
タスクマネージャーから確認できます。
また、Quartusはバージョンによってサポートしている開発対象のデバイスが異なります。
今回はMAX IIを使用するため、どのバージョンでも開発は可能なのですが、個人的に初期のCycloneシリーズを在庫していることもあって、古いバージョンからインストールしていきます。
Step1. Quartus II Web Edition v13.0 Service Pack 1
最初にインストールします。
初期のCycloneシリーズを開発するのに必要なためこのバージョンのインストール作業を行います。
MAX IIやMAX 10、最新のCycloneシリーズのみ開発を行うのであれば飛ばして構いません。
「Multiple Download」から「Quartus-web-13.0.1.232-windows.tar」をダウンロードします。
tarを解凍できるソフト(7-Zip, WinRAR, WinZip)や、コマンドラインのtarコマンドで解凍します。
インストール先はデフォルトで「C:\altera\13.0sp1」です。
Cyclone IIからのデバイスサポートがあります。
初回起動時に聞かれますが無償版を使用するので「Run the Quartus II software」を選択します。
Step2. Quartus Prime Lite Edition Design Software Version 20.1.1
2番目にインストールします。
SDRAMコントローラー・ModelSimを同封した最後のバージョンです。
この次のバージョンより、SDRAMコントローラーは同封されなくなり、ModelSimはQuestaに変更となります。
「Multiple Download」から「Quartus-lite-20.1.1.720-windows.tar」をダウンロードします。
tarを解凍できるソフト(7-Zip, WinRAR, WinZip)や、コマンドラインのtarコマンドで解凍します。
インストール先はデフォルトで「C:\intelFPGA_lite\20.1」です。
Cyclone Ⅱ,Ⅲのサポートがありませんが、新しくMAX 10 FPGAの開発に対応しています。
インストールの最後で「Launch USB Blaster Ⅱ driver installation」のチェックを必ず外しておきます。
Windows11環境ではインストールに失敗します。
初回起動時に聞かれますが無償版を使用するので「Run the Quartus Prime software」を選択します。
Step3. Quartus Prime Lite Edition Design Software Version 22.1.1 (Programmer Only)
ここではWindows11上で動くドライバーの関係でプログラマだけインストールします。
「Additional Software」→「Stand-Alone Software」にある「QuartusProgrammerSetup-22.1std.1.917-windows.exe」をダウンロードします。
インストール先はデフォルトで「C:\intelFPGA\22.1std」です。
最後の「Launch USB Blaster Ⅱ driver installation」のチェックはつけたままで大丈夫です。
ドライバーのインストールはそのまま続けます。
無事ドライバーインストール完了です!
色々試した結果、デジタル署名、VBS/HVCI対応のドライバーがVersion 21~でしか提供されていないようで、先程インストールしたVersion 20のドライバーではWindows11で動作しません。
ちなみにですが、Windows11のVBS/HVCI(コア分離・メモリ整合性)によって古いソフトウェアのドライバーが壊滅状態で環境を作るのが大変でした。
例えば、個人的に使用している Adobe Creative Suite 6 Master Collection ですが、VBS/HVCI(コア分離・メモリ整合性)が有効だと、 Audition CS6とEncore CS6が光学ドライブ周りのドライバーの関係でインストール不可能でした。
話を戻しますが、ドライバーの動作のために、最新のVersion 22のプログラマだけを個別にインストールしました。
ドライバーは「C:\intelFPGA\22.1std\qprogrammer\drivers」に置かれ、USB-Blasterに上記パスを指定すればWindows11環境でもドライバーが当たります。
正式にはバージョン22.3~の対応ですが、2023年5月現在、無償版のLite Editionでは最新が22.1のため、Lite Editionの22.3~が公開されることを望みます。
USB-Blasterの接続とドライバーインストール
はじめに、USB-Blasterをコンピュータと接続します。
デバイスマネージャーを確認すると、ドライバーが当たっていない状態となります。
「ドライバーの更新」を押して、ドライバーのインストールに進みます。
Windows11環境では、Version 21~のドライバーでしか動作しませんでしたので、先程インストールしたVersion 22.1.1のプログラマーのドライバーを使用します。
デフォルトのインストール先では「C:\intelFPGA\22.1std\qprogrammer\drivers」にドライバーが置かれていますので、こちらを指定します。
Windows11環境で無事ドライバーのインストールが完了しました。
プロジェクト作成から書き込みまで
一連の流れを試してみましょう。
MAX IIとのJTAG通信確認
JTAGチェーン上にMAX IIが存在するか実際に確認してみましょう。
まず最初に、MAX IIを載せたターゲット基板の電源をONにしておきます。
USB-Blasterは電源を供給する機能は無く、電源電圧に合わせた書き込み動作をするため、別途ターゲット基板の電源を入れておく必要があるためです。
Quartusを起動したら、上部メニューの「Tools」→「Programmer」とクリックし、プログラマーを起動します。
もちろん単体でインストールしたプログラマーであれば、スタートメニューに登録があるのでそちらを起動しても大丈夫ではあります。
プログラマーが起動したら、「No Hardware」という状態になっていると思われます。
隣りにある「Hardware Setup」ボタンを押しましょう。
新しく開く「Hardware Setup」ウィンドウにて、「Currently selected hardware」をUSB-Blasterにすれば良いです。
ここでUSB-Blasterが見えない場合は、ドライバーが上手く入っていないか、古いバージョンのJTAGServerプロセスで動作しているなどがありますので、確認してみてください。
USB-Blasterをうまく認識している状態であれば、プログラマーの「Auto Detect」ボタンを押してみましょう。
MAX IIが認識されるでしょうか?
ここで認識されない場合は、基板上の配線、電源などを確認する必要があります。
動作確認ができたら一度プログラマーを閉じておきましょう。
新規プロジェクトの作成
Quartus上で「File」→「New Project Wizard」とクリックし、プロジェクトウィザードを開きます。
プロジェクトウィザードが開き、Nextをクリックして進めるとプロジェクトの設定画面になります。
ファイル群をどのフォルダに置くか、プロジェクト名、top-level design entityを指定します。
「top-level design entity」とは、これから製作する論理回路のまとまりの上位に付ける名前(モジュール識別子)のことです。
使用できる文字はアルファベット、数字、アンダースコア(_)、ダラー($)に限られ、先頭の文字はアルファベット、またはアンダースコアにする必要があります。
C言語で例えれば最初に呼ばれる「main」関数を指定しているようなもので、どのモジュールを最初に呼ぶかという話になります。
ここで例にするのは、SFPモジュール用の基板ですので、以下のような名称にしました。
プロジェクト名:MAX2_Universal_SFP_Transceiver
top-level design entity:max2_universal_sfp_transceiver_top
プロジェクトにファイルを追加するか?と聞かれますが、あとから追加出来るので、ここでは追加せずに進めてしまいます。
FPGAファミリ、デバイスの設定画面になります。
今回使用するFPGAは「MAX II」ファミリ製品ですから、Familyを「MAX II」にします。
MAX IIのデバイスリストが表示されるので、今回使用するデバイスを選択します。
今回の基板に搭載されているデバイスは「EPM570T100C5」ですので、リストから探し出し、進みます。
EDAツールの設定が聞かれますが、今回はデフォルトのまま進めてしまいます。
内容を確認して進めていくとプロジェクトウィザードが終了します。
Verilog HDLファイルの追加
Quartus上で「File」→「New」とクリックするとファイル作成のウィンドウが現れます。
今回はVerilog HDLでのデザインファイルを追加するため、「Design Files」の「Verilog HDL File」を指定します。
まだ何も記述していませんが、「File」→「Save As」とクリックし、デザインファイルを保存しておきます。
プロジェクトフォルダ内に「rtl」フォルダを作成し、「max2_universal_sfp_transceiver_top.v」としてファイルを保存しました。
Verilog HDLファイルが増えることを想定しているためフォルダに収めましたが、好きに配置して問題ないです。
この時「Add file to current project」にチェックが入っていると、自動的にプロジェクトにデザインファイルが追加されます。
ファイルを作成した後からでもプロジェクトにファイルを追加することができます。
プロジェクトに登録されたファイルの中からtop-level design entityで指定したモジュールが最初に呼ばれる動作をするため、登録していないと論理合成が通りません。
ピンアサインの記述
信号名と実際のピンとの対応が無いと、回路を記述することができません。
例えばFPGA評価ボードなどであれば、ピンアサインが定義されている拡張子が「.qsf」のファイルが提供されていることがあります。
その場合は、Quartus上で「Assignments」→「Import Assignments」とクリックすることにより、ピンアサインをインポート出来ます。
自分で製作した基板など、ピンアサインの定義が無い場合には、ここから作らなくてはなりません。
ピンアサインの定義を作るにはPin Plannerを使用します。
Quartus上で「Assignments」→「Pin Planner」とクリックすることにより、Pin Plannerが表示されます。
Pin Plannerで信号名とピンを定義する
Pin Planner上で信号名とそれに対応するピンをすべて入力していく方法でも良いのですが、 Verilog HDLファイル上で信号名を定義してあるとそれがPin Plannerに反映されます。
反映された信号名にピンを割り当てていけば良いので、入力の手間が軽減されます。
まず最初に前回用意したVerilog HDLファイル上に信号名の定義だけを行い、コンパイル(論理合成)を行って、Pin Plannerに反映させてみましょう。
先程用意した「max2_universal_sfp_transceiver_top.v」に以下の内容を書き込み、保存します。
module max2_universal_sfp_transceiver_top (
/* Master Clock and Reset */
input [1:0] CLK,
input [1:0] RST_N,
/* 5V-TTL GPIO */
inout [1:0] IO,
output [1:0] DIR,
/* Onboard DIP-SW */
input [7:0] DIP_SW1,
input [7:0] DIP_SW2,
/* Green and Red LED */
output [1:0] LED_G,
output [1:0] LED_R,
/* SFP Module */
input SFP_LOSS_SIG,
output SFP_RATE_SEL,
output SFP_TX_DIS_N,
input SFP_TX_FLT,
/* SFP MOD_DEF */
inout [2:0] SFP_MOD_DEF,
/* LVDS I/F IC */
input LVDS_DAT_OUT,
output LVDS_DAT_IN,
output LVDS_DRV_EN,
output LVDS_RCV_EN_N,
/* MCU */
inout MCU_D6,
inout MCU_D7,
inout MCU_D8,
inout MCU_D9,
inout MCU_D10,
/* Trans Flash Card */
inout [3:0] TF_DAT,
inout TF_CMD,
inout TF_CLK,
input TF_CD,
/* 3.3V Extension Box Header */
inout [5:0] GPIO3,
inout [5:0] GPIO4,
/* Debug */
inout [3:0] TP5,
inout [3:0] TP6
);
endmodule
あくまで一例です。
例えば、Terasic社などのFPGA評価ボードの設計リソースなどを見てみると参考になるかと思います。
この内容をVerilog HDLファイルに記載し、保存します。
Quartus上で「Processiong」→「Start Compilation」とクリックすることによって、コンパイル(論理合成)を行うことができます。
ここまで行うと、Pin Planner上に信号名が列挙されると思います。
その信号名に対して回路図を見ながらピンをアサインしていきましょう。
未使用ピンの処理
このセクションは重要な設定事項です。
Quartusのデフォルト設定では、FPGA/CPLDの使用していないピンをGNDに接続してしまいます。
これは意図していない場合は、非常に危険な設定です。
極端な例ですが、使用していないピンの一部が外部でVCCに繋がっていたとします。
未使用ピンをGNDに繋ぐ設定では、VCCに繋がった一部のピンも内部でGNDに接続されてしまい、結果、ショート状態になり大電流が流れ、FPGA/CPLDや周辺回路を破損してしまう原因になるのです。
よって、大抵の場合は未使用ピンをGNDに繋ぐのではなく、入力ピンとして設定しておくと安全です。
Quartus上で「Assignments」→「Device」とクリックし、デバイスのウィンドウを開きます。
「Device and Pin Options」ボタンをクリックし、ピン設定のウィンドウを開きます。
左のカテゴリで「Unused Pins」を指定し、「Reserve all unused pins」を「As input tri-stated」にすることにより、未使用ピンを入力状態に設定することが可能です。
この設定は各種評価ボードを使う際には必ず確認するものと覚えておくとよいでしょう。
Verilog HDL記述
とりあえず何か回路を書いてみましょう。
今回は基板上にDIPスイッチとLEDがありますので、単純に接続する回路をVerilog HDLで記述します。
~上部省略~
);
assign LED_G[1:0] = ~DIP_SW1[1:0];
assign LED_R[1:0] = ~DIP_SW1[3:2];
endmodule
このように記述することによって、LEDの出力信号に対してDIPスイッチの信号をアサインすることができました。
実際に書き込んで動作確認してみましょう。
もちろん、Quartus上で「Processiong」→「Start Compilation」とクリックし、コンパイル(論理合成)を行っておきます。
USB-Blasterでの書き込み動作
Quartus上で「Tools」→「Programmer」とクリックし、プログラマーを起動します。
プロジェクトでVerilog HDLなどをコンパイルした後にプログラマーを開くと以下のような画面になっていると思います。
万が一、プログラムするファイルが指定されていない場合は、「Add File」ボタンをクリックし、プロジェクト以下の「output_files」フォルダを参照します。
フォルダ内にある.pofファイルを追加し、CFM,UFM両方が選択されるようにProgram/Configureにチェックを入れます。
「Start」ボタンを押せる状態になるので、「Start」ボタンを押してコンフィギュレーションします。
動作確認
DIPスイッチを動かしてみるとLEDが点灯することがわかります。
ここまで動けば大成功です。
なぜVerilog HDL記述中に反転(NOT)が?
先程のVerilog HDL記述では、DIP_SWの記述の前に「~」での反転(NOT)が入っています。
それはなぜか?
~上部省略~
);
assign LED_G[1:0] = DIP_SW1[1:0];
assign LED_R[1:0] = DIP_SW1[3:2];
endmodule
このように反転は必要ないのでは?と直感的に思うかもしれません。
しかし、電子回路ではスイッチの入力はプルアップ抵抗にてプルアップすることが多いのです。
スイッチが閉じていない場合は、プルアップ抵抗にて電圧が引き上げられ、スイッチが閉じた状態ではGNDに下がるというような回路です。
つまり、スイッチ入力はFPGA/CPLD側で見ると、スイッチが閉じている間は入力が無い状態、動作が反転しているような挙動として見えるわけです。
そのためDIP_SWの前に反転を入れていました。
試しに、反転を外した状態でコンパイル、書き込みをしてみましょう。
スイッチを閉じていない状態では常に光っていることが確認できると思います。
固定値でLEDを光らせる
スイッチ入力ではなく特定の値でLEDを駆動してみましょう。
~上部省略~
);
assign LED_G[1:0] = 2'b11;
assign LED_R[1:0] = {2{1'b1}};
endmodule
1行目では、2bit幅の値を宣言、それぞれ1として記述しています。
2行目では連結演算子{}を使って1bit幅の値が2つ並んでいるものとして記述しています。
飛ばし飛ばしのスイッチをアサインする
並んだ位置のスイッチをアサインしていましたが、1個飛ばしでスイッチをLEDにアサインしてみましょう。
~上部省略~
);
assign LED_G[1:0] = ~{DIP_SW1[2], DIP_SW1[0]};
assign LED_R[1:0] = {~DIP_SW1[6], ~DIP_SW1[4]};
endmodule
それぞれ違う位置のスイッチ入力を連結演算子{}にて2bit幅の信号とし、LEDに入力しています。
スイッチ入力の時点で負論理になっているので、NOTで反転しています。
最後に全体を反転させるか、スイッチ入力をそれぞれ反転させるかで記述方法が違います。
論理演算
ANDやORなどの論理演算をしてみましょう。
~上部省略~
);
assign LED_G[1:0] = ~{DIP_SW1[3] & DIP_SW1[2], DIP_SW1[1] | DIP_SW1[0]};
assign LED_R[1:0] = {~DIP_SW1[7] ~^ ~DIP_SW1[6], ~DIP_SW1[5] ^ ~DIP_SW1[4]};
endmodule
DIP_SW1[0]とDIP_SW1[1]はOR(|)を取っているが論理反転しているためLED_G[0]はAND(&)として動作。
DIP_SW1[2]とDIP_SW1[3]はAND(&)を取っているが論理反転しているためLED_G[1]はOR(|)として動作。
DIP_SW1[4]とDIP_SW1[5]はXOR(^)を取っているためLED_G[0]はXOR(^)として動作。
DIP_SW1[6]とDIP_SW1[7]はXNOR(~^)を取っているためLED_G[0]はXNOR(~^)として動作。
Verilog HDLではNANDとNORの表記法は無く、ANDやORの全体をカッコで囲って反転させる必要があります。
NAND例「~(A & B)」、NOR例「~(A | B)」
比較演算
2つの値を比較してみましょう。
~上部省略~
);
assign LED_G[1:0] = {2{~DIP_SW1[3:0] == 4'b1101}};
assign LED_R[1:0] = {2{DIP_SW1[7:4] == DIP_SW1[3:0]}};
endmodule
DIP_SW1[0]からDIP_SW1[3]までの4bitの値が「1011」となれば、assign LED_G[1:0]が点灯。
DIP_SW1[0]からDIP_SW1[3]までの4bitと、DIP_SW1[4]からDIP_SW1[7]までの4bitが一致すればLED_R[1:0]が点灯。
もちろん比較演算子も使用可能で、スイッチの値を2進数として数値比較することができます。
ここでは、出力にLEDが2つあり、2bit幅の信号が必要ですが、比較演算の結果はTrue/Falseの1bitとなるので、連結演算子{2{xxxxx}}で2bit幅の信号として同じ内容を出力しています。
そのためLEDは同時に2つ点灯します。
現在の回路を見てみる
Quartus上で「Tools」→「Netlist Viewers」→「RTL Viewer」とクリックします。
今現在の回路がどのようになっているのか見ることもできます。