Posts Tagged with "FPGA"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.

Parameterについて (3)

posted by sakurai on November 24, 2023 #702

IPインテグレータによる変更

モジュールをダブルクリックすると図702.1の画面が現れ、パラメータが2進数で表示されます。これはbscがverilog中に32'b0と書いたからであり、10進で書けば10進で表示されます。

残念ながらbsvではデフォルト値を設定することはできません。モジュールの階層ではなく、その上のモジュールをインスタンスする際にはbsvでパラメータ指定が可能ですが、今回はbsvでモジュールを作成しIPインテグレータで回路を作成するので、bsvソースレベルでは不可能ということになります。

ただし前稿にもあるようにverilogではデフォルトの値が設定できるので、必要であればbscでコンパイルしたverilogを修正します。

図%%.1
図702.1 パラメータ変更画面

実機動作

このパラメータテストモジュールはパラメータで与えられた数だけパルスを出力する回路です。IPインテグレータでパラメータを変更しただけで実際にパルス数が変わるかを確認します。具体的なbsvコードの中心は以下の行です。

    repeat (unpack(pack(count))) seq
       outPulse <= True;
       outPulse <= False;
    endseq 

パラメータcountで指定された数だけパルスのON-OFFを行います。


左矢前のブログ 次のブログ右矢

Parameterについて (2)

posted by sakurai on November 23, 2023 #701

verilogにおけるparameter

次にbscを用いてverilogにコンパイルします。

$ bsc -verilog TestParam.bsv
Verilog file created: mkTestParam.v

コンパイルするとmkTestParam.vというverilogファイルが生成されます。パラメータ部分を見ると、

    :
    module mkTestParam(CLK,
                   RST_N,
                   button_flag,
                   lrclk);
     parameter [31 : 0] count = 32'b0;
    :

のように、モジュール定義のすぐ後にparameterとしてcountが定義されています。そのほかにもverilogコード内でcountは複数使用されていますが、レジスタではないので書き込みのコードは存在せず、定数として参照されています。例えば、

    assign n__h31509 = count - 32'd1 ;
    ;
    assign MUX_jj_repeat_count$write_1__VAL_1 =
             (n__h31509[15:0] == jj_repeat_count) ? 16'd0 : x__h31537 ;

のようにcount-1とjj_repeat_countが一致するかのテストを行っている回路が生成されます。repeat_countは文字通りrepeat回数の実行時の変数と思われ、終了条件としてそれがcount-1(定数)と一致するかのテストを行っているようです。

IPインテグレータによる変更

これだけであれば、結局bsvなりverilogのパラメータ部分を修正するので、ソース修正となることからdefineでもあまり変わりません。

完全に動的にはいかずとも、ソースファイルを編集することなくVivaoのIPインテグレータのブロックデザイン画面上で変更する方法があります。

まずVivadoでmkTestParam.vをソースとして読み込み、回路をインスタンシエートします。

図%%.1
図701.1 mkTestParamモジュールを配置

左矢前のブログ 次のブログ右矢

Parameterについて

posted by sakurai on November 22, 2023 #700

Parameterについて

Verilogにおいてparameterという機能があります。これは動的に定数を変更することができ便利な機能ですが、ソースを修正することからあまり使用していませんでした。

ところがIPインテグレータを使用すれば、ソースを修正することがなく再合成だけで仕様を変更することができます。今回テスト回路を作成し、BSVからFPGAまでの繋がりを確認します。

BSVにおいてのparameter

BSVリファレンスガイド5.3モジュールにパラメータの文法が書かれています。これを用いたテスト回路を作成します。

図%%.1
図700.1 BSVリファレンスガイド5.3モジュール

文法を見るとわかるようにデフォルト値を設定する機能はありません。'='記号の使用等でそれが可能であればよかったのですが。

以下に具体的なBSVコードを示します。ボタンを押すとパラメータで指定された数だけパルスを出力するFSMです。ポートリストというかメソッドリストの直前にカッコ書きで記述するようです。

import StmtFSM::*;
   
interface FSM_ifc;
   method Action button(Bool flag);
   method Bool lrclk();
endinterface

(* synthesize,always_ready,always_enabled *)
module mkTestParam #(
   parameter Int#(32) count
) (FSM_ifc);
  
   Reg#(Bool) outPulse <- mkReg(False),
              buttonf <- mkReg(True);
   //  Mainloop
   Stmt main = seq
      while(True) seq
         outPulse <= False;
         await(!buttonf);
         await(buttonf);
            repeat (unpack(pack(count))) seq
               outPulse <= True;
               outPulse <= False;
            endseq 
      endseq
   endseq;
   mkAutoFSM(main);

   method Bool lrclk();
      return outPulse;
   endmethod
   method Action button(Bool flag);
      buttonf <= flag;
   endmethod

endmodule: mkTestParam

パルスの出力回数を表すcountをパラメータ化しました。


左矢前のブログ 次のブログ右矢

Cmod A7の利用 (6)

posted by sakurai on November 21, 2023 #699

DRPからアクセス可能な各種ステータスレジスタ及びコントロールレジスタを示します。

図%%.1
図699.1 XADC構造

次にDRPアクセスタイミングを示します。

図%%.2
図699.2 XADCのDRPアクセスタイミング

この仕様に従ってADCデータを読み出すFSMをBSVでプログラミングします。BSVではStmtFSMライブラリを用いることによりシーケンシャルな処理を実行するFSMが容易にかけるため、FSMの設計に何ら痛痒を感じません。ただし結果としてはEOC(End of conversion)をDEN(DRP Enable)に接続し、Continuousモードに設定するだけで連続的にADC値が出力されるため、シーケンサを組む必要はありませんでした。

完成したADCソフトブロックを以下に示します。ADCの出力に接続しているのは、ADC値からy座標に変換する回路(#705で設計予定)です。

図%%.2
図699.3 ADCソフトブロック

左矢前のブログ 次のブログ右矢

Cmod A7の利用 (5)

posted by sakurai on November 17, 2023 #698

Artix 7シリーズFPGAのADCを利用するには、ただ読み込めば良い基板上のスイッチと異なりいろいろと制約があるようです。ADCのユーザーズガイド(UG480)に書かれていますが、DRP(Dynamic Reconfigure Register)経由で読み出すとのことです。

その日本語版 (UG480) のXADCの概要によれば、

XADC には、オンチップ電源電圧とダイ温度の測定をサポートするいくつかのオンチップ センサーも含まれています。ADC 変換データはステータス レジスタと呼ばれる専用レジスタに格納されます。これらのレジスタは、ダイナミック リコンフィギュレーション ポート (DRP) と呼ばれる 16 ビットの同期読み取り/書き込みポートを使用して、FPGA インターコネクト経由でアクセスできます。

とのことであり、以下にブロック図を示します。右下にDRPブロックがあります。

図%%.1
図698.1 XADC回路図

VivadoにおいてはXADC Wizardによりパラメータを設定してからインスタンスします。

  • Vivadoのブロックデザインエディタにおいて、右クリックからAdd IPをクリック、XADC Wizを開く。
  • Basicタブにおいて、Interface OptionをDRPとする。
  • Timing ModeはContinuous Mode
  • startup Channel SelectionはSingle Channel
  • DRP Timing Optionは無設定(DCLKは100MHzがデフォルト)
  • AXI4Sは無設定
  • Control/Status Portsは無設定
  • ADC Setupタブにおいて、全てを無設定、None、空欄とする。
  • Alarmsタブにおいても同様。
  • Single ChannelタブはChannel Enableにチェック

以上を設定のうえOKをクリックすると図のようなモジュールが生成されます。WizardではXADCが内部にインスタンスされたラッパーモジュールを生成します。

図%%.2
図698.2 生成されたXADCモジュール

左矢前のブログ 次のブログ右矢

Cmod A7の利用 (4)

posted by sakurai on November 15, 2023 #697

回路を修正し、基板版数をV5としました。修正箇所は

  • VRを追加
  • Micro USBの書き込みポートが干渉するため、逆向きにした。
  • ドリルホールが小さかったのを広げた

これにより基板サイズを多少大きくしました。回路図中に文字の重なりがあるのはEagleのバグのようです。

図%%.1
図697.1 CmodA7toPMODV5ボード回路図

図%%.1
図697.2 CmodA7toPMODV5ボードガーバー図

再度JLCPCBに依頼しましたが、費用は以下のとおり変わりません。

表697.1 JLCPCB費用まとめ
内容 費用[USD]
基板製造費10枚 5.00
配送費(OCS) 1.98
合計 6.98


左矢前のブログ 次のブログ右矢

Pongの開発 (7)

posted by sakurai on November 14, 2023 #696

可変抵抗器の作成

標準ではLTSpiceに可変抵抗器は存在しないようです。そこで可変抵抗器のモデルを作成してLTSpiceに組み込んでみました。参考にさせて頂いたのはこのページ(魚拓)です。

図%%.1
図696.1 可変抵抗器等価回路

図696.1のZo1-Zo2間に0-10kΩの可変抵抗を発生させる仕様であり、インピーダンスがゼロとならないよう、電源内部に1Ω抵抗を入れています。以下はこの部品のSpice記述です。

.SUBCKT ZX In1 In2 Z Zo1 Zo2
Eout Zo1 1 POLY(2) (In1,In2) (Z,0) 0 0 0 0 1
Fcopy 0 Z Vsense 1
Rin In1 In2 1G
Vsense 1 Zo2 0
.ENDS

これを用いたLTSpiceにおける部品の作成法を示します。

  • 上記記述をZX.subとしてC:\Users\ユーザ名\AppData\Local\LTspice\lib\subに配置
  • OpenによりZX.subを開くが拡張子が制約されており対象に出ないため、全ファイルを対象として開く
  • 1行目を右クリックしてCreate Symbolを行う

これを組み込んだ回路のシミュレーションを実施したので以下に回路と波形を示します。

図%%.2
図696.2 可変抵抗器使用回路

制御電圧$V_\text{1}$(グリーン)は実際には存在しない制御電圧で0~1.0Vです。Zo1とZo2の間がこれにより0~10KΩとなります。$V_\text{in}$(ブルー)は0.3~3.3Vとなり、CmodA7入力電圧$V_\text{1}$(マゼンタ)は0.3~3.2Vとなっています。ADCの入力電圧$V_\text{out1}$(ブルーグリーン)は0.07~0.94Vとなっています。ただし変化が急かもしれないので、その場合にはR5を例えば10KΩと大きくすることで調整します。

図%%.3
図696.3 可変抵抗器使用回路

R5を10KΩとした場合、ADCの入力電圧$V_\text{out1}$(ブルーグリーン)は0.2~0.94Vと下側が上がったものの、変化が穏やかになりました。

秋月の10KΩの可変抵抗器Bを見ると可変角は最大300°だそうで、使用感を考えると可変抵抗を最大まで使うよりも角度の一部を使ったほうが使いやすそうです。そのためADC入力電圧の下側を上げて47KΩとし、回転角の60~90°くらいを使用したほうが良いかもしれません。


左矢前のブログ 次のブログ右矢

Pongの開発 (6)

posted by sakurai on November 13, 2023 #695

エミッタフォロワ

インピーダンス変換のためにNPN Trでエミッタフォロワ回路を構成しました。

図%%.2
図695.1 エミッタフォロワ回路と波形

ところが、TrがOnしても電圧降下が約0.8Vもあり、エミッタ電圧$V_\text{Tr}$(マゼンタ)は約2.5V Max程度となり、さらにADCの入力電圧$V_\text{out1}$(グリーン)は約0.75V Maxとなっています。

改善はされましたが1V近くまでは上昇しませんでした。もっともパドルの制御なのでどうでもよいことかもしれません。


左矢前のブログ 次のブログ右矢

Pongの開発 (5)

posted by sakurai on November 10, 2023 #694

パドルコントロール

さて、Pongの実装で欲しくなるのがパドルコントロールのためのツマミです。一般には可変抵抗器で実装しているようです。幸いCmodA7にはアナログ入力があるので、可変抵抗器を接続すればよさそうです。

FPGAボード内のアナログ入力は以下のようになっています。外部の0~3.3Vの電圧を抵抗で分圧し、FPGAのADC入力は0~1Vの入力としています。入力インピーダンスが高いとは言えないので、外部回路の出力インピーダンスが高い場合問題になります。

図%%.1
図694.1 CmodA7 ADC入力回路

可変抵抗器は出力インピーダンスが変化するので、設計が案外面倒です。最大と最小のみの2点だけを考えれば良いのかもしれませんが、ここではアナログ回路シミュレータであるLTSpiceを使用してみます。

まず、可変抵抗器のシミュレーションをする前に、出力インピーダンスが高い場合にどうなるかを見てみます。出力インピーダンスが3.3Kとした場合の回路とシミュレーション波形です。浮遊容量を少し付加しています。

図%%.2
図694.2 出力インピーダンス3.3Kと波形

サイン波形を入れていますが、DC特性を見る目的です。

波形から明らかなように、基準電圧$V_\text{in}$(ブルー)は3.3Vまで上昇しているにも関わらず、出力インピーダンスが後段の入力インピーダンスと同程度であるため、CmodA7ボードの入力電圧$V_\text{1}$(レッド)は期待の3.3Vまで上昇せず1.6V Maxとなり、分圧したADCの入力電圧$V_\text{out1}$(グリーン)は0.5V Maxと半分しか上がりません。


左矢前のブログ 次のブログ右矢

Pongの開発 (4)

posted by sakurai on November 9, 2023 #693

疑似乱数生成器

ChatGPTにLFSRのアルゴリズムを持つ疑似乱数生成器を記述してもらいました。以下の完成したモジュールはそれを手直ししたものです。

interface Randomizer_ifc;
  method ActionValue#(Bit#(1)) random_01();
endinterface

//(* synthesize *) モジュールをインライン化するためコメントアウト
module mkRandomizer(Randomizer_ifc);
    Reg#(Bit#(16)) lfsr <- mkReg(16'hACE1); // 適当な非ゼロの初期値

  method ActionValue#(Bit#(1)) random_01();
       Bit#(1) newBit = lfsr[15] ^ lfsr[13] ^ lfsr[12] ^ lfsr[10];
       lfsr <= {lfsr[14:0], newBit};
       return lfsr[15];
  endmethod

endmodule

ActionValueメソッドの呼び出し方

作成した疑似乱数生成器の呼び出しが少々難しかったのでまとめておきます。BSVにおいてはモジュールインタフェース内に記述されるメソッドの型は

  • Value Method
  • ActionValue Method
  • Action Method

の3種類があります。それぞれ入力、入出力、出力ポートに対応しますが、ActionValueの呼び出し方に少々困難がありました。単純にメソッドを変数に入れることができないためです。

特にFSMを構成するseqブロック内で、あるレジスタwにValueメソッドの戻り値を代入するだけなら、

seq
   :
   w <= random_01();
   :
endseq

等とすれば良いのですが、この場合のrandom関数は内部状態を持ち、それが呼び出しにより更新されるという副作用を持つため、ActionValueメソッドとして呼び出します。この呼び出し法が少々難しく、"<-"を用いてインスタンスした上で、かつ単純にseqの中で呼ぶことはできず、actionブロックを構成してその中でのみ有効な値となります。

実例を挙げると、

import Randomizer::*;
Randomizer_ifc randomizer <- mkRandomizer;
   :
    seq
        action
   :
           Bit#(1) w <- randomizer.random_01();
   :
        endaction
    endseq

のように、actionブロックの中で"<-"を用いて関数を呼び出します。特にactionブロックを構成することになかなか気づきませんでした。

追記:
この場合の変数wはaction - endactionのスコープ内でしか有効でないことが後日判明したので、それを回避する方法を追記します。action - endactionのスコープ内でコピー変数にコピーするだけです。

    Reg#(Bit#(1)) ww <- mkRegU; // wをactionスコープの外で使用するコピー変数
   :
    seq
        action
   :
           let w <- randomizer.random_01();  // Bit#(1)宣言でなくてletでも良い
           ww <= w;
   :
        endaction
    endseq

なお、関数がマルチサイクルの場合はこれでうまく行かない場合もあり、その場合はruleの中に入れます。


左矢前のブログ 次のブログ右矢


ページ: