1500円ZYNQ基板でFPGAプログラミング大全Xilinx編(第2版)の実習 2-3 HDMIでパターン表示

#はじめに
1500円 ZYNQ 基板(EBAZ4205)を使って、
FPGAプログラミング大全Xilinx編(第2版)の課題2-3 
「PC用ディスプレイにパターンを表示 (HDMI出力) 」
を学習したいと思います。

#DVI や HDMI で使われる TMDS 信号の説明
PC とモニタをデジタル接続する規格として、DVI が普及しました。
DVI 規格では、ディスプレイカードの高精細ビデオ信号をデジタル信号で出力します。
高速なデジタル信号を長いケーブルで伝えるため、TMDS 信号という形式で出力されています。

HDMI は、民生用のデジタルビデオ信号規格として、DVI が元になっているため、やはり TMDS で伝送されます。

>DVI 規格書
>http://www.cs.unc.edu/Research/stc/FAQs/Video/dvi_spec-V1_0.pdf

TMDS 信号の物理層は DVI 規格書に書かれています。
Transmitter 側は電流ソースの差動出力となっています。
Receiver 側では差動入力をそれぞれ AVCC=3.3V に RT=50Ω で終端して、受信します。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/0c50a113-37ae-95e3-e37b-2f72a46cc4ad.png)
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/88327725-5cbc-b60d-c48c-0cc3985eac25.png)


#Xilinx の TMDS_33 規格の説明
ZYNQ-7000 を含む Xilinx 7 シリーズ FPGA では、I/O ピンの出力モードを "TMDS_33" に設定すると、TMDS 信号を直接入出力できます。
具体的な使い方は、DS187 (Zynq-7000 SoC DC 特性および AC スイッチ特性)を見る事になっています。
しかし、肝心な回路図とかは無く、表の一部に TMDS_33 の項目が見えるだけで、さっぱりわかりません。
UG471 (7 シリーズ FPGA SelectI/O リソース ユーザーガイド)を見ても、「遠端に 3.3V への 50Ω抵抗」と、一言書かれているだけです。

TMDS_33 は、Xilinx の 2 世代前のFPGA Spartan-3A で最初に搭載された I/O 規格です。
そこで Spartan-3A の資料を探してみると、UG331 に TMDS_33 の具体的な解説と図がありました。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/a1738053-ca89-9592-ebae-2346b3700fd6.png)

---
TMDS_33 出力
>VCCO = 3.3V を供給する (Bank0 または Bank2)
>TMDS_33 に設定した差動ペアの出力端子から正・負の信号を出力し、HDMI ケーブルを駆動する。

---
TMDS_33 入力
>VCCAUX= 3.3V を供給する (Bank はどれでもよい)
>正・負どちらの信号線も、3.3V 電源に対して50Ωで終端してから、TMDS_33 に設定した>差動ペアの入力端子で受信する。



#HDMI 出力の搭載方法
TMDS_33 規格を使って、FPGA の I/O ピンからそのまま HDMI コネクタへ接続して、出力端子にできそうなことがわかりました。
(デバイスの静電気保護とかは、とりあえず考えない)

元の信号名は TMDS ですが、Xilinx では TMDS_33 と表記することで、その BANK の I/O 電源ピン(VCCO)への供給電圧を示しています。
(例えば、LVDS_25 は、VCCO に 2.5V を供給すると使える LVDS I/O 規格です。)

EBAZ4205 では、ZYNQ の PL の I/O ピンである VCCO_34 と VCCO_35 どちらも、3.3V が供給されているので、TMDS_33 で使えます。
ZYNQ では TMDS_33 に設定できるピンに BANK の縛りはなく、PL の I/O ピンはどれでも使用できるようです。
(7 シリーズは、Spartan6 よりも I/O バッファの構造が進化しているため)


#EBAZ4205 の出力ピンの調査
TMDS_33 出力の説明で、"差動ペアの出力端子" から出力すると書きました。
ZYNQ に限らず、たいていの FPGA では、差動出力でペアにできるピンは、あらかじめ決められています。(差動入力も同様)

最もよく使われる LVCMOS_33 だとペアの縛りがないので、任意のピンから任意の信号を出力できます。
しかし、差動出力はペアになれるピンが決まっているため、2本セットで引き出さないといけません。

EBAZ4205 では、DATA1, DATA2, DATA3 の 3 つのコネクタが、拡張コネクタとして利用できます。
このコネクタに接続されている ZYNQ の I/O ピンのうち、ペアにできるピンを使って、TMDS の 正・負 信号を出力しないといけません。

![9.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/20977d42-eaf7-1223-cb82-9b6e79348ab3.jpeg)



XC7Z010-1CLG400 のピン番号とピン名の割り当ては、xc7z010clg400pkg.txt に記載されています。
https://www.xilinx.com/support/packagefiles/z7packages/xc7z010clg400pkg.txt

信号名で、ほぼ同じ名前で 正(P)、負(N) の違いがあるピンが、差動ペアになれるピンです。
BGA パッケージ上で、必ず隣のピンに割り当てられています。

>(例)
>U20  IO_L15P_T2_DQS_34 (差動信号の正側)
>V20  IO_L15N_T2_DQS_34 (差動信号の負側)

EBAZ4205 の回路図では、FPGA の回路シンボルにピン名が記載されていません。
xc7z010clg400pkg.txt を使い、ピン番号からピン名を拾って、ペアにできるピンを探します。

DATA1, DATA2, DATA3 コネクタに割り当てられているピン番号と、ピン名を表にしてみました。
![11_pin_name.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/b19e4701-c74c-ef57-8562-d2e71403ba17.png)

#配線長について
基板で高速差動信号を扱う場合、正(P)、負(N)の配線長をできるだけ揃えないといけないのですが、EBAZ4205 基板の配線長はわかりません。
課題 2-3 では、VGA のピクセルレート 25.175MHz の 10倍で 251.75MHz 程度が、差動信号として出力されます。
この程度の速度であれば、5mm 程度の配線長差なら、まあ問題なく映るはずです。
(雑な計算だと、250 MHz では配線長差が±1.9mmぐらいでスキュー5%に収まる)

#DATA1 コネクタから HDMI 出力を検討
今回は、DATA1 コネクタから HDMI 出力を出したいと思います。
先ほどの表を差動ペア同志で並べ直して、HDMI で必要な信号を割り当ててみました。
![12_pin_name2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/8a86801a-7863-8a63-71ae-6ad7d12e2bb0.png)

#EBAZ4205 回路の確認と基板の改造
回路図によると、FPGA の I/O ピンと DATA1 コネクタの間には、22Ωのダンピング抵抗が挿入されています。
![10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/f44398fe-5478-f0bf-e0b3-047f28e4b5c2.png)

TMDS_33 で使う場合、直列に抵抗が入っていると邪魔なので、取り外して 0Ω に交換します。

必要なところだけ交換するため、表を作成しました。
回路図で R2473A の抵抗は、実際の基板シルクでは R2475 になっていました。
![13_data1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/1048ba4f-fd55-7839-deb9-ad6da8fcb465.png)


交換する抵抗は、枠で囲ったものです。1005 サイズなので小さいです。
![14_抵抗交換.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/52589ddb-c323-fd70-ccc4-610a62ac23c0.png)


抵抗 8 個を外して、
![11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/d3f0d0c4-cb69-8c76-9fe2-1251edf850da.jpeg)

0Ω を実装。色が同じなので、元と見分けがつきません。
![12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/5b4a0b04-46a9-d484-8dba-4e8efe0845eb.jpeg)


#HDMI 出力の接続図
HDMI 出力コネクタには、aitendo から、HDMI コネクタ with 基板(245円)を調達しました。
https://www.aitendo.com/product/6363

![IFB-HDMI19AW01-F.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/9efb5597-8d32-95f3-d8f2-1ec0cbd35365.png)

この基板に合わせて、DATA1 コネクタに挿し込むソケットとの接続図を描きました。
![15_配線図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/97c9765d-05d0-cede-1eb4-68561b4ec278.png)


コネクタは HDMI ですが、中身は DVI での出力です。
DVI では、DDC で映す信号規格をやり取りしなくても、映りそうなビデオ信号を出せば映してもらるため、SCL/SDA は接続しない事にします。

+5V Power は HDMI SINK 側(受信側)で接続検出に使われるため、電源から供給されている +5V をそのまま接続して供給します。
(DATA1 の電源逆流防止の D21 を外して、直結に変更する必要がある)


#配線作業

DATA1 コネクタに接続できる 2.0mm ピッチのソケットを発注したのですが、先方手違いで 2.54mm ピッチの普通のソケットが来てしまいました。
仕方ないので、とりあえず直結で接続します。

図の番号通りに配線したらこんな感じです。
(2.0mm ソケットが来たら、コネクタ結合式になおします)
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/892b1cee-07b6-f42c-5a7f-564ce70e47da.jpeg)

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/659ff0b3-cf58-8927-3521-8fcc6251f5d9.jpeg)

#関連ファイルのダウンロード
ソースファイル一式を、FPGAプログラミング大全Xilinx編(第2版) サポートサイトから取ってきます。
https://www.shuwasystem.co.jp/support/7980html/6326.html

XilinxFPGA_SE.zip を解凍して、\Zybo_Z7-10\dai2-3sho\blink フォルダをデスクトップに展開します。
HDMI 出力には Cora_Z7-10 より Zybo_Z7-10 の方がわかりやすいため、こちらを使います。


#制約ファイル(pattern.xdc)の変更
Zybo Z7-10 と EBAZ4205 で、FPGA のピンと、LED やスイッチの接続が違っているため、制約ファイル(pattern.xdc)を変更します。
ポート名に対する FPGA ピンの割り当てを、上の表に合わせて修正します。
変更点は、下記の通りです。

>クロック入力
> Zybo Z7-10:K17 (SYSCLK 125MHz) → EBAZ4205:N18 (33.333MHz)
> Zybo Z7-10:クロック周期 8ns → EBAZ4205:クロック周期 30ns
> Zybo Z7-10:クロックH期間 0-4ns(前半波) → EBAZ4205:クロックH期間 0-15ns(前半波)
>
>スイッチ入力(RESET)
> Zybo Z7-10:Y16 (BTN[3]) → EBAZ4205:V13 (端側)
>
>HDMI出力
> Zybo Z7-10:HDMI_CLK_N H17 → D20 EBAZ4205
> Zybo Z7-10:HDMI_CLK_P H16 → D19 EBAZ4205
> Zybo Z7-10:HDMI_N[0] D20 → B20 EBAZ4205
> Zybo Z7-10:HDMI_P[0] D19 → C20 EBAZ4205
> Zybo Z7-10:HDMI_N[1] B20 → A20 EBAZ4205
> Zybo Z7-10:HDMI_P[1] C20 → B19 EBAZ4205
> Zybo Z7-10:HDMI_N[2] A20 → H17 EBAZ4205
> Zybo Z7-10:HDMI_P[2] B19 → H16 EBAZ4205


```pattern.xdc
# EBAZ4205 constraints file
# chapter: 2
# project: pattern

#Clock signal
set_property -dict { PACKAGE_PIN N18   IOSTANDARD LVCMOS33 } [get_ports { CLK }];
create_clock -add -name sys_clk_pin -period 30.00 -waveform {0 15} [get_ports { CLK }];

#set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets CLK_IBUF];

#Reset
set_property -dict { PACKAGE_PIN V13   IOSTANDARD LVCMOS33 } [get_ports { RST }]; # BTN[3]

#HDMI TX
set_property -dict { PACKAGE_PIN D20   IOSTANDARD TMDS_33  } [get_ports { HDMI_CLK_N }];
set_property -dict { PACKAGE_PIN D19   IOSTANDARD TMDS_33  } [get_ports { HDMI_CLK_P }];
set_property -dict { PACKAGE_PIN B20   IOSTANDARD TMDS_33  } [get_ports { HDMI_N[0] }];
set_property -dict { PACKAGE_PIN C20   IOSTANDARD TMDS_33  } [get_ports { HDMI_P[0] }];
set_property -dict { PACKAGE_PIN A20   IOSTANDARD TMDS_33  } [get_ports { HDMI_N[1] }];
set_property -dict { PACKAGE_PIN B19   IOSTANDARD TMDS_33  } [get_ports { HDMI_P[1] }];
set_property -dict { PACKAGE_PIN H17   IOSTANDARD TMDS_33  } [get_ports { HDMI_N[2] }];
set_property -dict { PACKAGE_PIN H16   IOSTANDARD TMDS_33  } [get_ports { HDMI_P[2] }];
```
>set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets CLK_IBUF];

のところは、実験環境の Vivado 2018.3 ではコンパイル時にエラーになってしまうため、コメントアウトして通るようにしました。
大全の指定環境である Vivado 2020.1 では、そのままでコンパイルが通るはずです。

#MMCM接続部(pckgen.v)の変更
クロック周波数が 125 MHz → 33.333 MHz になるため、MMCM の周波数設定パラメータ 下記 3 点を変更します。
> 乗数 M(2.000-64.000)  36.0 → 27.0
> CLKIN1 周期 8.0ns → 30.0ns
> 除数 D(1-106) 5 → 1
> CLKOUT 分周数 Q = 35.75 のまま

MMCM 生成周波数は下記となります。
>fVCO    = fCLKIN x M / D = 33.333 MHz x 27 / 1 = 899.991 MHz
>fCLKOUT = fVCO / Q = 899.991 / 35.75 = 25.17457 MHz

```pckgen.v
/* Copyright(C) 2020 Cobac.Net All Rights Reserved. */
/* chapter: 第2章                     */
/* project: pattern                   */
/* outline: ピクセルクロック生成      */
/*          125MHz入力、25.175MHz出力 */
/* modifyed by KAN573                 */
/*        33.333MH入力、25.175MHz出力 */

module pckgen (
    input   SYSCLK,
    output  PCK
);

wire CLKFBOUT, iPCK, locked;
BUFG iBUFG (.I(iPCK), .O(PCK));

   MMCME2_BASE #(
      .BANDWIDTH("OPTIMIZED"),  // Jitter programming (OPTIMIZED, HIGH, LOW)
      .CLKFBOUT_MULT_F(27.0),   // 乗数M(2.000-64.000)  36 → 27 へ変更 by KAN573
      .CLKFBOUT_PHASE(0.0),     // 位相(-360.000-360.000)
      .CLKIN1_PERIOD(30.0),      // CLKINの周期 8.0 → 30.0 へ変更 by KAN573
      // CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
      .CLKOUT1_DIVIDE(1),
      .CLKOUT2_DIVIDE(1),
      .CLKOUT3_DIVIDE(1),
      .CLKOUT4_DIVIDE(1),
      .CLKOUT5_DIVIDE(1),
      .CLKOUT6_DIVIDE(1),
      .CLKOUT0_DIVIDE_F(35.75),  // 除数Q(1.000-128.000)
      // CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
      .CLKOUT0_DUTY_CYCLE(0.5), // デューティ比
      .CLKOUT1_DUTY_CYCLE(0.5),
      .CLKOUT2_DUTY_CYCLE(0.5),
      .CLKOUT3_DUTY_CYCLE(0.5),
      .CLKOUT4_DUTY_CYCLE(0.5),
      .CLKOUT5_DUTY_CYCLE(0.5),
      .CLKOUT6_DUTY_CYCLE(0.5),
      // CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
      .CLKOUT0_PHASE(0.0),
      .CLKOUT1_PHASE(0.0),
      .CLKOUT2_PHASE(0.0),
      .CLKOUT3_PHASE(0.0),
      .CLKOUT4_PHASE(0.0),
      .CLKOUT5_PHASE(0.0),
      .CLKOUT6_PHASE(0.0),
      .CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
      .DIVCLK_DIVIDE(1),         // 除数D(1-106) 5 → 1 へ変更 by KAN573
      .REF_JITTER1(0.0),         // Reference input jitter in UI (0.000-0.999).
      .STARTUP_WAIT("FALSE")     // Delays DONE until MMCM is locked (FALSE, TRUE)
   )
(以下略)
```

#コンパイル
オリジナルと同じですので、大全の手順通りでよいです。

#動作確認
Vivado からダウンロードが完了すると、HDMI 出力に接続したモニタにパターンが表示されます。
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/d0269bf7-c7c5-ad09-5590-6c848f66d685.jpeg)

同じ .xdc と pckgen.v を適用することで、課題 2-4-2 「グラデーション表示」も動作します。
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/955220/d3b81346-73b0-0c96-31f1-a3993dc9b8df.jpeg)


#まとめ
FPGA プログラミング大全 Xilinx 編 第2版
「課題 2-3 PC用ディスプレイにパターンを表示」について、EBAZ4205 で学習することができました。