Posts Tagged with "FPGA"

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

Pongの開発 (14)

posted by sakurai on December 8, 2023 #712

QSPIプログラミング

FPGAプログラミングにはVivadoやPCやUSBケーブル等が必要ですが、電源を投入してアプリケーションをすぐに動作させるためにはCmodA7ボード上のQSPI Flashに書き込む必要があります。基本的には過去記事:Artyで実施したのと同じ手順ですが、異なる点だけを示します。

  • Binファイルの作成: 過去記事どおりに実施します。
  • Binファイルの焼きこみ: 選択するFlashの型格に注意します。以下の図のとおり、mx25I3273f-spi-x1_x2_x4を選択します。間違えて異なる型格を指定すると、Vivadoがエラーを出力し正しい型各を教えてくれます。

図%%.1
図712.1 Flash選択画面

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

Pongの開発 (13)

posted by sakurai on December 7, 2023 #711

パドル動作

完成したADCとパドルVRの連携を以下の動画に示します。パドルの描画アルゴリズムは

  • 新しいADCの値を取得
  • ADCの値を要素8の移動平均化(フラつき防止のため)
  • 閾値4と移動値(ADC値-現在値)を比較し、閾値を超えていたら移動(フラつき防止のため)
  • 移動値を座標制限内にクリッピング
  • 移動の際には現在のパドル像を消去(ゴミ残り防止のため)
  • 前回値と同じであれば書き換えをしない(チラつき防止のため)

図%%.1
図711.1 パドル動作

ボール動作

ボールがパドルと衝突する判定は、ボール座標のVRAMデータを読み出して行います。右パドルのVRAMデータは3であるため、移動のたびにボール座標を読み出し3であれば衝突と判断します。

パドルのy座標範囲は0~25であり、これを①0~5,②6~12、③13~19、④20~25の4領域に分割します。①に衝突した場合は-45°の角度で反射し、②は約-18.4°の角度で反射します。これをxとyの増分であるdx, dyに変換すれば、-45度の場合はdx=1, dy=-1であり、-18.4度の場合はdx=3, dy=-1です。

図%%.2
図711.2 ボール衝突動作

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

Pongの開発 (12)

posted by sakurai on December 6, 2023 #710

実験によるフィードバック

VRを実際にADCに接続してJTAG経由で測定したところ、VRと付属回路の電圧値は0.158~0.711Vとなりました。LTSpiceの値と異なったのは手持ちの適当な抵抗を付けたからかもしれません。

また、パラメータ化したa, bはデフォルト値のa=105, b=90で特に違和感はありませんでした。特に可変範囲は90°としました。これは全回転角が300°でリニアの場合ですが実際にはそうではなく、使用角度bは45°くらいとなりました。

ADCの出力をちょうどy座標の動作範囲にクリップしていましたが、実験の結果、パドルが端にくっつかない問題がありました。そのためADCの出力を、動作範囲よりも5%ほど大きめにして座標計算でもクリップすることにします。

さらにパドル消去アルゴリズムを変更したため、パドルの大きさも多少変えました。従って、再度設計計算を行います。一度方式としては確定しているため、数値を少々変更するだけです。変化点をマーカで表示します。ピンク前記事との変化点であり、ブルーは最終結果としてソースコードに入れる値です。

  • VRの全角度は300°
  • VRの有効角はパラメータ化し、開始角a[°] (デフォルト値a=105)、範囲b[°] (デフォルト値b=90)
  • VRの全角度の際のADC入力電圧は測定結果より、0.16~0.71[V]

図%%.1
図710.1 レベルダイア

再設計計算

これらより、ADC入力電圧は開始角$a$の値を$V_\text{a}$、終了角$a+b$の値を$V_\text{a+b}$として、 $\require{color} \definecolor{pink}{rgb}{1.0,0.8,1.0} \definecolor{blue}{rgb}{0.8,0.8,1.0}$

  • $V_\text{L}=\colorbox{pink}{0.16}$, $V_\text{H}=\colorbox{pink}{0.71}$
  • $V_\text{range}=V_\text{H}-V_\text{L}=\colorbox{pink}{0.55}$
  • $V_\text{a}=\frac{V_\text{range}}{300}a+V_\text{L}$
  • $V_\text{a+b}=\frac{V_\text{range}}{300}(a+b)+V_\text{L}$

次にAD変換後のデータDは入力全範囲0~1[V]を4096分割する。開始角の値を$D_\text{a}$、終了角の値を$D_\text{a+b}$として

  • $D_\text{a}=4096V_\text{a}=\frac{4096V_\text{range}}{300}a+4096V_\text{L}=\colorbox{pink}{7.509}a+\colorbox{pink}{655.4}$
  • $D_\text{a+b}=4096V_\text{a+b}=\colorbox{pink}{7.509}(a+b)+\colorbox{pink}{655.4}$
  • $D_\text{range}=D_\text{a+b}-D_\text{a}=\colorbox{pink}{7.509}b$

一方、y座標の制約は以下のとおりであり、$y_\text{top}$(上限$y_\text{max}$+5%)と$y_\text{bottom}$(下限$y_\text{min}$-5%)の値でクリッピング。

  • $y_\text{min}=\colorbox{pink}{44}, y_\text{max}=\colorbox{pink}{219}, Paddle_\text{h}=\colorbox{pink}{26}$
  • $y_\text{bottom}=y_\text{min}-7=\colorbox{pink}{37}, y_\text{top}=(y_\text{max}-Paddle_\text{h})+7=\colorbox{pink}{200}$
  • $y_\text{range}=y_\text{top}-y_\text{bottom}=200-37=\colorbox{pink}{163}$

これらからy座標を求めると、ADCのデータを$D$とすれば、

  • $y=\frac{y_\text{range}}{D_\text{range}}(D-D_\text{a})+y_\text{bottom}=\frac{\colorbox{pink}{163}}{\colorbox{pink}{7.509}b}D-\frac{\colorbox{pink}{163}}{b}a-\frac{\colorbox{pink}{163}\cdot\colorbox{pink}{655.4}}{\colorbox{pink}{7.509}b}+\colorbox{pink}{37}\\ =\frac{\colorbox{pink}{347.3}}{b\ll4}D-\frac{\colorbox{pink}{163}}{b}a-\frac{\colorbox{pink}{14225}}{b}+\colorbox{pink}{37}=\frac{\colorbox{blue}{347}D-\colorbox{blue}{2608}a-\colorbox{blue}{227607}}{b\ll4}+\colorbox{blue}{37}$

y式中のシフトは固定小数点演算を行うために分母分子を16倍しているものです。さらに最小値$D_\text{a}$、最大値$D_\text{a+b}$で入力ADCデータのクリッピングを行います。

  • $D_\text{a}=\colorbox{pink}{7.509}a+\colorbox{pink}{655.4}=(\colorbox{blue}{120}a+\colorbox{blue}{10486})\gg4$
  • $D_\text{a+b}=\colorbox{pink}{7.509}(a+b)+\colorbox{pink}{655.4}=(\colorbox{blue}{120}(a+b)+\colorbox{blue}{10486})\gg4$

以上より、完成したBSVコードの変更点のみを以下に示します。

クリッピング値計算部分

        // 座標の下限-5%と上限+5%に対応するADC値の計算
        Bit#(20) adcMinValue = (120 * extendedA + 10486) >>4;     // Min = 7.509A + 655.4
        Bit#(20) adcMaxValue = (120 * (extendedA + extendedB) + 10486) >> 4; // Max = 7.509(A+B) + 655.4

ADCからy値計算部分

        Bit#(24) coordinate = ((zeroExtend(clippedAdcValue) * 347
               - zeroExtend(extendedA) * 2608 - 227607)
              / zeroExtend(extendedB) >> 4) + 37;

変換器部分はこのとおりですが、FSM中でのパドルの可動範囲$y_\text{min}=\colorbox{blue}{44}$、$y_\text{max}-Paddle_\text{h}=219-26=\colorbox{blue}{193}$でクリッピングすることを忘れないように注意します。


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

Pongの開発 (11)

posted by sakurai on December 5, 2023 #709

CmodA7からPMODへのインタフェース基板のため、CmodA7toPMODV5と名付けました。そのGerber図が図709.1であり、JLCPCBに依頼していた基板が届きました(図709.2)。

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

図%%.2
図709.2 CmodA7toPMODV5基板

早速組み立てて動作させたところ、デバッグした後に正常に動作しました。図はPMODVGAインタフェース、PMOD I2Sオーディオインターフェース、PMODジョイスティックスイッチインターフェースの3つを接続した図です。外部電源5VでもUSBのみの電力でも動作するようです。

図%%.3
図709.3 CmodA7toPMODV5完成

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

Pongの開発 (10)

posted by sakurai on December 4, 2023 #708

You

AとBはゲームを試作してみないと決定できませんが、決める方法は?

Bluespec Expert
AとBがゲームの試作段階で決定されるというのは理解しました。AとBは、ゲームのデザインやユーザーインターフェースの要件に基づいて変わる可能性があるため、試作を通じてこれらの値を最適化するのは良いアプローチです。

試作段階では、さまざまなAとBの値を試して、ゲームプレイに最も適した設定を見つけることが重要です。この過程で以下の点を考慮すると良いでしょう:

 1. ユーザーインターフェース:
プレイヤーが可変抵抗器のツマミをどのように操作するか、そしてその操作がゲーム上でどのように反映されるかを考慮します。

 2. 応答性:
ツマミの操作に対するゲームの応答性を評価します。ツマミを少し回すだけで大きく座標が変化するか、またはより細かい調整が可能かを検討します。

 3, プレイの難易度:
AとBの設定はゲームの難易度に直接影響を与える可能性があります。簡単すぎるか難しすぎるかを評価し、プレイヤーにとって楽しく挑戦的なバランスを見つけます。

 4, テストとフィードバック:
実際のプレイヤーによるテストを行い、彼らのフィードバックをもとに、AとBの最適な値を決定します。

試作プロセスが完了し、AとBの値が決定されたら、提供された変換式を使用して、ADCの値からゲーム画面上の座標への変換を実装できます。これにより、ゲームの操作性とプレイヤーの体験を最適化することができるでしょう。


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

Pongの開発 (9)

posted by sakurai on December 1, 2023 #707

You

正解です。それではA°のときが画面上の座標44に相当し、A+B°のときが座標186のときに相当するとき、ある角度A+x°のときの座標を計算してください。

Bluespec Expert
与えられた条件に基づいて、角度A+x°のときの座標を計算するためには、角度と座標の間の線形関係を確立する必要があります。A°が座標44に、A+B°が座標186に対応するとします。この関係から、角度と座標の変換式を導き出し、それを使って任意の角度A+x°のときの座標を求めます。

  1. 角度と座標の変換係数の計算:

    • 角度の変化量は B、対応する座標の変化量は 186 - 44 です。
    • したがって、1°あたりの座標の変化量は (186 - 44) / B です。
  2. 任意の角度A+x°の座標の計算:

  • A°のときの座標は44なので、A+x°のときの座標は 44 + x * ((186 - 44) / B) となります。

この計算には、角度の増加量 x とBの具体的な値が必要です。しかし、これらの値が提供されていないため、具体的な座標を計算することはできません。もしこれらの値を提供いただければ、具体的な座標を計算することが可能です。

You

ゲーム中にxは毎秒変化するから具体的な値は与えられません。以上から、ADCの値から座標値へ変換する式を求めてください。

Bluespec Expert
ADCの値からゲーム画面上の座標値への変換式は以下の通りです:

$$座標 = 44 + ((((\text{adc_value} / 4096 - 0.2) / 0.74) * 300 - A) * ((186 - 44) / B))$$

この式では、まずADC値 (adc_value) から対応する角度への変換を行い、その後その角度を基にして座標値に変換しています。ただし、この式はBの具体的な値に依存します。Bは角度AからA+Bまでの変化量を示しており、これによって角度と座標の関係が決定されます。

You

事前に演算できる定数をまとめてください。

Bluespec Expert
確かに、定数同士の除算も事前に計算して定数として扱うことができます。式内のすべての定数同士の乗算と除算を事前に行い、式をさらに簡略化してみましょう。式は次のようになります:

$$座標 = 44 + \frac{\text{adc_value} \times 14.05}{B} - \frac{11513.36}{B} - \frac{A \times 142}{B}$$

これで、式は定数計算をすべて事前に行った状態で、より簡略化されています。これを使って、特定の $\text{adc_value}$、$A$、$B$ の値に対する座標を計算できます。


ChatGPTに計算してもらった式を固定小数点演算化するために分母分子を16倍します。すると、 $$座標 = 44 + \frac{\text{adc_value} \times 225}{16B} - \frac{184214}{16B} - \frac{A \times 2272}{16B}$$ となり、前記事の式と有効数字5桁で一致しました。


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

Pongの開発 (8)

posted by sakurai on November 30, 2023 #706

設計段階でVRの操作範囲(開始点、可変範囲)をパラメータ化して回路設計しましたが、現実には実際にゲームをして値を決定します。

そこで例によってChatGPTのBSV Expert君と対話してみます。これは設計開始時点からの会話です。

You

電圧が0.2Vから0.94Vまでの信号を、入力電圧0Vから1Vまでを12bit ADCで測定します。ADCの結果はどの範囲となりますか?

Bluespec Expert
0.2V から 0.94V の電圧範囲は、12ビットのADCでは約819から3850の値に相当します。これは、0Vから1Vの範囲を12ビットで測定するとき、各ビットが約0.244mVを表すことに基づいています。したがって、測定される電圧範囲はADCの値として819から3850の範囲になるでしょう。

You

正解です。その入力電圧はVR(可変抵抗器)のツマミを回すことで発生します。VRの最大回転角度は300°です。ここで、VRのツマミをA°からA+B°まで回すときに先ほどの入力電圧が発生すると、得られるADCの値は何から何までですか?

Bluespec Expert

  1. 角度から電圧への変換:

    • 可変抵抗器のツマミが最大に回されたとき、0.2Vから0.94Vの範囲をカバーします。
    • したがって、可変抵抗器の最大回転角度300°に対応して、電圧範囲は0.74V(0.94V - 0.2V)になります。
  2. 角度 A と A+B に対応する電圧:

    • 角度 A に対応する電圧は 0.2 + (A / 300 * 0.74) となります。
    • 角度 A+B に対応する電圧は 0.2 + ((A+B) / 300 * 0.74) となります。
  3. 電圧からADC値への変換:

    • 12ビットのADCでは、1Vに対して4096の値が割り当てられます。
    • したがって、電圧 V に対応するADC値は V * 4096 です。
  4. ADC値の範囲:

    • 角度 A に対応するADC値は (0.2 + (A / 300 * 0.74)) * 4096 となります。
    • 角度 A+B に対応するADC値は (0.2 + ((A+B) / 300 * 0.74)) * 4096 となります。

これにより、可変抵抗器のツマミを任意の角度 A から A+B まで回したときに得られるADCの値の範囲を計算できます。


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

Cmod A7の利用 (8)

posted by sakurai on November 29, 2023 #705

レベルダイアグラム

前稿のレベルダイアグラムを変数を用いて書き直したものが図705.1です。これに従いデータ変換器をBSVで開発します。ただし、前稿ではVRの開始角と使用角度範囲を105°, 90°と仮決めしましたが、試行錯誤で変更することを見越してパラメータ化したRTLとします。

図%%.1
図705.1 レベルダイアグラム

  • VRの全角度は300°
  • VRの使用角はパラメータ化し、開始角a[°]、範囲b[°]
  • VRの全角度の際のADC入力電圧はLTSpiceの結果より、0.2~0.94[V]

これらより、使用電圧は開始角の値を$V_\text{a}$、終了角の値を$V_\text{a+b}$として、

  • $V_\text{L}=0.2$, $V_\text{H}=0.94$
  • $V_\text{range}=V_\text{H}-V_\text{L}=0.74$
  • $V_\text{a}=\frac{V_\text{range}}{300}a+V_\text{L}$
  • $V_\text{a+b}=\frac{V_\text{range}}{300}(a+b)+V_\text{L}$

次にAD変換後のデータDは入力全範囲0~1[V]を4096分割する。開始角の値を$D_\text{a}$、終了角の値を$D_\text{a+b}$として

  • $D_\text{a}=4096V_\text{a}=\frac{4096V_\text{range}}{300}a+4096V_\text{L}=10.1a+819.2$
  • $D_\text{a+b}=4096V_\text{a+b}=10.1(a+b)+819.2$
  • $D_\text{range}=10.1b$

一方、y座標の制約は以下のとおりであり、上限$y_\text{top}$と下限$y_\text{bottom}$の値でクリッピングが必要。

  • $y_\text{bottom}=44$, $y_\text{top}=186$
  • $y_\text{range}=y_\text{top}-y_\text{bottom}=142$

これらからy座標を求めると、ADCのデータを$D$とすれば、

  • $y=\frac{y_\text{range}}{D_\text{range}}(D-D_\text{a})+y_\text{bottom}=\frac{142}{10.1b}D-\frac{142}{b}a-\frac{142\cdot 819.2}{10.1b}+44\\ =\frac{224.9}{b\ll4}D-\frac{142}{b}a-\frac{11514}{b}+44=\frac{225D-2272a-184216}{b\ll4}+44$

y式中のシフトは固定小数点演算を行うために分母分子を16倍しているものです。さらに最小値$D_\text{a}$、最大値$D_\text{a+b}$で入力ADCデータのクリッピングを行います。

  • $D_\text{a}=10.1a+819.2=(162a+13107)\gg4$
  • $D_\text{a+b}=10.1(a+b)+819.2=(162(a+b)+13107)\gg4$

以上より、完成したBSVコードは以下のとおりです。

package FixedPointConverter;

import Vector::*; // ベクター操作のためのモジュール

interface ConverterIfc;
    method Bit#(12) convert(Bit#(12) adcValue);
endinterface

// ADCの値から座標に変換する演算器(固定小数点演算を使用)
(* synthesize, always_ready, always_enabled, no_default_clock, no_default_reset *)
module mkFixedPointConverter #(
    parameter Bit#(12) a,  // 角度の最小値
    parameter Bit#(12) b   // 角度範囲
) (ConverterIfc);

    method Bit#(12) convert(Bit#(12) adcValue);
        // パラメータの拡張
        Bit#(20) extendedA = zeroExtend(a);
        Bit#(20) extendedB = zeroExtend(b);

        // 座標の下限と上限に対応するADC値の計算
        Bit#(20) adcMinValue = (162 * extendedA + 13107) >>4;     // Min = 10.1A + 819.2
        Bit#(20) adcMaxValue = (162 * (extendedA + extendedB) + 13107) >> 4; // Max = 10.1(A+B) + 819.2
        // クリッピング処理
        Bit#(12) clippedAdcValue = (adcValue < truncate(adcMinValue)) ? truncate(adcMinValue) :
                                  (adcValue > truncate(adcMaxValue)) ? truncate(adcMaxValue) :
                                  adcValue;

          Bit#(24) coordinate = ((zeroExtend(clippedAdcValue) * 225
                               - zeroExtend(extendedA) * 2272 - 184216)
                               / zeroExtend(extendedB) >> 4) + 44;

        return truncate(coordinate);
    endmethod

endmodule
endpackage: FixedPointConverter

これをVivadoに配置した図は以下のとおりで単なる組み合わせ回路です。

図%%.2
図705.2 変換器

このモジュールをダブルクリックすると以下のパラメータ設定画面が表示されます。aとbがすでに設定されているのは、残念ながらbsvにデフォルト値の設定が無いのですが、生成されたverilogのパラメータ文を修正したものです。verilogを10進で修正したため、vivadoでも10進表示となっています。

図%%.3
図705.3 パラメータ設定画面

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

Cmod A7の利用 (7)

posted by sakurai on November 28, 2023 #704

レベルダイアグラム

アナログ回路では用いられる概念でレベルダイアグラムという概念があります。回路の各部分でどれだけのダイナミックレインジがあるかを示す図です。ここではアナログ入力についてダイナミックレインジを調べておきます。

VR角度[°] XADC入力電圧[V] XADC出力
0 0.2 820
300 0.94 3,852

使用VR角度[°] 変換器出力 画面可動域[pix]
105 1598 44
195 2498 186

  • VR回転角は0~300°
  • XADC入力は0~1.0Vであるが可変抵抗器出力のため、0.2~0.94V
  • XADCの変換後の出力はおよそ820~3852
  • 使用VR回転角は中心150°±45°=105~195°⇒調整により変更予定
  • 変換回路の出力は1598~2498⇒調整により変更予定
  • 画面の可動域(y座標)は44~186

読み出しシーケンス

読み出しだけなのでデータバスdi_in及びdwe_in入力は0とします。またアドレスはPin 15に対応するChannel 4(0x14)とし、den_inを1サイクルだけアサートします。すると変換データが準備されデータバスdo_outに出力されるので、それを読み込みます。この回路では変換終了信号eoc_outをden_inに接続しているため、連続的に変換が実行されます。

eoc_outをden_inに接続することにより、特に複雑なシーケンサを組まなくても連続的にADCが実行できるようです。

図%%.1
図704.1 XADC回路図

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

Parameterについて (4)

posted by sakurai on November 27, 2023 #703

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

まずパラメータを5とします。入力は10進数、16進数、2進数を受け付けますが、表示は2進数となります。最初は5回を設定したので、"0000....0101"と表示されます。ただしこれはverilog記述に依存するようで、verilogが10進であれば10進となります。

図%%.1
図703.1 パラメータ変更画面(count=5)

合成してビットストリームをFPGAにダウンロードしてボタンを押せば、以下の波形が得られます。パルスが5回出力されています。

図%%.2
図703.2 オシロスコープ画面

次にパラメータを7とすれば、"0000....111"と表示されます。

合成してビットストリームをFPGAにダウンロードしてボタンを押せば、以下の波形が得られます。パルスが7回出力されています。

図%%.3
図703.3 オシロスコープ画面
以上より、ソースを修正せずともIPインテグレータ上でパラメータを変更するだけで、合成と配置配線は必要なものの、bsvからFPGAまでパラメータの変更が一貫することが確認できました。ただしbsvはパラメータの箱だけを確保し中身は0です。つまりbsvのソース段階においてはパラメータのデフォルト値は0となり任意の値を設定することはできません。

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


ページ: