FPGA をもっと活用するために IP コアを使ってみよう (3)

みなさんこんにちは。この「FPGA をもっと活用するために IP コアを使ってみよう」のシリーズでは、FPGA を使って実用的なアプリケーションを実装するために必要不可欠な IP コアの使い方を紹介していきます。

第3回の今回は、FPGA 内部のロジックに供給するクロック周波数を指定するための IP コアを紹介します。

FPGA ボードに搭載されているクロックより高い周波数でロジックを駆動したい、ちょっと回路が大きくなってしまったから周波数を低くしたい、接続するデバイスにあわせた周波数が必要、などと、実際に FPGA アプリケーションを開発する際に必須の IP です。

クロック周波数を変更する必要とは?

4ビットカウンタでわかる FPGA のための論理回路入門(2)で説明されていますが、FPGA で設計している多くの回路はクロック同期回路です。これは、定期的に 0→1→0→... と変化する信号 (クロック信号) の変化のタイミングに合わせて動作する回路です。

クロック同期回路ではクロック信号の変化を速くする、つまりクロック周波数を高くすることで回路を高速化できます。逆に、クロック周波数を低くすることで回路を正しく動作させることができるでしょう。

また、FPGA に接続するデバイスによっては適切なクロック周波数で回路を駆動することが求められる場合があります。たとえば USB や Ethernet などのインターフェースはそれぞれの基準となるクロック周波数に合わせる必要がありますし、ディスプレイ出力などを考えると解像度とリフレッシュレートに合った周波数で回路を駆動する必要があります。

多くの場合、クロック信号はボード上に備えつけられた (FPGAの外にある) クロックを生成する素子で生成されますが、その周波数は固定されています。そのため、自分の都合で周波数を変更しようと思うと FPGA の中でどうにかする必要があります。ここで活躍するのが周波数を変更するための IP コアです。

FPGA の中でクロック周波数を変える

Xilinx、Intel、Lattice などの主要なベンダの FPGA の中には、入力されたクロック信号の M/D 倍 (M と D は整数) の周波数や位相をずらした信号を生成できるモジュールが組み込まれています。これらのモジュールを直接利用することもできるのですが、複雑なパラメタを設定しなければなりません。そのため、簡単に利用できるように用意された IP コアを利用することがほとんどです。

この記事では、Xilinx の Artix7 が搭載された Digilent の Arty を対象に、クロック周波数を変更する IP コアの使い方を紹介します。

使ってみよう

前置きが長くなりましたが、IP コアを使って FPGA の回路を所望の周波数で駆動する手順をみていきましょう。なお、今回の最終的な成果物はこちらにアップロードしてあります。

例題: UART + VIO

例題として、シリアル通信で Hello, FPGA (2)で解説されているシリアル通信で文字を送出する回路に、この連載の前回紹介した VIO を加えたものを使います。

ここでは、送出したい文字を入力ポートで与えるようになっている部分、

    input logic [7:0] DATA_IN;
    input logic       WE;

の代わりに、

    (* KEEP *) logic [7:0] DATA_IN;
    (* KEEP *) logic       WE;

    vio_0 vio_0_i (.clk(CLK),
           .probe_in0(1'b0),
           .probe_out0(WE),
           .probe_out1(DATA_IN)
           );

として、VIO で送出したい文字を与えられるように変更しています。変更したソースコードは、こちらです。

まずは使ってみる

この回路の動作を確認するために Arty 用のプロジェクトを作成して合成し、Hardware Manager で VIO 操作用の hw_vio_1 ペインを開いたところが次の図です。操作しやすいように WE の UI をボタンに変更しています。

たとえば、DATA_IN に、57(W の文字コード) をセットして WE のボタンをクリックすると、ボーレートを 115200 にセットしたシリアルターミナルに W が表示されます。

クロック変更 IP を生成

では、クロックを変更するための IP コアを生成して、デザインに組み込んでみましょう。まずは、Vivado の Flow Navigator にある IP Catalog をクリックします。

IP Catalog の検索フィールドに clocking と入力すると、Clocking Wizard というアイテムが表示されます。これが、所望の周波数を得るための IP コアを生成するためのエントリポイントです。ダブルクリックして設定ウィザードを開きます。以降は Clocking Wizard での設定です。

Clocking Options

IP 内部で使用するクロック生成用のモジュール (Primitive) を選択し、入力クロックをセットします。多くの場合、Primitive はデフォルトの MMCM のままで問題ありません。入力クロックは、Arty ボードが供給する 100MHz に設定します。

Output Clocks

生成したいクロックを設定します。一つの IP コアで、7つのクロック信号を生成できます。今回は一つだけ利用します。ここでは、Requested の欄に200と入力して 200MHz のクロックを作ることにしましょう。

位相やデューティ比率 (1と0の時間比率) を変更できますが、そのままにしておきます。

Summary

生成する IP コアの設定のまとめを確認します。Mult Counter と Divider がそれぞれ10.0000 と1、clk_out1 に対する Divider が 5.000 であるため、clk_out1 が 100MHz * 10 / 1 / 5 = 200MHz に設定されていることを確認できます。

一通り設定が終わったら OK をクリックしてウィザードを終了します。その後に表示される Generate Output Product ダイアログは Generate か Skip をクリックして閉じれば、100MHz から 200MHz を得る IP コアの生成が完了です。

IP をデザインに組み込む

デザインに Clocking Wizard で生成した IP コアを組み込みましょう。Sources ペインで IP Sources を選択、IP → clk_wiz_0 → Instantiation Template とツリーを辿ると、デザインに組み込むためのテンプレートファイル clk_wiz_0.veo にアクセスできます。

テンプレートにある、

  clk_wiz_0 instance_name
   (
    // Clock out ports
    .clk_out1(clk_out1),     // output clk_out1
    // Status and control signals
    .reset(reset), // input reset
    .locked(locked),       // output locked
    // Clock in ports
    .clk_in1(clk_in1));      // input clk_in1

を参考に、serial_send.sv に、

  logic CLK_i; // 生成したクロック信号を取り出す信号を定義
  logic locked;  // クロック周波数が安定したかどうかのフラグ

  clk_wiz_0 clk_wiz_0_i // clk_wiz_0_iという名前でインスタンス生成
   (
    .clk_out1(CLK_i),  // 生成したクロックを取り出す
    .reset(RST),
    .locked(locked),     // クロック周波数が安定したかどうかのフラグ
    .clk_in1(CLK));      // 元のクロックを供給

のようにインスタンス生成文を記述します。

これで、ボードから提供されたクロック信号 CLK (100MHz) をベースにして生成された 200MHz のクロック信号 CLK_i を得ることができます。なお、locked は、生成されるクロック信号の周波数が安定したことを示すフラグです。

あとは、元のデザインで CLK を使用していた箇所を CLK_i に変更することで、ロジックを 200MHz で駆動できるようになります。変更したソースコードの全容は、こちらをご覧ください。

合成して動作を確認してみよう

HDL コードの修正が終わったら合成、配置配線してビットストリームを作ります。

ビットストリームの生成が終わったら、いつもと同じように Hardware Manager を開いて bit ファイルと ltx ファイルをセットします。前回と同じようにターミナルを開いて、115200でシリアルポートを開いてみます。

先程と同様に VIO の UI (hw_vio_0) で、DATA_IN に 57 を入力し WE を1にすると、! が表示されました (環境によって文字が表示されなかったり、別の文字が表示されるかもしれません)。これは UART の送信レート (115200 baud) を生成している基準クロックを 100MHz から 200MHz に変更したことが原因です。

ここで、ターミナルのボーレートの設定を、115200 の倍の 230400 に設定して動かしてみましょう。今度は、想定通り W が表示されました。これで、たしかにロジックが 200MHz で動作していることを確認できました。

設定する値に注意

クロック生成用の IP では、与えられた周波数からうまく M/D 倍して所望の信号を作るのですが、すべての出力ポートに対して適切な M と D を見つけることができない場合があります。そのため、たとえば、200MHz と 108MHz (フル HD のピクセルクロック) を一つのインスタンスで生成しようとしてもうまく設定できません。このような場合には2つのインスタンスを生成するのが良いでしょう。

ちなみに、108MHz だけが必要な場合には、100MHz を 54/50 することで生成できます。

タイミング制約違反に注意

Clocking Wizard では、内部モジュールが生成できる周波数の範囲で好きな周波数に設定できます。ただし、さまざまな周波数に設定できるからといって回路がその周波数で正しく動作するわけではありません

クロック同期回路ではクロックに合わせて回路内の信号が変化するわけですが、逆に言うとクロックに合わせて回路内の信号の変化が終わらなければなりません。クロック周波数を高くしすぎると、回路内の信号の変化が間に合わないことがおこりえます。

たとえば、400MHz に設定して同じコードを合成すると、一部の回路で信号伝達が間に合わず、正しく動作しない可能性のあるビットストリームが生成されてしまいます。

まとめ

FPGA に実装するクロック同期回路を駆動する肝である、クロック信号の周波数を変更できる IP コアを紹介しました。

実際に FPGA アプリケーションを開発していると、高速化あるいは安定化のために動作周波数をあげさげしたい、あるいは、接続するデバイスにあわせた周波数が必要といったケースに遭遇します。そんなときには、Clocking Wizard を使って好きな周波数のクロック信号を生成する IP コアを利用してみてください。

小ネタ: VIO をコマンドラインで操作する

VIO を仕込んだ回路は、Vivado の Hardware Manager でポチポチと操作できます。ただ時には、GUI を立ち上げるのが面倒だったり、回線が細くて GUI での操作がままならないこともありますよね。そんなときには、コマンドラインから Tcl インタプリタや Tclスクリプト を使って操作することもできます。

以下のコマンドで、今回のプロジェクトを Tcl スクリプトを使って合成して、操作してみることができます。

% wget -O c1897581fb8be83245f9b33b5c53dc9a-b8d1f38f8d2b6c3019d019d6d219e1bfd07e3b7f.zip \
  https://codeload.github.com/gist/c1897581fb8be83245f9b33b5c53dc9a/zip/b8d1f38f8d2b6c3019d019d6d219e1bfd07e3b7f
% unzip c1897581fb8be83245f9b33b5c53dc9a-b8d1f38f8d2b6c3019d019d6d219e1bfd07e3b7f.zip
% cd c1897581fb8be83245f9b33b5c53dc9a-b8d1f38f8d2b6c3019d019d6d219e1bfd07e3b7f
% vivado -mode batch -source ./create_prj.tcl
% vivado -mode batch -source ./program.tcl
% vivado -mode batch -source ./write_data_in.tcl

実際に VIO を操作しているのは write_data_in.tcl で、このスクリプトの11行目にある

set_property OUTPUT_VALUE 57 [get_hw_probes DATA_IN -of_objects [get_hw_vios -of_objects [get_hw_devices xc7a35t_0] -filter {CELL_NAME=~"vio_0_i"}]]

の定数57を変更すると、UART 経由で出力する文字列を変更できます。

わさらぼ・みよしたけふみ

タイトルとURLをコピーしました