2018年03月22日

NTSC エンコーダー(1)

さて、NTSC エンコーダーを設計してみよう。

ハードウェアのおさらい
icedip-vdacpng.png

4bit DAC で 1Vp-p DC出力。0 = -40IRE , 4 = 0 0IRE, 14 = 100IRE (のつもり)。
輝度信号は、4 - 11 の 8 レベルしか使わない。U,V 信号は、-4 〜 +4 で 合成したときに 15 になる場合が出てくる。NTSC エンコーダーは、14.314 MHz のクロック入力(4fs) で駆動して、映像データ以外の DAC 出力と 映像の タイミングを出力することにする。

module ntsc_encoder (
input NTSC_CLK // 14.314 MHz
, output NTSC_OUT[3:0]
, output XDISP
, output YDISP
, output FLAME
);

FLAME は、偶数フレームか奇数フレームかを示す。YDISP は、映像表示期間 XDISP は、1ラインの中の映像表示期間。映像生成のモジュールは、これらを使って、ローカルカウンタを制御する。
そして、NTSC_OUT と 映像を合成する。仮に NTSC_OUT をそのまま DAC に出力すれば、ブランク画面が表示される。

chaN 氏の 「RS-170A NTSCビデオ信号タイミング規格の概要」を見ながら作っていく。

reg [9:0] x; // 14.314 MHz counter
reg [8:0] y;
reg [1:0] f;

どうも フレーム 4つで1セット。1フレームは 最大 263ライン , 1ラインは 910 クロック(227.5fs) らしいので、内部状態として 3 つのカウンタを用意する。このカウンタは外部に出さずに、映像のスタートタイミングだけ知らせる。映像を作るモジュールは、別のカウンタを使い これらのデータを見て実際の DAC 出力を生成することにしよう。

assign XDISP = r_disp;
assign YDISP = (27 <= y) && (y < 27+228);
assign FLAME = f[0];
always @(posedge NTSC_CLK) begin
if ((~f[0] && (y == 262 -1) &&(x < 455 -1))
|| (~f[0] && (y != 262 -1) &&(x < 910 -1))
|| (f[0] &&(x < 910 -1))) begin // 227.5fs
x <= x + 1;
r_disp <= ((39 + 14)*4 -1 <= x) && (x < (39 + 14 +160)*4 -1);
end else begin
if (y < 262) begin
x <= 0;
y <= y +1;
r_disp <= 1'b0;
end else if (~f[0] && (y == 9)) begin
x <= 455;
y <= 0;
f <= f + 1;
r_disp <= 1'b0;
end else begin
x <= 0;
y <= 0;
f <= f + 1;
r_disp <= 1'b0;
end
end
end

これらのカウンタの操作。その前に 記法について、 C 言語だと begin,end は {,} になる。
長い間使っている自己流の記法だと } else { とか使うので それに合わせて end else begin みたいな書き方にすることにした。
映像信号について、
 ・偶数フレームは、先頭から始まり、最後は途中で打ち切り。
 ・奇数フレームは、途中から始まり、最後は打ち切らない。

1ラインは、910 クロックで 227.5fs 。

打ち切りは、偶数フレーム最後で 455 クロック。また、奇数フレームの映像ライン開始のときだけ x = 455 からいきなり始める。こうすることで Y の範囲は、共に 0 - 262 だが、表示は 262.5 ライン 分とした。ちなみに、半端なラインは、そもそも映像範囲ではない。なので、XDISP には影響しない。

YDISP や FLAME は、カウンタから簡単に生成できるのだが、XDISP は面倒な計算式になりそうなので、専用にレジスタを持つことにした。
映像の範囲は、640 clock x 228(456) にした。2 clock で 1dot 表示の予定なので 320 x 228 の解像度。モニタは、調整できそうにないので、モニタに合わせて コードの方を変更する。720 clock x 240(480) も出力可能だと思われるが、モニタが表示できるかどうか?


    always @(posedge NTSC_CLK) begin
    // (1)
    if ((3 <= y) && (y < 6)) begin
    if (x < 455 - 67) state <= 0; // -40IRE
    else if ((455 <= x) && (x < 910 - 67)) state <= 0; // -40IRE
    else state <= 4; // 0IRE
    // (2)
    end else if (y < 9) begin
    if (x < 33) state <= 0; // -40IRE
    else if ((455 < x) && (x < 455 + 33)) state <= 0; // -40IRE
    else state <= 4; // 0IRE
    // (3)
    end else if (f[0] && (y < 10)) begin
    state <= 4; // 0IRE
    end else begin
    if (x < 6*4) state <= 4; // 0IRE
    // H pluse
    else if (x < (6+17)*4) state <= 0; // -40IRE
    else if (x < (6+17+2)*4) state <= 4; // 0IRE
    // color burst
    else if (x < (6+17+2)*4+2) state <= 5; // 10IRE
    else if (x < (6+17+2)*4+4) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+6) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+8) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+10) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+12) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+14) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+16) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+18) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+20) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+22) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+24) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+26) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+28) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+30) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+32) state <= 2; // -20IRE
    else if (x < (6+17+2)*4+34) state <= 6; // 20IRE
    else if (x < (6+17+2)*4+36) state <= 3; // -10IRE

    else if (x < (6+17+2+9+5)*4) state <= 4; // 0IRRE

    else state <= 4; // 0IRE
    end
    end

さて、同期信号の出力。ここでは、x,y,f を見て、4bit を出力する。
ややこしいので 3 つに分ける。
(1) 垂直同期パルス
 4 〜 6 フレームで、幅広のパルスを出力する。奇数、偶数とも同じタイミング。H = 0IRE , L = -40IRE である。
(2) 前置等化パルス、後置等化パルス、
 (1) の前後 3 フレームづつ 1 〜 3 , 7 〜 9 フレームで、幅狭のパルスを出力。

33 clk = 2.3us , 67 clk = 4.7us

(3) 残りの部分
奇数フレームの映像ライン開始のときだけ途中から始めると書いたが、その直前の 1 ラインは、0IRE を出力するようである。そこだけが特別で、後は 水平同期を出す普通のラインのようである。
ここは、決まりに従って出力パターンをだらだらと書いた。

case 文 や case 文のようなロジックを if else の深いネストで記述するのは、FPGA は得意だと考えて多用している。こういう書き方で ROM なんかきれいに合成されるし、へたに最適化しようとしいてもしょうがないと思っている。

以上で、同期信号などは、エンコードできたはずなのである。

    Final Design Statistics
    Number of LUTs : 119
    Number of DFFs : 29
    Number of DFFs packed to IO : 0
    Number of clocks: 1
    Clock: ntsc_sate|NTSC_CLK | Frequency: 59.45 MHz | Target: 93.11 MHz |

    論理合成したらこうなった。14.314 MHz でしか動かさないので余裕。規模はちょっと多いが、まだまだ。



白黒で良いならば、適当なタイミングで 4/14 を出力してやれば、画像が出るはず。
カラーも 14.314 MHz と 4bit DAC の範囲で 多少は出せるはずで、パターンを作ってテストしたい。
高クロックでの処理は、実験結果を踏まえて検討する。

ところで、市松模様のようにドットが配置されるそうだが、実際どうなるか分かっていないのであった。色についても位相が逆になるとかなんとか。ちょっと苦労しそうな印象がある。

なおテストは、購入したモニタでのみ行う。当たり前だが、いろんな機器で検証するつもりはない。

    安いものには 4.3 inch 480x272 解像度のタイプと 5.0 inch 800x480 のタイプがある。他には 320x240 3.5 inch も。車載用が安いが、モジュールもある。4.3 inch でテストする予定だが、別途 5.0 inch も買うかも知れない。NTSC では、720x480 が表示可能だそうなので、ドットがまともに見えるかも知れない。
     ・このショップが安いようだ。4.3 inch $12 , 5.0 inch $16 ぐらい。
    (メモ) ひとつ NTSC/PAL 入力 LCD コントローラのデータシートを入手。MST703 というチップで 上記の 5.0 inch モジュールに採用されている。S-Video 入力に改造しようとしているサイトも見つけた。
    しかもこのチップ単体で買えるし -- いや買わないけど。

      MST703 は、
       ・NTSC, PAL 以外に SECAM をサポート
       ・S-Video x2 もしくは NTSC/PAL x4 の入力。
       ・RGB もしくは YCbCr 入力も 2系統サポート。

    安物ではまた違うチップだろう。購入中のものが届いたら中を見てみよう。

    さらに、NTSC デコーダーのチップ TI の TVP5150 も発見。どんな風にデコードしているのか参考にしよう。これでキャプチャとか アップコンバータとか作りたくなるが、変換したい元の機器持ってないし。参考にするだけ。参考といえば、MST703 は、9タップの FIR フィルタ内蔵だそうだ。ΣΔ DAC の話になるが、この程度で良いなら 実装は厳しくなさそう。

    3.5 インチ 320x240 タイプの安物では AMT630A がよく使われているようだ。モニタの内部写真をひとつ発見。2つのタイプが映っていたが、入力・電源ケーブルは、基板に直接ハンダづけされていた。RCA コネクタが相対的に大きく、配線がかっこ悪いと思っていたので、付け替えるのも良いかも。

    MST703-1s.jpg
    4.3 インチタイプも発見。こちらは、MST703 が使われていて、コネクタで配線。だが、もうひとつ空き端子がある。パラレルなのか? 系統が違うのか不明。また、12V 入力だが DC/DC コンバータで降圧している。・・・ということは 5V で動くものもあるかも知れない。

    AMT630-3.jpg

    買おうとしている安物そっくりの 5 インチ 800x480 タイプは AMT630 が使われていたり。映れば良いぐらいに考えていたが、MST703 は「あたり」で、AMT630 は「はずれ」という気がしてきた。

    追記:実は 紹介したショップの 5インチ は買ってあった。中を見ると AMT630A で、上のような小さな基板であった。DC/DC コンバータのチップは、TD1519A というもので データシートを見ると 4.75V 〜 32V で動作する。3.3V を作っているのであれば、5V 入力が出来そうな感じ。なお、AMT630A は、外付け SPI FLASH に ファームウェアが載っている。ハックしている人がいるかも知れない。
    安物だけあって、4.3 インチも同じようなものだろう。AMT630 は、S-Video 入力もあるのだが、ファームウェアを弄れるぐらいでないと改造できないだろう -- 無理。
    AMT630 は、320x240 だけかと思っていたが甘かった。
     − 480x240, 640x240, 520x288, 800x480, 800x600,1024x768, and more
    高解像度のものでも使われているかも知れない。VGA 入力とかが付いていれば確実に違うのだろうが。別に画像が悪いかどうかは知らないんだが、「はずれ」な気分である。

      追記:4.3 inch タイプも AMT630A であった。同じような基板。TD1519A かどうかは分からないが、12V/24V 対応。操作スイッチ3つ別基板なのだが、2 線のみ。ADC 入力と思われる。

    AMT630Acapture.jpg
    他に AMT630A を使った USB キャプチャードングル が安価に売られている(aliexpress を AMT630A で検索) 。$4.66 なので 液晶モニタより随分と安い。デコーダーが同じチップなわけだから、液晶モニタを写真に取るより、確実に状態を確認・キャプチャできる。Windows 10 で使えるとも書いてある。Don't need any drivers, more compatible!!!  とも。AUDIO LINE 入力や S-Video 入力もある。LINE 入力があるのであれば、DAC の波形をチェックする程度には使えそうだ。また標準ドライバでいけるものなら Linux で使えるかも知れない。ひとつ持っておくと良さそうな気がしてきた。

    予備知識がないのだが、EasyCAP UTV007 というのがデファクトスタンダード? みたいだ。が、かなり昔の話のようだ。で、dual chip で UTV007 より良いのだーみたいな宣伝。まがい物にしか見えないのだが。
    それはともかく、意外と便利かも知れない。ひとつは、NTSC エンコーダーの証拠写真 ーデバッグ用である。もうひとつは、Orange PI Zero とか Nanopi DUO のモニタ。PC の画面に表示できるのであれば、HDMI なんかより 便利に使えるかも知れない。期待することにしよう。

テストコード


      reg [3:0] v_dac;
      reg [9:0] x;
      reg [8:0] y;
      reg d_prev;
      reg y_prev;
      //assign VDAC = NTSC[3:0];
      assign VDAC = (X_DISP && Y_DISP) ? v_dac[3:0] : NTSC[3:0];


      always @(posedge CLK14M) begin
      d_prev <= X_DISP;
      if (X_DISP) begin
      y_prev <= Y_DISP;
      if (Y_DISP) begin
      if (y_prev != Y_DISP) begin
      y <= 0;
      end else if (d_prev != X_DISP) begin
      y <= y + 1;
      x <= 0;
      end else
      x <= x+1;
      v_dac <= FLAME ? 11 : 4;
      end
      end
      end

    簡単なものを記述してみた。カウンタの制御には、XDISP, YDISP の立ち上がり検出が必要になる。
    あとは、(X_DISP && Y_DISP) の期間で出力値を計算すれば良い。

    最初は、モニタのどこに表示されるかのチェック。偶数フレーム、奇数フレーム別々に表示させてみようと思う。

    今頃気が付いたのだが、FIFO を使えば データ生成と表示のタイミングを変えられる。iCE40 の ERB は、1024x4 の構成が可能。4 つ使えば 4096 エントリで1ライン分が多分入る。そうなると、表示していない区間の時間も使えて余裕が出てくる。基本は 14.314 MHz 910 clock で 640 clock しか表示しない。30% 時間を稼げるのだ。
    例えば、5 倍クロックで DAC を動かすが 、計算は 8 クロック 表示は 5 クロックとか。・・・これ自体はちょっと無理。全体で 910 x5 クロックだが、8 クロックかけていたら 568 個まで。16 クロックなら 284 個まで。こういうワザを使うかどうか分からないが、覚えておこう。

とりあえずここまで
 ・icedip2-samples-01.zip



posted by すz at 22:44| Comment(0) | TrackBack(0) | MachXO2
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/182754463
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック