こんな感じに表示されてます.720x480、8bit RGBを縦横斜めにインクリメントしてるのでこんな画像が表示されます.
全面的に参考にさせていただいたのが、こちらのページです.verilogソースも引用させていただきました.ありがとうございます.多謝、多謝!
画像を表示させてみて判ったことは、
1) HDMIケーブルを流れるクロック周波数
前回、誤解してたと書いたとおり、HDMIケーブルを流れるクロックは、チャネルクロック(ex.250MHz)ではなくキャラクタクロック(ex.25MHz)でした.クロック周波数が低いのはうれしいけど、液晶モニタ側でx10倍の周波数UPが必要になります.
2) HSYNC/VSYNCの幅は、1キャラクタなのか? それとも幅を持っているのか?
simulationではこうなってます.つまり、1キャラクタではなくて、幅を持っています.どれだけの幅が必要なのかは不明です.引用したverilog sourceのパラメータを踏襲しただけです.基本的には試行錯誤で決めりゃいいのかと思ってはいますが.
clkp キャラクタクロック
hd HSYNC
vd VSYNC
以下はverilog ソースコードです.
top module
HDMIケーブルに配線するのは、全て差動信号で、clkp/clkm,rp/rm,gp/gm,bp/gm です.
200ΩをシリーズにしてHDMIケーブルに接続します.
おおまかには、4つのブロックから成ります.
・clk270R27 XTAL 50MHz → 270.27MHz をつくります
・testpattern 720x480の画像を作ります.HSYNC/VSYNCも作ります
・dvi_enc HDMI規格の8/10変換
・10:1シリアル変換 LSB firstでHDMIケーブルに出力
clk270R27は、Xilinxの設計ツールのcoregenで生成していますので、black boxです.
各moduleのclockにはチャネルクロック=270MHzを与えています.ところが多くのmoduleはキャラクタクロックで動作するので、1/10 dutyのen10でenable制御しています.(clockを一本化したかったため)
============= top module ここから ===============
`timescale 1ns / 1ps
module top(
input clki,
input xrst,
output reg clkp, // character clock
output reg clkm,
output rp,
output rm,
output gp,
output gm,
output bp,
output bm,
output [3:0] LED
);
wire chclk;
clk270R27 HDMIclk (
.CLKIN_IN(clki), //50MHz
.RST_IN(~xrst),
.CLKFX_OUT(chclk) // 270.27MHz
);
// channel counter
reg [3:0] r;
always @(posedge chclk or negedge xrst)
if(!xrst) r <= 0;
else if(r==9) r<=0;
else r<=r+1;
// character enabler
reg en10;
always @(posedge chclk or negedge xrst)
if(!xrst) en10<=0;
else en10<=(r==0);
// character clock output
always @(posedge chclk or negedge xrst)
if(!xrst) begin clkp<=0; clkm<=1; end
else if(r==0) begin clkp<=1; clkm<=0; end
else if(r==5) begin clkp<=0; clkm<=1; end
// test pattern generation
wire [7:0] red, grn, blu;
wire den, hd, vd;
testpattern testpattern (
.clk(chclk),
.en(en10),
.xrst(xrst),
.red(red),
.grn(grn),
.blu(blu),
.den(den),
.hd(hd),
.vd(vd)
);
// encoder
wire [29:0] tmds; // ={r[9:0],g[9:0],b[9:0]}
dvi_enc dvi_enc (
.clk(chclk),
.en(en10),
.xrst(xrst),
.red_in(red),
.grn_in(grn),
.blu_in(blu),
.den_in(den),
.hd_in(hd),
.vd_in(vd),
.tmds_out(tmds)
);
// shift register
reg [29:0] tmdsp, tmdsm;
always @(posedge chclk or negedge xrst)
if(!xrst) begin tmdsp<=0; tmdsm<=~0; end
else if(en10) begin tmdsp<=tmds; tmdsm<=~tmds; end
else begin tmdsp<={1'b0,tmdsp[29:1]}; tmdsm<={1'b1,tmdsm[29:1]}; end
// LSB first serial output
assign rp =tmdsp[20];
assign rm =tmdsm[20];
assign gp =tmdsp[10];
assign gm =tmdsm[10];
assign bp =tmdsp[0];
assign bm =tmdsm[0];
// LED indicator
reg [27:0] LEDr;
always @(posedge chclk or negedge xrst)
if(!xrst) LEDr<=0;
else LEDr<=LEDr+1;
assign LED[0] = LEDr[25];
assign LED[1] = LEDr[20];
assign LED[2] = LEDr[15];
assign LED[3] = LEDr[10];
endmodule
============= top module ここまで ===============
testpattern
720x480のパラメータと、640x480のパラメータが書かれていて、640x480はコメントアウトしてあります.640x480で動かしたければ、720x480をコメントアウトすると同時に、topのclockを250MHzにする必要があります.
always文の中では、ごちょごちょと計算して、走査線データをRGB+SYNCの形で生成しています.
preambleとguard bandを発生する機能が在りません.それでもHDMIは動くという証明かと.
shiftという変数を0固定してあります.shiftをインクリメントさせると、画面がゾゾーッと動きます.目が回るので0固定にしました.
============= testpattern ここから ===============
module testpattern(
input wire clk, en, xrst,output reg [7:0] red, grn, blu,
output reg den, hd, vd
);
//Vact TtlLines Vblank VFreq HFreq PixeFreq Httl Hact Hblank
// 480 525 45 60.0 31.50 27.027 858 720 138
//720x480 858x525x60=27.027MHz
wire [15:0] hsync = 16'd40;
wire [15:0] hbp = 16'd40;
wire [15:0] hdata = 16'd720;
wire [15:0] hfp = 16'd58;
wire hsp = 1;
wire [15:0] vsync = 16'd2;
wire [15:0] vbp = 16'd33;
wire [15:0] vdata = 16'd480;
wire [15:0] vfp = 16'd10;
wire vsp = 1;
//Vact TtlLines Vblank VFreq HFreq PixeFreq Httl Hact Hblank
// 480 525 45 60.0 31.50 25.200 800 640 160
//VGA 640x480 800x525x60=25.2MHz
/*
wire [15:0] hsync = 16'd96;
wire [15:0] hbp = 16'd48;
wire [15:0] hdata = 16'd640;
wire [15:0] hfp = 16'd16;
wire hsp = 1;
wire [15:0] vsync = 16'd2;
wire [15:0] vbp = 16'd33;
wire [15:0] vdata = 16'd480;
wire [15:0] vfp = 16'd10;
wire vsp = 1;
*/
reg [15:0] hcnt, vcnt;
reg [ 7:0] shift;
always@(posedge clk or negedge xrst)
if(!xrst) begin hcnt<=0; vcnt<=0; shift<=0; red<=0; grn<=0; blu<=0; den<=0; hd<=0; vd<=0; end
else if(en) begin
if(hcnt<hsync+hbp+hdata+hfp-16'd1) begin
hcnt <= hcnt + 1;
end
else begin
hcnt <= 0;
if(vcnt<vsync+vbp+vdata+vfp-16'd1) begin
vcnt <= vcnt + 1;
end
else begin
vcnt <= 0;
shift <= shift + 0; // stop to shifting
end
end
if(hcnt<hsync) hd <= hsp; else hd <= !hsp;
if(vcnt<vsync) vd <= vsp; else vd <= !vsp;
if(hsync+hbp<=hcnt && hcnt<hsync+hbp+hdata && vsync+vbp<=vcnt && vcnt<vsync+vbp+vdata) begin
red <= (hcnt-hsync-hbp+shift)&8'hFF;
grn <= (vcnt-vsync-vbp+shift)&8'hFF;
blu <= (hcnt-hsync-hbp+vcnt-vsync-vbp-shift)&8'hFF;
den <= 1;
end
else begin
den <= 0;
end
end
endmodule
============= testpattern ここまで ===============
dvi_enc
testpatternを入力され、RGB各々の8/10変換をするところです.
HSYNC/VSYNCは、BLUE channelにのみ入力されます.
AUDIOは存在しません.
============= dvi_enc ここから ===============
module dvi_enc(input wire clk, en, xrst,
input wire [7:0] red_in,
input wire [7:0] grn_in,
input wire [7:0] blu_in,
input wire den_in, hd_in, vd_in,
output wire [29:0] tmds_out
);
wire [9:0] r,g,b;
assign tmds_out = {r,g,b};
tmds_enc ENC0(blu_in, hd_in, vd_in, den_in, clk, en, xrst, b);
tmds_enc ENC1(grn_in, 1'b0 , 1'b0 , den_in, clk, en, xrst, g);
tmds_enc ENC2(red_in, 1'b0 , 1'b0 , den_in, clk, en, xrst, r);
endmodule
============= dvi_enc ここまで ===============
tmds_enc
冒頭で引用したサイトからダウンロードしました.このmoduleについては一文字も変更してません.
dvi_enc.v
RGB用の8/10変換が実装されています.
SYNC用の2/10変換が実装されています.
AUDIOは伝送しないので、4/10変換は実装されていません.
それと、preambleとguard bandを発生する機能が在りません.HDMIはそれでも動くっていうことの証明かと思います.
制約ファイル
・ピン設定
・外付けXTAL=50MHzのタイミング設定
・マルチサイクルパス設定
をやっています.
マルチサイクルパス設定の意図は、clockに270MHzを与えているけど、27MHzで動けばOKなので制約を緩くする為です.クロックを一本化にこだわったのでこのような部分にしわ寄せが....
============= ここから ===============
NET "clki" LOC = "P129" |IOSTANDARD = LVCMOS33 | PERIOD = 20 ns HIGH 50%;NET "xrst" LOC = "P69" |IOSTANDARD = LVCMOS33 ;
NET "clkp" LOC = "P87" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "clkm" LOC = "P88" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "rp" LOC = "P91" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "rm" LOC = "P92" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "gp" LOC = "P93" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "gm" LOC = "P94" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "bp" LOC = "P96" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "bm" LOC = "P97" |IOSTANDARD = LVCMOS33 |DRIVE = 12 |SLEW = FAST ;
NET "LED<0>" LOC = "P52" |IOSTANDARD = LVCMOS33 |DRIVE = 8 |SLEW = SLOW ;
NET "LED<1>" LOC = "P53" |IOSTANDARD = LVCMOS33 |DRIVE = 8 |SLEW = SLOW ;
NET "LED<2>" LOC = "P54" |IOSTANDARD = LVCMOS33 |DRIVE = 8 |SLEW = SLOW ;
NET "LED<3>" LOC = "P58" |IOSTANDARD = LVCMOS33 |DRIVE = 8 |SLEW = SLOW ;
TIMESPEC TS_270MHz = PERIOD 3.7 ns HIGH 50%;
INST testpattern/* TNM = SOURCE1;
INST testpattern/* TNM = DESTINATION1;
TIMESPEC TS_TESTPATTERN = FROM SOURCE1 TO DESTINATION1 TS_270MHz*10;
INST dvi_enc/* TNM = SOURCE2;
INST dvi_enc/* TNM = DESTINATION2;
TIMESPEC TS_ENC = FROM SOURCE2 TO DESTINATION2 TS_270MHz*10;
============= ここまで ===============
文字を表示させたいならば、各位で実装をお願いします.
その5へ戻る
続くシリーズで、中華LCDパネルにHDMI-IFをつける試作を行いましたのでそちらも参考になるかもしれませんのでよろしく.
かしこ
0 件のコメント:
コメントを投稿