2017年1月9日月曜日

【電子工作】 AUO B101EAN01 でHDMI LCD displayを作ってみる (3)

中華通販LCDでこんな感じのHDMIモニタを作ってみようとしています.
前回は、FPGA内部で発生させたRGB信号をLCDパネルに表示させました.
今回は、PCから来たHDMI信号をLCDパネルに表示させるトライです.
1280x800 HDMI信号のbit clock周波数は750MHzになります.(コンフィグにより各種あるけどここでは750MHzとする)

だがしかし、XILINX Spartan6 でHDMI信号を処理するため750Mbpsシリアル信号を10bitパラレル 75Msymbol/Sに変換するのが意外にめんどくさい件についてレポートします.まぁなんとか上手く行かせたんだけどね.


【簡単な状況表現】
Spartan6の動作速度の限界を突破するための方策に関して、、、

1) Spartan6でユーザーロジックを好き勝手に実装できるのはせいぜい300MHzぐらいまで

2) 750MHzなどという速度のユーザーロジックは動作速度がまずMETしない (簡単なシリパラ変換回路ですらMETしないくらいダメ)

3) ユーザーロジックによるシリパラ変換すらMETしないことからの逃げとして、ISERDES2のようなシリパラ変換coreを活用してシリパラ変換する必要がある

4) 円満な実装状態では750MHz clockはシリパラ変換coreにのみ供給される形になる


【背景】
HDMI→LCDへのブリッジ回路を設計中です.
HDMIのケーブルを流れるRGB信号のデータレートは、画面の解像度にもよりますが、1280x800だとするとおよそ750Mbpsぐらいになります.

ゆえにぶっちゃけ、FPGAには750MHz clockで動く性能が必要となります.だがしかし、Spartan3EやCycloneのような廉価なFPGAだとPLLが300MHzぐらいまでしか発振してくれないので、採用不可となります.

Spartan6なら750MHzを発振できるだけのPLL性能があるのでSpartan6を採用しました.

次に、パラシリ変換の仕様について考えます.

HDMIケーブルを流れる信号は8/10変換されていますから、750Mbpsのビットストリームを10bitパラレル変換するのが通常的な処理になります.10bitパラレルデータを1シンボルと呼びます.シンボルレートは、75Msymbol/Secになります.

↓以上より、FPGAの入力直後で10bitシリパラ変換して75MHzのゆっくりしたclockでユーザーロジックを実装すればよいわけです.こんなイメージです.

↓ところがですぅ、HDMIケーブルを流れるクロック信号はシンボルレートの75MHzなんです.なのでFPGAで750MHzを再生しなくちゃいけません.こんなイメージになります.

↓だんだんと状況が地雷めいてきます.青いブロックがSpartan6のcoreなんですが、シリパラcoreが最大8パラまでしかできません.なので、10パラを実現するには5パラと2パラを直列接続しないといけません.こんなイメージです.

ここで、XILINXのFPGAについてさらに詳しく知っていれば、2パラもcoreを採用して、core-coreカスケード接続で10パラを実現することも可能らしいのですが、coreの使いこなしってめんどくさいのでやめました. (coreのカスタマイズは専らcore generatorを使っています)

以下では、PLL coreとシリパラcoreの生成について、ノウハウを書きます.


【core generatorによるPLL生成】
1ページ目
・Minimize output jitterを選択したけどこれで論理合成が楽になったのかどうかは不明
・入力周波数=75MHzにする
・HDMIケーブルの信号は差動なのでDifferential clock capable pinにします.ここをsingle-endにしておいて手書きでIBUFGDSを手書きで配置することも可能ですが、IBUFGが2ヶシリーズになってしまうのでエラーでビルドが止まってしまいますのでやめた方がいいでしょう.
2ページ目
・出力周波数を、75/750/375/150MHzに設定
・750MHzの位相は、simulationや実機デバッグでシリパラcoreのデータ化けが生じたら疑って下さい.0か180度を試すとどっちかで上手くいくかもです.わたしの場合はsimulationでシリパラcoreのデータ化けが生じ、750MHzの位相を180度にしたら治りました.シリパラcoreの取り扱いにはクロックレーシングの回避は設計者マターのようです. (FPGAロジックにおいてはPLLで生成させたクロックの乗せ変えはビルドツールが自動的にやってくれるのかなーと思ってるんですがね、わたしの誤解なのかもしれない)
・750MHzではBUFGじゃ役不足なのだそうで、強制的にNo bufferになる
・BUFGではなくBUFPLLを使えと指示される
↓3ページ目
とくになにもせず
↓4ページ目
とくになにもせず
↓5ページ目
クロックのポート名をお好みに名付けます.
↓6ページ目
とくになにもせず、Generateを押す.

【core generatorによるシリパラ生成】
↓1ページ目
・Customを選択
・入力なのでConfigure inputs from deviceを選択
・HDMI信号は差動なのでDifferentialを選択
・HDMI信号はTMDSという電圧規格です.ゆえにTMDS33を選択します.
↓TMDSの受信端では、3.3Vへ50Ωでプルアップするよう定められています.
↓Spatran6がTMDSを受信するには、VCCAUXを3.3Vにしなくちゃいけませんが、あいにくプリント基板は2.5Vに接続されています.なお、VCCAUXはFPGA内部で同一ノードですから、全部同時に3.3Vに接続変えする必要があります.
↓プリント基板の回路図を見ると、電源部分の2.5Vを3.3Vに繋ぎ替えれば良さそうです.まだ試してませんが.  → 追記: これでやってみてOKでした

↓2ページ目
・Use serializationを選択
・5パラにするので、Serialization factor=5
・外部から入力される信号はRGBの3本ですので、External data width=3
・以上の設定により、入力[2:0]、出力[14:0] になります
・Retimedを選択します.これを怠ると、750MHz clockでラッチされた信号が出力に出てきてしまってMETしません.Retimedにすれば、出力が150MHzでラッチされた信号になります.
↓3ページ目
・Delay TypeはNoneでよいと思う
↓4ページ目
・Clock仕様は、Single-endedです.なぜなら、ここに入力されるclockはPLLで生成された750/150MHzだからです.すなわち内部信号であって外部信号ではありません.
・内部信号がLVCMOS18であるべきなのかはよく判りませんがLVCMOS18を選んでおきました.論理合成で無視されることを期待します.
・PLLの設定の2ページ目でBUFPLLを使いなさいと指摘されていました.それに従ってBUFPLLを選択します.BUFPLLはこのcoreに自動的に実装されますので、自分で記述する必要はありません.
・Risingを選択します.これをBothにしてしまうとDDRになってしまいます.
↓5ページ目
とくになにもせず、Generateを押す.


【verologソース】
PLLとシリパラに関連する箇所だけです.

module top(
    input xrst,   // LOW=RESET
    input  clkp,  // HDMI clock  75MHz
    input  clkm,
    input  rp, // HDMI R   750Mbps
    input  rm,
    input  gp, // HDMI G
    input  gm,
    input  bp, // HDMI B
    input  bm
);

pll_tdms pll_tdms        // PLLのcore
(
    .clk75in_P(clkp),    // IN 差動pinを直接配線
    .clk75in_N(clkm),    // IN
    .clk75(clk75),       // OUT
    .clk750(clk750),     // OUT
    .clk375(clk375),     // OUT
    .clk150(clk150),     // OUT
    .RESET(~xrst),       // IN
    .LOCKED(tdms_LOCKED) // OUT
);

wire [14:0] rgb;
ser2para2 ser2para2      // 5シリパラ変換のcore
(
    .DATA_IN_FROM_PINS_P( {rp,gp,bp} ), 差動pinを直接配線
    .DATA_IN_FROM_PINS_N( {rm,gm,bm} ), 差動pinを直接配線
    .DATA_IN_TO_DEVICE( rgb ),          出力は150MHzレート
    .CLK_IN(clk750),
    .CLK_DIV_IN(clk150),
    .LOCKED_IN(tdms_LOCKED),
    .LOCKED_OUT(),
    .CLK_RESET(~xrst),
    .IO_RESET(~xrst)
);

後段のユーザーロジックはrgbとclk150でお好きにどうぞ、となります.


【制約ファイル】
HDMI信号の部分だけです.

NET "clkp" LOC = "P134" ;  # HDMI clock 75MHz = 13.3ns
NET "clkm" LOC = "P133" ;
NET "rm"   LOC = "P137" ;
NET "rp"   LOC = "P138" ;
NET "gm"   LOC = "P139" ;
NET "gp"   LOC = "P140" ;
NET "bm"   LOC = "P141" ;
NET "bp"   LOC = "P142" ;

NET "clk?" IOSTANDARD = "TMDS_33" ;
NET "r?"   IOSTANDARD = "TMDS_33" ;
NET "g?"   IOSTANDARD = "TMDS_33" ;
NET "b?"   IOSTANDARD = "TMDS_33" ;
NET "clk?" PERIOD = 13.33 ns | CLOCK_DEDICATED_ROUTE = FALSE ;

最後にあるFALSEの意味は、差動IOバッファであるところのIBUFGDSがpll coreに自動的に実装される都合上、clkpとclkmにIOバッファが自動挿入されるのを抑制するためです.これがないとビルドがエラーで止まるはずですのでご注意ください.


↓こうなるまでに4~5日悩んだよ.

なお~いつものように、この情報に間違いがあってもわたしは知りませんので、はまったら素直に死んでね.

前回へ      次回へ

かしこ

0 件のコメント:

コメントを投稿