FPGAボードプレゼントへの応募者はゼロでした。
このテーマはこれで一旦終了して、次は中途半端に中断していたZYBOでI2S IPを利用したスクラッチ音生成を再開しようと思う。
2015年11月23日月曜日
2015年11月9日月曜日
2015年11月7日土曜日
世界最小クラスかも知れないFPGAボード 15 (ブロック崩しゲームの実装 2)
現在実装中のブロック崩しゲームだがゲームとして遊べるレベルにはなった。
バーの操作はロータリーエンコーダで行うことにした。エンコーダの左側にある基板上の部品は押しボタンスイッチでゲーム開始の操作に使用する。

また、画像だけだとつまらないので音も発生するようにした。

箱の内部はエンコーダのケーブルがとぐろを巻いているだけだ。

電源を入れると、以下の画面表示になる。

ここで押しボタンスイッチを押すとボールが下方に動き始めゲームが開始される。
プレイしている様子
プレイしてみて、自分の反射神経の衰えを実感してしまった。orz
が、中々楽しい。なんじゃこりゃーおもしろいぞー!ってな感じだ。
アーキテクチャと最上位のRTLは以下のようになっていて結構シンプルだ。


syncgenで同期信号と描画座標を生成してbreakoutモジュールに渡す。
breakoutモジュールは描画座標とボールや各ブロックの座標とを比較して衝突判定して処理をおこなっている。

回路規模はこんな感じ


タイミングもMetしている。
バーの操作はロータリーエンコーダで行うことにした。エンコーダの左側にある基板上の部品は押しボタンスイッチでゲーム開始の操作に使用する。
また、画像だけだとつまらないので音も発生するようにした。
このままだと操作しづらいので以下のように段ボール箱を筐体代わりにして組み上げた。
箱の内部はエンコーダのケーブルがとぐろを巻いているだけだ。
電源を入れると、以下の画面表示になる。
ここで押しボタンスイッチを押すとボールが下方に動き始めゲームが開始される。
プレイしている様子
プレイしてみて、自分の反射神経の衰えを実感してしまった。orz
が、中々楽しい。なんじゃこりゃーおもしろいぞー!ってな感じだ。
アーキテクチャと最上位のRTLは以下のようになっていて結構シンプルだ。


syncgenで同期信号と描画座標を生成してbreakoutモジュールに渡す。
breakoutモジュールは描画座標とボールや各ブロックの座標とを比較して衝突判定して処理をおこなっている。

回路規模はこんな感じ


タイミングもMetしている。
2015年11月1日日曜日
世界最小クラスかも知れないFPGAボード 14 (ブロック崩しゲームの実装 1)
2015年10月25日日曜日
世界最小クラスかも知れないFPGAボード 13 (VGA I/Fを実装してみる)
今回は趣向を変えてVGA出力回路の実装をやってみた。表示内容はカラーバーの背景に32x32ドットのパターンをスプライト表示してみる。FPGAのピン数が少ないので、R,G,Bの階調は4階調とした。
今回作成したVGAテストセット

裏面

表示画面

画素数はVGA(640 x 480、ピクセルクロック 25MHz)としている。SVGA(800x600,50MHz)だと僅かにタイミングマージンが不足する。
リソースの使用状況はこんな感じだった。

スプライトで表示している四角のパターンは、ソース上はROMとして推論されるように記述しているのだがROMとして推論されず、CLBに展開されてしまっている。

色々試行錯誤したのだが、どうやってもROMとして推論されなかった。 iCE40には4KbitのBRAMが20個あるが、容量が4Kbit以上の場合は推論されないようだ。仕方がないので、BRAMのプリミティブセルをインスタンスしそれに初期値を設定して使う方法でやってみた。ここで、初期値のロードに$readmemhが使えると楽なのだが、iCE40のプリミティブセル内のメモリ配列が1次元のレジスタとして記述されていて$readmemhが使えないので、以下のようにparameterとして設定した。

ROM化すると回路規模は以下のようになった。

ROM化出来ていない場合に比べ若干小さくなっているように見える。
タイミングマージンは改善されSVGAでもMetするようになった。


リソースには空きがかなりあるので、ブロック崩しゲーム位なら実装できるかも知れないな。
今回作成したVGAテストセット
裏面
表示画面
画素数はVGA(640 x 480、ピクセルクロック 25MHz)としている。SVGA(800x600,50MHz)だと僅かにタイミングマージンが不足する。
リソースの使用状況はこんな感じだった。

スプライトで表示している四角のパターンは、ソース上はROMとして推論されるように記述しているのだがROMとして推論されず、CLBに展開されてしまっている。

色々試行錯誤したのだが、どうやってもROMとして推論されなかった。 iCE40には4KbitのBRAMが20個あるが、容量が4Kbit以上の場合は推論されないようだ。仕方がないので、BRAMのプリミティブセルをインスタンスしそれに初期値を設定して使う方法でやってみた。ここで、初期値のロードに$readmemhが使えると楽なのだが、iCE40のプリミティブセル内のメモリ配列が1次元のレジスタとして記述されていて$readmemhが使えないので、以下のようにparameterとして設定した。

ROM化すると回路規模は以下のようになった。

ROM化出来ていない場合に比べ若干小さくなっているように見える。
タイミングマージンは改善されSVGAでもMetするようになった。

リソースには空きがかなりあるので、ブロック崩しゲーム位なら実装できるかも知れないな。
2015年10月11日日曜日
世界最小クラスかも知れないFPGAボード 12 (2枚目作成)
CANも動いたし、作成したFPGAボードは問題なさそうだと判断できるので、もう1つ作ることにした。
以下はFPGAのボールに線材をハンダ付けし始めたところで、実体顕微鏡越しにデジカメで撮影した。こんな感じで0.35mmのピッチのボールに線材を手作業でハンダ付けしていく。

全てのボールにハンダ付けするとこうなる。

目視ではハンダブリッジ等のハンダ付け不良は無さそうなので、1枚目の基板と同様に全てのI/Oピンに順繰りにパルスを出力する回路をFPGAにダウンロードして動作させ、ロジアナで確認した。


1ピンづつパルス出力されており、問題ない。

右が1号機、左が本日ハンダ付けした2号機
1号機はFPGAの配線部を保護する目的で接着剤で固めてある。
2号機はまだその作業を行っていない。

以下はFPGAのボールに線材をハンダ付けし始めたところで、実体顕微鏡越しにデジカメで撮影した。こんな感じで0.35mmのピッチのボールに線材を手作業でハンダ付けしていく。
全てのボールにハンダ付けするとこうなる。
目視ではハンダブリッジ等のハンダ付け不良は無さそうなので、1枚目の基板と同様に全てのI/Oピンに順繰りにパルスを出力する回路をFPGAにダウンロードして動作させ、ロジアナで確認した。

1ピンづつパルス出力されており、問題ない。

右が1号機、左が本日ハンダ付けした2号機
1号機はFPGAの配線部を保護する目的で接着剤で固めてある。
2号機はまだその作業を行っていない。
2015年10月4日日曜日
世界最小クラスかも知れないFPGAボード 11 (CAN IPを実装してみる 7)
CANバス経由でのリードバックを見てみた。
いきなり実機で動かすことはせず、RTLレベルとゲートレベルでシミュレーションをして動くことを確認してから実機で確認することにした。 シミュレーションではこれまでと同様にCANマスタとしてOpenCoresのCAN IPを使用した。
以下のようにCANバスからI2Cコントローラのreg_adrレジスタに0x55を、reg_wdatレジスタに0xAAを書き、次にreg_adrレジスタの値をリードバックしてみた。

以下がRTLシミュレーションの結果である。赤字のref_modelの部分がCANマスタの信号で、data_out[7:0]は受信した(即ち、自作CANIPが送信した)データである。 0x55 が受信できているので期待通りだ。

こちらはゲートレベルシミュレーションの結果で、こちらも期待位通りの結果だった。

I2C busの通信も起動できるかの確認
こちらも期待通りの結果だった。


実機での確認
シミュレーションと同じようにI2C コントローラに値を書いて、それが読めるかを見てみた。
zynq側のプログラム

結果
3行目の「2: xxxxxxxx]の左端がリードバックして受信した値で、55になっているので成功だ。

http://bravo-fpga.blogspot.jp/2015/08/fpga-7.htmlに書いたとおり、I2CバスにはMCP3425ADT (16bit ΔΣ A/D)、 MCP4726A0T (12bit DAC)、 STTS751 (12bit 温度センサ)が接続されているが、今回はSTTS751のレジスタを読んでみることにした。

STTS751のレジスタマップは以下のようになっている。

Manufacturer ID、Revision、Product ID等固定値のレジスタと温度レジスタをリードしてみた。
zynq側のプログラム

結果

固定値の部分はデータシート通りの値が読めている。また、このプログラムを実行した時の室温は29℃だった。1℃の違いはあるが、温度も正しく読めていると考えて良いだろう。

ということで、リードバックは問題無さそうだ。
いきなり実機で動かすことはせず、RTLレベルとゲートレベルでシミュレーションをして動くことを確認してから実機で確認することにした。 シミュレーションではこれまでと同様にCANマスタとしてOpenCoresのCAN IPを使用した。
以下のようにCANバスからI2Cコントローラのreg_adrレジスタに0x55を、reg_wdatレジスタに0xAAを書き、次にreg_adrレジスタの値をリードバックしてみた。

以下がRTLシミュレーションの結果である。赤字のref_modelの部分がCANマスタの信号で、data_out[7:0]は受信した(即ち、自作CANIPが送信した)データである。 0x55 が受信できているので期待通りだ。

こちらはゲートレベルシミュレーションの結果で、こちらも期待位通りの結果だった。

I2C busの通信も起動できるかの確認
こちらも期待通りの結果だった。


実機での確認
シミュレーションと同じようにI2C コントローラに値を書いて、それが読めるかを見てみた。
zynq側のプログラム

結果
3行目の「2: xxxxxxxx]の左端がリードバックして受信した値で、55になっているので成功だ。

http://bravo-fpga.blogspot.jp/2015/08/fpga-7.htmlに書いたとおり、I2CバスにはMCP3425ADT (16bit ΔΣ A/D)、 MCP4726A0T (12bit DAC)、 STTS751 (12bit 温度センサ)が接続されているが、今回はSTTS751のレジスタを読んでみることにした。
STTS751のレジスタマップは以下のようになっている。

Manufacturer ID、Revision、Product ID等固定値のレジスタと温度レジスタをリードしてみた。
zynq側のプログラム

結果

固定値の部分はデータシート通りの値が読めている。また、このプログラムを実行した時の室温は29℃だった。1℃の違いはあるが、温度も正しく読めていると考えて良いだろう。
ということで、リードバックは問題無さそうだ。
2015年9月6日日曜日
世界最小クラスかも知れないFPGAボード 10 (CAN IPを実装してみる 6)
LSEで合成した場合の結果が変な件だが、どうも解せないのでFPGAの設定をMachXO2に変えて合成し生成されたネットリストでゲートシミュレーションを実行してみた。結果は同じでCANが応答しない。

XO2用に合成した場合はモジュール階層がある程度維持されるようで、canモジュールも各サブモジュールの信号名も保持されたネットリストになっており、can_rxpp(受信モジュール)のステートマシンのステートカウンタの信号も残っていたのでその信号を見てみたところ、上図のようになっていた。 stateがステートカウンタ、prv_stateは直前のステート値を保持するレジスタである。
このステートマシンはステート数16で4bitのステートカウンタの全ての値に意味がある。従って、state[1]が z になるのは変だ。 この z という状態はネットが浮いている、つまりどこにも接続されていないということなので、合成エンジンはstate[1]を不要と判断してその部分のレジスタを削除した可能性がある。

一方のprv_stateは一つ前のstateの値を保持するレジスタで、

prv_stateの値は以下の2箇所(794行目と821行目)で参照されている。

ST_ERROR値は4'd12とST_OVLDの値は4'd14なので、論理式の部分を解くと以下のようになり、確かにprv_state[1]は削除できることが解る。 ( prv_state != ST_ERROR && prv_state != ST_OVLDは、prv_state == ST_ERROR || prv_state == ST_OVLD の反転値なので両者でprv_state[1]は不要である。)

prv_stateの結果は間違っていないがstateの合成結果は明らかに間違っている。合成の最適化オプションの設定が関係しているかも知れない。上記合成は以下の最適化オプション設定で行った。

そこで、最適化オプションのResource SharingをFalseにして合成しなおしてみた。(尚、iCE40用のLSEの設定ではResoure SharingはデフォルトでTrueとなっている。)

生成されたネットリストでシミュレーションしてみると・・・

旨く行った! state[1]も正常だ。
この結果を受けて、iCEcube2でもResource SharingをFalseにして合成してみた。

生成されたネットリストでシミュレーションしてみると・・・

b2r_spenはcan_phyモジュールで生成されていて、信号受信が無い(RXD信号が変化しない)場合は、自走してビットレートに応じた周期のパルスになる。今の場合は1Mbpsなので1us周期のパルスとなる。また、RXD信号に0➔1または1➔0の遷移がある場合は、そのエッジで周期が微調整される。その様子は以前CAN IPのDEBUG 7に書いた。

なので、ノイズでの誤動作とかメタステーブルとかが原因では無さそうだ。
念の為オシロスコープでも見てみた。

そこで、ロジアナで採取したCANのRXD信号をテストベンチに取り込んで、シミュレーションで再現するかを見てみることにした。その為には・・・
まず、GTKWaveで観測している波形をTIMファイルにエクスポートする。

TIMファイルは以下のような形式のテキストファイルで全ての信号の情報を含んでいるので、そこからRXDの部分を抽出する。


そして、時刻情報と信号の値をテキストエディタなどを使ってテストベクタに変換する。

このベクタでRTLシミュレーションを実施したところ、現象が再現された。

色々原因を探った結果、Zynq側のビットレートが1Mbpsに対して9%程度低い可能性が見えてきた。
以下の波形はRXD信号に変化が無くてcan_phyが自走してb2r_spenを生成している部分だが、パルス間隔は1us (=1Mbps)となっていて正しい。


これに対して、RXDを見てみると、以下の波形は9シンボル分の間隔を見ているが、その値は9.83usとなっている。 9.83÷9 ≒ 1.09なので9%程度ビットレートがズレている。
CANの規格では送受信間のクロックのズレは最大1.58%となっているので9%は大きすぎる。

Zynq側に何か問題がありそうだ。
ZynqのCANモジュールのリファレンスクロックは24MHzだが、IO_PLLのから供給していて実際は23.809525MHzが供給されている。

ただ、誤差は0.8%程度なのでこれが原因とは考えにくい。とすると、CANモジュール内部のクロック関係の設定が怪しい。クロック関連の設定要素としてはBRPR(プリスケーラ)レジスタとBTRレジスタがある。それぞれの設定とビットレートとの関係はZynq-7000 AP SoC Technical Reference Manualに書いてある。現在のプログラムの設定値もここを参考にして決定した。

が、よく見ると、最下段のfreqBIT_RATEの式は間違っているようだ。Sync Segmentの分が含まれていない。正しくは、
freqBIT_RATE = freqCAN_REF_CLK / ((can.BRPR[BRP] + 1) * (3 + can.BTR[TS1] + can.BTR[TS2]))
でなければならない筈だ。現在の設定値はBRPR[BRP]が1,BTR[TS1]が8、BTR[TS2]が2なので、間違っている方の式でビットレートを求めると、24/((1+1)×(2+8+2)) = 1と1Mbpsになるが、正しくは、24/((1+1)×(3+8+2)) ≒ 0.923の筈で、これは1/0.923 = 1.083なので8%程度の誤差となる。
原因はここのようだ。
そこで、プログラムのTS1の値を7に変更することにした。

修正したプログラムを走らせてみたところ、旨くいった!! やたっ!
以下のプログラムではPWMのDutyを0%から100%まで5%刻みでCANバス経由で設定しているが、そのとおりにPWMの出力は変化している。



ということで、遂に世界最小クラスかもしれないFPGAボードでCANを動かすことが出来た。!!
やったー \(^_^)/
iCE40LMのパッケージへのハンダ付けの挑戦をするためにデジタル温調ハンダゴテを購入したのが2月だから、ここまで来るのに8ヶ月位かかったが、なんとかCANの動作まで漕ぎ着けた。 また、今回は2Gsのオシロよりも100Msの自作ロジアナの方が役に立った。このロジアナは作ってよかったと実感している。自作したものが十分使えて役に立ったという点も非常にうれしい。
次はCANバス経由でのリードバックを確認しよう。

XO2用に合成した場合はモジュール階層がある程度維持されるようで、canモジュールも各サブモジュールの信号名も保持されたネットリストになっており、can_rxpp(受信モジュール)のステートマシンのステートカウンタの信号も残っていたのでその信号を見てみたところ、上図のようになっていた。 stateがステートカウンタ、prv_stateは直前のステート値を保持するレジスタである。
このステートマシンはステート数16で4bitのステートカウンタの全ての値に意味がある。従って、state[1]が z になるのは変だ。 この z という状態はネットが浮いている、つまりどこにも接続されていないということなので、合成エンジンはstate[1]を不要と判断してその部分のレジスタを削除した可能性がある。

一方のprv_stateは一つ前のstateの値を保持するレジスタで、

prv_stateの値は以下の2箇所(794行目と821行目)で参照されている。

ST_ERROR値は4'd12とST_OVLDの値は4'd14なので、論理式の部分を解くと以下のようになり、確かにprv_state[1]は削除できることが解る。 ( prv_state != ST_ERROR && prv_state != ST_OVLDは、prv_state == ST_ERROR || prv_state == ST_OVLD の反転値なので両者でprv_state[1]は不要である。)

prv_stateの結果は間違っていないがstateの合成結果は明らかに間違っている。合成の最適化オプションの設定が関係しているかも知れない。上記合成は以下の最適化オプション設定で行った。

そこで、最適化オプションのResource SharingをFalseにして合成しなおしてみた。(尚、iCE40用のLSEの設定ではResoure SharingはデフォルトでTrueとなっている。)

生成されたネットリストでシミュレーションしてみると・・・

旨く行った! state[1]も正常だ。
この結果を受けて、iCEcube2でもResource SharingをFalseにして合成してみた。

生成されたネットリストでシミュレーションしてみると・・・
こちらも旨く行った! iCE40用の合成の場合は階層情報が維持されないようで、can_rxppモジュールのstateやprv_state等も上記の信号名しか参照できなかった。が、canはACKフレームを出しているので期待通りの動作をしている。
上述の通り、can_rxppモジュールのステートマシンはステート数が16あるステートマシンだ。
ステート間の遷移パターンは49パターンある。
上図のcovered_fsm、... はCoveredというコードカバレッジツール用のもので、このステートマシンの(記述されている)ステート遷移がシミュレーションで全てカバーされているか(検証されているか)を見るための記述である。 このcan_ip開発時に検証した。(CAN IPのDEBUG 8)
上記のような複雑なステートマシンの場合は、Resource Sharingは旨く作用しない場合があるのかも知れない。 ということで、Synplifyで旨く行って、LSEで旨く行かないことの原因らしきものは判った。
次は、実機でFPGAが反応しない(ACK応答しない)件だ。
Resource SharingをFalseにして合成したビットマップファイルをFPGAにダウンロードして実機で動作させてみたところ、Synplifyの場合と同じでACKフレームが出ない。反応していないように見えた。 そこで、can_ipの内部信号をFPGAの未使用ピンに出して、その状態をロジアナで観測してみた。

引き出したのはステートマシンがIDLEステートにいることを示す信号と、ERRORステートにいることを示す信号、そして、can_phyモジュールで生成されるcanのRXD信号をサンプリングするためのイネーブル信号(b2r_spen)だ。


引き出したのはステートマシンがIDLEステートにいることを示す信号と、ERRORステートにいることを示す信号、そして、can_phyモジュールで生成されるcanのRXD信号をサンプリングするためのイネーブル信号(b2r_spen)だ。


その結果、ステートマシンは動いてはいるようだが途中でエラーステートに遷移していることが判った。 さらに細かく見ていくと、b2r_spenの間隔が異常に短い箇所があることが判った。

b2r_spenはcan_phyモジュールで生成されていて、信号受信が無い(RXD信号が変化しない)場合は、自走してビットレートに応じた周期のパルスになる。今の場合は1Mbpsなので1us周期のパルスとなる。また、RXD信号に0➔1または1➔0の遷移がある場合は、そのエッジで周期が微調整される。その様子は以前CAN IPのDEBUG 7に書いた。
俯瞰して見てみると、この現象には周期性があるようだ。

なので、ノイズでの誤動作とかメタステーブルとかが原因では無さそうだ。
念の為オシロスコープでも見てみた。
そこで、ロジアナで採取したCANのRXD信号をテストベンチに取り込んで、シミュレーションで再現するかを見てみることにした。その為には・・・
まず、GTKWaveで観測している波形をTIMファイルにエクスポートする。

TIMファイルは以下のような形式のテキストファイルで全ての信号の情報を含んでいるので、そこからRXDの部分を抽出する。


そして、時刻情報と信号の値をテキストエディタなどを使ってテストベクタに変換する。

このベクタでRTLシミュレーションを実施したところ、現象が再現された。

色々原因を探った結果、Zynq側のビットレートが1Mbpsに対して9%程度低い可能性が見えてきた。
以下の波形はRXD信号に変化が無くてcan_phyが自走してb2r_spenを生成している部分だが、パルス間隔は1us (=1Mbps)となっていて正しい。


これに対して、RXDを見てみると、以下の波形は9シンボル分の間隔を見ているが、その値は9.83usとなっている。 9.83÷9 ≒ 1.09なので9%程度ビットレートがズレている。
CANの規格では送受信間のクロックのズレは最大1.58%となっているので9%は大きすぎる。

Zynq側に何か問題がありそうだ。
ZynqのCANモジュールのリファレンスクロックは24MHzだが、IO_PLLのから供給していて実際は23.809525MHzが供給されている。

ただ、誤差は0.8%程度なのでこれが原因とは考えにくい。とすると、CANモジュール内部のクロック関係の設定が怪しい。クロック関連の設定要素としてはBRPR(プリスケーラ)レジスタとBTRレジスタがある。それぞれの設定とビットレートとの関係はZynq-7000 AP SoC Technical Reference Manualに書いてある。現在のプログラムの設定値もここを参考にして決定した。

が、よく見ると、最下段のfreqBIT_RATEの式は間違っているようだ。Sync Segmentの分が含まれていない。正しくは、
freqBIT_RATE = freqCAN_REF_CLK / ((can.BRPR[BRP] + 1) * (3 + can.BTR[TS1] + can.BTR[TS2]))
でなければならない筈だ。現在の設定値はBRPR[BRP]が1,BTR[TS1]が8、BTR[TS2]が2なので、間違っている方の式でビットレートを求めると、24/((1+1)×(2+8+2)) = 1と1Mbpsになるが、正しくは、24/((1+1)×(3+8+2)) ≒ 0.923の筈で、これは1/0.923 = 1.083なので8%程度の誤差となる。
原因はここのようだ。
そこで、プログラムのTS1の値を7に変更することにした。

修正したプログラムを走らせてみたところ、旨くいった!! やたっ!
以下のプログラムではPWMのDutyを0%から100%まで5%刻みでCANバス経由で設定しているが、そのとおりにPWMの出力は変化している。


ということで、遂に世界最小クラスかもしれないFPGAボードでCANを動かすことが出来た。!!
やったー \(^_^)/
iCE40LMのパッケージへのハンダ付けの挑戦をするためにデジタル温調ハンダゴテを購入したのが2月だから、ここまで来るのに8ヶ月位かかったが、なんとかCANの動作まで漕ぎ着けた。 また、今回は2Gsのオシロよりも100Msの自作ロジアナの方が役に立った。このロジアナは作ってよかったと実感している。自作したものが十分使えて役に立ったという点も非常にうれしい。
次はCANバス経由でのリードバックを確認しよう。
登録:
投稿 (Atom)
ERROR: Failed to spawn fakeroot worker to run ...
なにかと忙しくてなかなか趣味の時間を確保できない。 ...orz 家の開発機のOSはLinux Mintなのだが、最近バージョンを22に更新したところ、myCNC用のpetalinuxをビルドできなくなってしまった。ビルドの途中で ERROR: Failed to spawn ...
-
FT232RというUSB-UART変換ICがある。このICにはBit Bang Modeという機能があって、UART用の端子がGPIO的制御が可能になる。 FT232Rを搭載したUSB-UART変換基板は秋月電子やマルツパーツ等色んなところで売られていて私もSparkfunのF...
-
これまではTCM8230MDの出力形式はRGB565にしていたが、画像もちゃんと表示できるようになってきたのでYUV422形式も扱えるようにして両者の画像の違いを見てみた。 まずTCM8230MDの出力をcolor bar出力にして、取り込んだ値に変換式を適用してどんな感じの...




