ようやくDDR2 SDRAM controllerのcore module のRTLが出来た。
作成しているcontrollerは以下のような構造になっている。
←この部分がcore moduleになる。
clock domain はbf_clk (bus i/f clock)、wr_clk系、rd_clk系の3つだ。
CMD QUEUE, WDT QUEUEは非同期FIFOでここでclockの乗換も兼ねている。非同期FIFOの為同期損が発生し、同期式の場合と比べてlatencyが増加してしまうが反面bus i/f側と異なる周波数に出来るので全体的な設計は容易になると考えている。また、非同期FIFOはPHY_DPにも存在する。これはread data用である。
BCはbank controllerだ。本設計ではbank単位でpage管理を行おうと考えているので4つある。CPはcommand path controllerでBCからのaccess要求を調停して勝者の要求を実効する。各BCからCPへの要求信号はhreqとlreqがあり、Bank ActiveやPrecharge等の要求はhreqに、readやwriteの要求はlreqに出す。信号名からも自明なようにhreqの方が優先度は高く、CPはhreqの方を優先して処理する。
また、単にmodule構成の話ではあるが、wr_clk, rd_clkを作るDCM部はcore module内に持つことにした。その構成は今のところ以下の方針でいこうと考えている。
dcm_srcで周波数を作り、dcm_wr, dcm_rdで位相を作る。
dcm_srcのfeed back pathはSpartan3A Starter KitではLOOP_OUTとLOOP_INというそれ用と思われる配線があるのでその経路を使うことにした。(Starter Kitのdemoの設計資料は回路図とUCFファイル以外は参照していない。)
まだ実機動作はおろか合成すらしていないのでもしかしたら修正になるかも知れないが。。。
Micronのweb siteからsimulation modelを入手してsimulationにも着手した。
これはbank0,1,2,3へのwriteが連続する場合だ。各bankのpageは閉じている状態から始めている。上述の通りBCからCPへの要求はhreqが優先されるため、各bankのactiveが連続して実行され、その後writeが連続して実行される。SD_DQ, SD_DMの初めの部分に不定がのっている(赤くなっている)のは非同期FIFO内のRAMの初期値が不定の為であり、設計不良によるものではない。
これは同一bankへの連続writeの場合だ。本設計の用途はframe bufferとしてのものなので上記のような各bankへのaccessが連続するよりも左のような単一bankへのaccessが連続する方がより現実的だろう。もちろん論理addressをDRAMのaddressにどう対応づけるかにもよるが。。。また、波形から、write latencyは12だ。(bank activeから始まる場合、bank がactiveな状態ではもっと少なくなる。)Command queueが同期FIFOであれば2cycle程度は減る筈だが上述のような理由のためやむを得ない。
これは同一bankからの連続readの場合だ。bankがactiveの状態で開始しているのでread latencyは最小の場合だ。波形から17だ。
readではCommand queue部の同期損にPHY_DP部の非同期FIFOの同期損が加わるためlatencyは悪化してしまう。また、上述のlatency値はcore moduleのみの値であるがaccessを要求する側から見れば、MULTI PORT I/F部のlatencyも加味されることになる。
2010年10月31日日曜日
2010年10月29日金曜日
神のBIN2BCD
BIN2BCDについてネットで検索していたら凄いのを見つけてしまった。
このサイトだ。 (※. リンク先のサイトが存在しなくなっていたのでリンクを削除しました。 2016.09.19)
ここに引用しておく。
~~ 引用ここから ~~
module bin2bcd_m16
(
input wire [15:0] bin_in, // binary number in
output wire [15:0] bcd_out // BCD digits out
);
reg [3:0] ones, tens, huns, thous;
integer i;
assign bcd_out[3:0] = ones;
assign bcd_out[7:4] = tens;
assign bcd_out[11:8] = huns;
assign bcd_out[15:12] = thous;
always @(*) begin
thous = 0;
huns = 0;
tens = 0;
ones = 0;
for(i=15; i>=0; i=i-1) begin
{thous, huns, tens, ones} = {thous[2:0],huns,tens,ones,bin_in[i]};
if(ones >= 5 && i > 0) ones = ones + 3;
if(tens >= 5 && i > 0) tens = tens + 3;
if(huns >= 5 && i > 0) huns = huns + 3;
if(thous >= 5 && i > 0) thous = thous + 3;
end
end
endmodule
なんと、これでBinaryからBCDへの変換が出来るようだ。
コーディングの仕方は教科書では決して推奨されないスタイルだけれども凄い。
こんなんでちゃんと合成できるんだろうか?
ISEで合成してみた。。
ちゃんと合成できた。
シミュレーションをしてみた。
テストベンチは以下のようにした。
RTLとP&R後のネットリストの両方に同じ値を入力して、テストベンチ内部で生成した期待値と両者の出力が一致するかを見ている。
`timescale 1ns/1ps
module tb;
reg clk;
reg [15:0] bin_in;
wire [15:0] bcd_rtl,bcd_map;
reg [3:0] d3,d2,d1,d0;
integer r,err;
bin2bcd_m16 i_rtl ( .bin_in (bin_in), .bcd_out(bcd_rtl));
bin2bcd_m16_map i_map ( .bin_in (bin_in), .bcd_out(bcd_map));
initial begin
clk = 0;
forever clk = #5 ~clk;
end
initial begin
bin_in = 0;
err = 0;
wait (!glbl.GSR);
@(posedge clk); #1;
@(posedge clk); #1;
for (bin_in = 0; bin_in < 10000; bin_in = bin_in + 1)
begin
@(posedge clk); #1;
d3 = bin_in / 1000;
r = bin_in % 1000;
d2 = r / 100;
r = r % 100;
d1 = r / 10;
d0 = r % 10;
if ((bcd_rtl !== {d3,d2,d1,d0}) ||
(bcd_map !== {d3,d2,d1,d0}) ||
(bcd_map !== bcd_rtl)) begin
$display("ERROR!!! in=%d,exp=%x->rtl=%x,map=%x",
bin_in,{d3,d2,d1,d0}, bcd_rtl, bcd_map);
err = err+1;
end else begin
$display("O K !!! in=%d,exp=%x->rtl=%x,map=%x",
bin_in,{d3,d2,d1,d0}, bcd_rtl, bcd_map);
end
end
if (err == 0)
$display("END OF SIMULATION WITH NO ERROR");
else
$display("END OF SIMULATION WITH %d ERROR(S)", err);
$finish;
end
endmodule
icarus verilogでsimulationした。
エラーなし!! 凄い!!
こういうアルゴリズムをサクッと創造できるようになりたいもんだ。
私にとってみると正に神のBIN2BCDだ。
すげ~、凄い、凄すぎます。きゃ~~興奮しちゃう。
私もDRAMCの作成を頑張ろう。
ここに引用しておく。
~~ 引用ここから ~~
module bin2bcd_m16
(
input wire [15:0] bin_in, // binary number in
output wire [15:0] bcd_out // BCD digits out
);
reg [3:0] ones, tens, huns, thous;
integer i;
assign bcd_out[3:0] = ones;
assign bcd_out[7:4] = tens;
assign bcd_out[11:8] = huns;
assign bcd_out[15:12] = thous;
always @(*) begin
thous = 0;
huns = 0;
tens = 0;
ones = 0;
for(i=15; i>=0; i=i-1) begin
{thous, huns, tens, ones} = {thous[2:0],huns,tens,ones,bin_in[i]};
if(ones >= 5 && i > 0) ones = ones + 3;
if(tens >= 5 && i > 0) tens = tens + 3;
if(huns >= 5 && i > 0) huns = huns + 3;
if(thous >= 5 && i > 0) thous = thous + 3;
end
end
endmodule
~~ 引用ここまで ~~
なんと、これでBinaryからBCDへの変換が出来るようだ。
コーディングの仕方は教科書では決して推奨されないスタイルだけれども凄い。
こんなんでちゃんと合成できるんだろうか?
ISEで合成してみた。。
ちゃんと合成できた。
シミュレーションをしてみた。
テストベンチは以下のようにした。
RTLとP&R後のネットリストの両方に同じ値を入力して、テストベンチ内部で生成した期待値と両者の出力が一致するかを見ている。
`timescale 1ns/1ps
module tb;
reg clk;
reg [15:0] bin_in;
wire [15:0] bcd_rtl,bcd_map;
reg [3:0] d3,d2,d1,d0;
integer r,err;
bin2bcd_m16 i_rtl ( .bin_in (bin_in), .bcd_out(bcd_rtl));
bin2bcd_m16_map i_map ( .bin_in (bin_in), .bcd_out(bcd_map));
initial begin
clk = 0;
forever clk = #5 ~clk;
end
initial begin
bin_in = 0;
err = 0;
wait (!glbl.GSR);
@(posedge clk); #1;
@(posedge clk); #1;
for (bin_in = 0; bin_in < 10000; bin_in = bin_in + 1)
begin
@(posedge clk); #1;
d3 = bin_in / 1000;
r = bin_in % 1000;
d2 = r / 100;
r = r % 100;
d1 = r / 10;
d0 = r % 10;
if ((bcd_rtl !== {d3,d2,d1,d0}) ||
(bcd_map !== {d3,d2,d1,d0}) ||
(bcd_map !== bcd_rtl)) begin
$display("ERROR!!! in=%d,exp=%x->rtl=%x,map=%x",
bin_in,{d3,d2,d1,d0}, bcd_rtl, bcd_map);
err = err+1;
end else begin
$display("O K !!! in=%d,exp=%x->rtl=%x,map=%x",
bin_in,{d3,d2,d1,d0}, bcd_rtl, bcd_map);
end
end
if (err == 0)
$display("END OF SIMULATION WITH NO ERROR");
else
$display("END OF SIMULATION WITH %d ERROR(S)", err);
$finish;
end
endmodule
icarus verilogでsimulationした。
エラーなし!! 凄い!!
こういうアルゴリズムをサクッと創造できるようになりたいもんだ。
私にとってみると正に神のBIN2BCDだ。
すげ~、凄い、凄すぎます。きゃ~~興奮しちゃう。
私もDRAMCの作成を頑張ろう。
2010年10月27日水曜日
BIN2BCD
ブログFPGAの部屋の今日の記事は2進数からBCDへの変換回路だった。
おもしろそうなので、私も検討してみた。
私の場合はこうするかな?
module bin2bcd (clk, bin, bcd);
input clk;
input [ 9:0] bin;
output [15:0] bcd;
wire [13:0] k3;
reg [13:0] k3b;
reg [ 3:0] d32;
reg [ 3:0] d31;
reg [ 3:0] d30;
wire [13:0] k2;
reg [13:0] k2b;
reg [ 3:0] d21;
reg [ 3:0] d20;
wire [13:0] k1;
reg [ 3:0] d10;
reg [ 3:0] d00;
assign k3 = bin + bin[9:6] + bin[9:7] + bin[9] + 1'b1;
always @(posedge clk) d32 <= k3[13:10];
always @(posedge clk) k3b <= bin - (k3[13:10] * 1000);
assign k2 = k3b * 10 + k3b[13:2];
always @(posedge clk) d21 <= k2[13:10];
always @(posedge clk) k2b <= k3b - (k2[13:10] * 100);
always @(posedge clk) d31 <= d32;
assign k1 = k2b * 102 + k2b[13:1];
always @(posedge clk) d00 <= k2b - (k1[13:10] * 10);
always @(posedge clk) d10 <= k1[13:10];
always @(posedge clk) d20 <= d21;
always @(posedge clk) d30 <= d31;
assign bcd = {d30,d20,d10,d00};
endmodule
パイプライン式でLatencyは3だけど乗算部が5つもある。
y = -ax+b , y = a x+b部を1つにしてステートマシンで回すようにすればもう少しコンパクトにできるかも知れないな。
2010年10月26日火曜日
PHY部の検討
DDR2 SDRAM CONTROLLERのPHY部に検討を行っている。
Spartan3AはIDELAYを持っているが、IOB内部のF/Fを使用する場合は4tapしか使えず自由度が低い。Spartan3Aではread dataの取り込みはDQSの位相をずらして使用するのではなく、DCMでCapture用のclockを生成して使うのが作法のようだ。その作法に則って設計することにしよう。
Write系のData pathは以下のようにした。
//--------------------------------------------------------------------------------
// circuit description
//--------------------------------------------------------------------------------
OBUF i_obuf_dm [(PHYDMW/2)-1:0] (
.O( DM ),
.I( dmo )
);
IOBUF i_iobuf_dq [(PHYDW/2)-1:0] (
.IO( DQ ),
.O ( dqi),
.I ( dqo),
.T ( oen)
);
IOBUFDS i_iobufds_dqs [(PHYDW/16)-1:0] (
.IO ( DQS_P),
.IOB( DQS_N),
.O ( dqsi ),
.I ( dqso ),
.T ( oen )
) ;
//--------------------------------------------------------------------------------
// write
//--------------------------------------------------------------------------------
/*********************************************************************************
tx_clk_270 ~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|_
tx_clk_180 |___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___
tx_clk_90 __|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~
tx_clk ___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~
: : : : : : : : : : : : : : : : : : : : : : : : : :
dp_ten ____/~~~~~~~~~~~~~~~~\_________________________________
dp_ten_1d __________/~~~~~~~~~~~~~~~~\_________________________
ten_pd __________________/~~~~~~~~~~~~~~~~\_________________
ten_nd ________________/~~~~~~~~~~~~~~~~\___________________
: : : : : : : : : : : : : : : : : : : : : : : : : :
oen __________/~~~~~~~~~~~~~~~~~~~~~~~~\_________________
dqso_en __________/~~~~~~~~~~~~~~~~~~~~~~\___________________
DQS ----------_______|~~~|___|~~~|_____------------------
: : : : : : : : : : : : : : : : : : : : : : : : : :
tx_clk_90 __|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~
___ _______ _______ _______ _______ _______ _______ __
dp_wd ___X__Va___X__Vb___X_______X_______X_______X_______X__
______ _______ _______ _______ _______ _______ ______
wd_180 ______X__Va___X__Vb___X_______X_______X_______X______
____ _______ _______ _______ _______ _______ _______
wd_90 ____X_______X___Va__X__Vb___X_______X_______X_______X
___ ___ ___ ___
DQ -----------#####X_a_X_a_X_b_X_b_X####-----------------
: : : : : : : : : : : : : : : : : : : : : : : : : :
___ ___ ___ ___
DQ -----------#####X_a_X_a_X_b_X_b_X####-----------------
: : : : : : : : : : : : : : : : : : : : : : : : : :
DQS ----------_______|~~~|___|~~~|_____------------------
latency = 2
*********************************************************************************/
FDC i_ten_1d (.C(tx_clk ),.D(dp_ten ),.Q(dp_ten_1d),.CLR(tx_rst));
FDC i_ten_pd (.C(tx_clk ),.D(dp_ten_1d),.Q(ten_pd ),.CLR(tx_rst));
FDC i_ten_nd (.C(tx_clk_270),.D(dp_ten_1d),.Q(ten_nd ),.CLR(tx_rst));
NOR2 i_nor_oen (.I0(ten_pd), .I1(dp_ten_1d), .O(oen ));
NOR2 i_nor_dqso_en (.I0(ten_nd), .I1(dp_ten_1d), .O(dqso_en));
OR2 i_or_dqo_en (.I0(ten_nd), .I1(dp_ten_1d), .O(dqo_en));
ODDR2 #(
.DDR_ALIGNMENT( "NONE" ),
.INIT ( 1'b0 ),
.SRTYPE ( "ASYNC" )
) i_oddr_dqso [(PHYDW/16)-1:0] (
.CE ( 1'b1 ),
.R ( dqso_en ),
.S ( 1'b0 ),
.Q ( dqso ),
.C0 ( tx_clk_180 ),
.C1 ( tx_clk ),
.D1 ( 1'b1 ),
.D0 ( 1'b0 )
);
FD i_fd_wd_180 [PHYDW-1 :0] (.C(tx_clk_180), .D(dp_wd ), .Q(wd_180 ));
FD i_fd_wdm_180 [PHYDMW-1:0] (.C(tx_clk_180), .D(dp_wdm ), .Q(wdm_180));
FD i_fd_wd_90 [PHYDW-1 :0] (.C(tx_clk_90 ), .D(wd_180 ), .Q(wd_90 ));
FD i_fd_wdm_90 [PHYDMW-1:0] (.C(tx_clk_90 ), .D(wdm_180), .Q(wdm_90 ));
ODDR2 # (
.DDR_ALIGNMENT( "NONE" ),
.INIT ( 1'b0 ),
.SRTYPE ( "ASYNC" )
) i_dqo_ddr[(PHYDW/2)-1:0] (
.CE ( dqo_en ),
.R ( 1'b0 ),
.S ( 1'b0 ),
.Q ( dqo ),
.C0 ( tx_clk_270 ),
.D0 ( wd_90[ 7:0] ),
.C1 ( tx_clk_90 ),
.D1 ( wd_90[15:8] )
) ;
ODDR2 # (
.DDR_ALIGNMENT( "NONE" ),
.INIT ( 1'b0 ),
.SRTYPE ( "ASYNC" )
) i_dmo_ddr [(PHYDMW/2)-1:0] (
.CE ( dqo_en ),
.R ( 1'b0 ),
.S ( 1'b0 ),
.Q ( dmo ),
.C0 ( tx_clk_270 ),
.C1 ( tx_clk_90 ),
.D1 ( wdm_90[1] ),
.D0 ( wdm_90[0] )
) ;
また、Read系は以下だ。
//--------------------------------------------------------------------------------
// read
//--------------------------------------------------------------------------------
IDDR2 #(
.DDR_ALIGNMENT( "NONE" ),
.SRTYPE ( "ASYNC" ),
.INIT_Q0 ( 1'b0 ),
.INIT_Q1 ( 1'b0 )
)
i_ddr [(PHYDW/2)-1:0] (
.C0 ( rx_clk_180 ),
.C1 ( rx_clk ),
.D ( dqi ),
.Q1 ( dqip ),
.Q0 ( dqin ),
.CE ( 1'b1 ),
.S ( 1'b0 ),
.R ( 1'b0 )
);
wire dp_ren_dly;
FDC i_ren_dly1 (.C (rx_clk),.D(dp_ren),.Q(dp_ren_dly),.CLR(rx_rst));
FDC i_ren_dly2 (.C (rx_clk),.D(dp_ren_dly),.Q(af_wen),.CLR(rx_rst));
afifo #(.DW(PHYDW), .AW(3)) i_asq (
.wclk (rx_clk ),
.wrst (tx_rst ),
.full (/* open */ ),
.amfull (/* open */ ),
.wen (af_wen ),
.wdt ({dqin,dqip}),
.rclk (bf_clk ),
.rrst (bf_rst ),
.empty (asq_empty ),
.ren (dp_rd_rdy ),
.rdt (pd_rd )
);
INV i_vld (.I(asq_empty),.O(pd_rd_vld));
Icarus Verilogでsimulationを行った。
Write系
Read系は上記Write dataを折り返して確認した。
Spartan3AはIDELAYを持っているが、IOB内部のF/Fを使用する場合は4tapしか使えず自由度が低い。Spartan3Aではread dataの取り込みはDQSの位相をずらして使用するのではなく、DCMでCapture用のclockを生成して使うのが作法のようだ。その作法に則って設計することにしよう。
Write系のData pathは以下のようにした。
//--------------------------------------------------------------------------------
// circuit description
//--------------------------------------------------------------------------------
OBUF i_obuf_dm [(PHYDMW/2)-1:0] (
.O( DM ),
.I( dmo )
);
IOBUF i_iobuf_dq [(PHYDW/2)-1:0] (
.IO( DQ ),
.O ( dqi),
.I ( dqo),
.T ( oen)
);
IOBUFDS i_iobufds_dqs [(PHYDW/16)-1:0] (
.IO ( DQS_P),
.IOB( DQS_N),
.O ( dqsi ),
.I ( dqso ),
.T ( oen )
) ;
//--------------------------------------------------------------------------------
// write
//--------------------------------------------------------------------------------
/*********************************************************************************
tx_clk_270 ~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|_
tx_clk_180 |___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___
tx_clk_90 __|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~
tx_clk ___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~
: : : : : : : : : : : : : : : : : : : : : : : : : :
dp_ten ____/~~~~~~~~~~~~~~~~\_________________________________
dp_ten_1d __________/~~~~~~~~~~~~~~~~\_________________________
ten_pd __________________/~~~~~~~~~~~~~~~~\_________________
ten_nd ________________/~~~~~~~~~~~~~~~~\___________________
: : : : : : : : : : : : : : : : : : : : : : : : : :
oen __________/~~~~~~~~~~~~~~~~~~~~~~~~\_________________
dqso_en __________/~~~~~~~~~~~~~~~~~~~~~~\___________________
DQS ----------_______|~~~|___|~~~|_____------------------
: : : : : : : : : : : : : : : : : : : : : : : : : :
tx_clk_90 __|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~~~|___|~
___ _______ _______ _______ _______ _______ _______ __
dp_wd ___X__Va___X__Vb___X_______X_______X_______X_______X__
______ _______ _______ _______ _______ _______ ______
wd_180 ______X__Va___X__Vb___X_______X_______X_______X______
____ _______ _______ _______ _______ _______ _______
wd_90 ____X_______X___Va__X__Vb___X_______X_______X_______X
___ ___ ___ ___
DQ -----------#####X_a_X_a_X_b_X_b_X####-----------------
: : : : : : : : : : : : : : : : : : : : : : : : : :
___ ___ ___ ___
DQ -----------#####X_a_X_a_X_b_X_b_X####-----------------
: : : : : : : : : : : : : : : : : : : : : : : : : :
DQS ----------_______|~~~|___|~~~|_____------------------
latency = 2
*********************************************************************************/
FDC i_ten_1d (.C(tx_clk ),.D(dp_ten ),.Q(dp_ten_1d),.CLR(tx_rst));
FDC i_ten_pd (.C(tx_clk ),.D(dp_ten_1d),.Q(ten_pd ),.CLR(tx_rst));
FDC i_ten_nd (.C(tx_clk_270),.D(dp_ten_1d),.Q(ten_nd ),.CLR(tx_rst));
NOR2 i_nor_oen (.I0(ten_pd), .I1(dp_ten_1d), .O(oen ));
NOR2 i_nor_dqso_en (.I0(ten_nd), .I1(dp_ten_1d), .O(dqso_en));
OR2 i_or_dqo_en (.I0(ten_nd), .I1(dp_ten_1d), .O(dqo_en));
ODDR2 #(
.DDR_ALIGNMENT( "NONE" ),
.INIT ( 1'b0 ),
.SRTYPE ( "ASYNC" )
) i_oddr_dqso [(PHYDW/16)-1:0] (
.CE ( 1'b1 ),
.R ( dqso_en ),
.S ( 1'b0 ),
.Q ( dqso ),
.C0 ( tx_clk_180 ),
.C1 ( tx_clk ),
.D1 ( 1'b1 ),
.D0 ( 1'b0 )
);
FD i_fd_wd_180 [PHYDW-1 :0] (.C(tx_clk_180), .D(dp_wd ), .Q(wd_180 ));
FD i_fd_wdm_180 [PHYDMW-1:0] (.C(tx_clk_180), .D(dp_wdm ), .Q(wdm_180));
FD i_fd_wd_90 [PHYDW-1 :0] (.C(tx_clk_90 ), .D(wd_180 ), .Q(wd_90 ));
FD i_fd_wdm_90 [PHYDMW-1:0] (.C(tx_clk_90 ), .D(wdm_180), .Q(wdm_90 ));
ODDR2 # (
.DDR_ALIGNMENT( "NONE" ),
.INIT ( 1'b0 ),
.SRTYPE ( "ASYNC" )
) i_dqo_ddr[(PHYDW/2)-1:0] (
.CE ( dqo_en ),
.R ( 1'b0 ),
.S ( 1'b0 ),
.Q ( dqo ),
.C0 ( tx_clk_270 ),
.D0 ( wd_90[ 7:0] ),
.C1 ( tx_clk_90 ),
.D1 ( wd_90[15:8] )
) ;
ODDR2 # (
.DDR_ALIGNMENT( "NONE" ),
.INIT ( 1'b0 ),
.SRTYPE ( "ASYNC" )
) i_dmo_ddr [(PHYDMW/2)-1:0] (
.CE ( dqo_en ),
.R ( 1'b0 ),
.S ( 1'b0 ),
.Q ( dmo ),
.C0 ( tx_clk_270 ),
.C1 ( tx_clk_90 ),
.D1 ( wdm_90[1] ),
.D0 ( wdm_90[0] )
) ;
また、Read系は以下だ。
//--------------------------------------------------------------------------------
// read
//--------------------------------------------------------------------------------
IDDR2 #(
.DDR_ALIGNMENT( "NONE" ),
.SRTYPE ( "ASYNC" ),
.INIT_Q0 ( 1'b0 ),
.INIT_Q1 ( 1'b0 )
)
i_ddr [(PHYDW/2)-1:0] (
.C0 ( rx_clk_180 ),
.C1 ( rx_clk ),
.D ( dqi ),
.Q1 ( dqip ),
.Q0 ( dqin ),
.CE ( 1'b1 ),
.S ( 1'b0 ),
.R ( 1'b0 )
);
wire dp_ren_dly;
FDC i_ren_dly1 (.C (rx_clk),.D(dp_ren),.Q(dp_ren_dly),.CLR(rx_rst));
FDC i_ren_dly2 (.C (rx_clk),.D(dp_ren_dly),.Q(af_wen),.CLR(rx_rst));
afifo #(.DW(PHYDW), .AW(3)) i_asq (
.wclk (rx_clk ),
.wrst (tx_rst ),
.full (/* open */ ),
.amfull (/* open */ ),
.wen (af_wen ),
.wdt ({dqin,dqip}),
.rclk (bf_clk ),
.rrst (bf_rst ),
.empty (asq_empty ),
.ren (dp_rd_rdy ),
.rdt (pd_rd )
);
INV i_vld (.I(asq_empty),.O(pd_rd_vld));
Icarus Verilogでsimulationを行った。
Write系
Read系は上記Write dataを折り返して確認した。
2010年10月22日金曜日
2010年10月21日木曜日
色味の調整3
2010年10月20日水曜日
調整用プログラム
調整用プログラムをwxWidgetsで作った。
カラーバーの画面を見ながら各スライダーを動かして最適ポイントに合わせようというスンポウだ。
が、中々最適ポイントにならない。
←は一見ばらつきも少なくいい感じのように見えるが、FPGA内部で生成したパターンよりも振幅が大きくサチってる感じだ。
カメラのテストパターンをRamp2にして見ると左の通りでやはり飽和していた。
カラーバーの画面を見ながら各スライダーを動かして最適ポイントに合わせようというスンポウだ。
が、中々最適ポイントにならない。
←は一見ばらつきも少なくいい感じのように見えるが、FPGA内部で生成したパターンよりも振幅が大きくサチってる感じだ。
カメラのテストパターンをRamp2にして見ると左の通りでやはり飽和していた。
2010年10月19日火曜日
色味の調整2
R,G,B各成分の振幅をグラフ表示するようにしてみた。
← 横一直線に並んでいるのはFPGAで生成したカラーバーのもの。上下に散らばっているのはカメラのカラーバーだ。
この画面を見ながらカメラのレジスタ値を調整していけば判りやすいのではないかと考えているが。。。旨くいくかな?
← 横一直線に並んでいるのはFPGAで生成したカラーバーのもの。上下に散らばっているのはカメラのカラーバーだ。
この画面を見ながらカメラのレジスタ値を調整していけば判りやすいのではないかと考えているが。。。旨くいくかな?
2010年10月18日月曜日
色味の調整
色味の調整を試行している。
TCM8230MDはテストパターンの出力機能を内蔵していて、0x1E番地のレジスタのTESPIC, PICSELビットで機能のON/OFFと出力パターンの選択が出来る。出力パターンとしてはColorbar、Ramp1、Ramp2の3パターンだ。この中からカラーバーを出力するようにして、FPGA内部で生成したカラーバーとの色味を比べながら調整できないか試してみている。
dvi_encの出力サイズをVGAにし、カメラデータを切取る矩形サイズを512x27にして容易に比較できるようにした。
←この部分がカメラから取り込んだカラーバーだ。
微妙にというべきかかなりと言うべきか、色味が違う。
色境界部の変色も気になるが、とりあえずここでは置いておく。
0x18番地のSATU (SATURATION か?)レジスタの値を初期値の0x27から0x4Eにしてみた。
次にVHUE (0x13), UHUE(0x14), VGAIN(0x15), UGAIN(0x16)レジスタの値も振ってみよう。これらのレジスタの設定値はGAMSW (0x0D) をOFFにしないと有効にならないようだ。
何れにしても今のやり方だと効率が悪いので、もっと簡単に調整できるよう工夫が必要だな。
TCM8230MDはテストパターンの出力機能を内蔵していて、0x1E番地のレジスタのTESPIC, PICSELビットで機能のON/OFFと出力パターンの選択が出来る。出力パターンとしてはColorbar、Ramp1、Ramp2の3パターンだ。この中からカラーバーを出力するようにして、FPGA内部で生成したカラーバーとの色味を比べながら調整できないか試してみている。
dvi_encの出力サイズをVGAにし、カメラデータを切取る矩形サイズを512x27にして容易に比較できるようにした。
←この部分がカメラから取り込んだカラーバーだ。
微妙にというべきかかなりと言うべきか、色味が違う。
色境界部の変色も気になるが、とりあえずここでは置いておく。
0x18番地のSATU (SATURATION か?)レジスタの値を初期値の0x27から0x4Eにしてみた。
次に0x13にしてみた。
黄色は近くなったけど他は逆に遠ざかってしまった。。
次にVHUE (0x13), UHUE(0x14), VGAIN(0x15), UGAIN(0x16)レジスタの値も振ってみよう。これらのレジスタの設定値はGAMSW (0x0D) をOFFにしないと有効にならないようだ。
何れにしても今のやり方だと効率が悪いので、もっと簡単に調整できるよう工夫が必要だな。
2010年10月17日日曜日
動き始めたぞっと
ハンダ付け作業も一通り終わり、動作確認に着手した。
まずは起動直後のレジスタ値を読んでみた。
0x00, 0x01, 0x2B, 0x2D, 0x32, 0x33, 0x34, 0x36, 0x37の値がデータシートと異なっているが、これらがどういうレジスタなのかは現時点では不明。
次にいよいよ撮像確認だが、このカメラのフレームレートは30fpsであるため例えディスプレイ出力をVGAモードにしたとしてもカメラのデータをスルーして出力することは出来ない。フレームバッファを介する必要がある。現状まだSDRAMコントローラの実装はしていないため、FPGAの内部RAMをフレームバッファとして使うことにした。容量の制約から128x110分とし、カメラの撮像データを切り出して格納・表示するようにした。
←撮影対象
まずは起動直後のレジスタ値を読んでみた。
0x00, 0x01, 0x2B, 0x2D, 0x32, 0x33, 0x34, 0x36, 0x37の値がデータシートと異なっているが、これらがどういうレジスタなのかは現時点では不明。
次にいよいよ撮像確認だが、このカメラのフレームレートは30fpsであるため例えディスプレイ出力をVGAモードにしたとしてもカメラのデータをスルーして出力することは出来ない。フレームバッファを介する必要がある。現状まだSDRAMコントローラの実装はしていないため、FPGAの内部RAMをフレームバッファとして使うことにした。容量の制約から128x110分とし、カメラの撮像データを切り出して格納・表示するようにした。
←撮影対象
撮像データのフォーマットはRGB565、CODEはNormalにしている。
撮影対象の写真と比べると色が薄いというか白っぽい。
レジスタで調整できるのかなぁ?
それっぽい名前のレジスタの設定を色々変えてみようか。
YUV422も試してみよう。
現状のレジスタ設定はデータフォーマットや出力コード設定等のみで、
画質に関わるようなレジスタは触っていない。
現在の設定
main()
{
fpga_open();
reg_wrt(0x02,0x40,0);//FPS:30fps, ACF:60Hz, DCLKP:NORMAL, ACFDET:AUTO
reg_wrt(0x03,0x02,0);//DOUTSW:ON, DATA:OUT, PICSIZ:VGA,
PICFMT:RGB565, CM:COLOR
reg_wrt(0x1e,0x68,0);//D_MASK:01, CODESW:OUT, CODESEL:NORMAL,
// HSYNCSEL:NORMAL, TESPIC:Not out, PICSEL:Colorbar
fpga_close();
}
2010年10月14日木曜日
2010年10月13日水曜日
2010年10月11日月曜日
UARTとI2C モジュールの作成
カメラは再度購入することにした。
カメラコントローラのデバッグ時にI2Cコントローラが必要になる。また、その制御は最初のうちはUART経由でPCから行うことになる。そこで、物が入手できるまでこれらコントローラの作成を行うことにした。
- 通信フレーム
PC - FPGA間の通信は以下のような通信フレームで行う。
FPGAはcommand frameに対してACK(受信成功時), NAK(受信失敗時)応答を返す。
// UART I/F
//
// [frame format]
//
// *command frame (PC -> FPGA)
// +---+---+---+---+---+---+---+---+
// |STX|CMD| B3| B2| B1| B0|ETX|SUM|
// +---+---+---+---+---+---+---+---+
//
// command_frame := {STX, CMD, B3, B2,
// B1, B0, ETX, SUM}
// STX := 0x02
// CMD := {cmd_rw, cmd_addr[6:0]}
// B3 := cmd_data[31:24]
// B2 := cmd_data[23:16]
// B1 := cmd_data[15: 8]
// B0 := cmd_data[ 7: 0]
// ETX := 0x03
// SUM := sum[7:0]
// sum = STX + CMD + B3 + B2
// + B1 + B0 + ETX
//
// *response data (FPGA -> PC)
// |STX|TYP| B3| B2| B1| B0|ETX|SUM|
// +---+---+---+---+---+---+---+---+
//
// response_frame := {STX, TYP, B3, B2,
// B1, B0, ETX, SUM}
// STX := 0x02
// TYPE := rd_typ[7:0]
// B3 := rd_data[31:24]
// B2 := rd_data[23:16]
// B1 := rd_data[15: 8]
// B0 := rd_data[ 7: 0]
// ETX := 0x03
// SUM := sum[7:0]
// sum = STX + CMD + B3 + B2
// + B1 + B0 + ETX
//
カメラコントローラのデバッグ時にI2Cコントローラが必要になる。また、その制御は最初のうちはUART経由でPCから行うことになる。そこで、物が入手できるまでこれらコントローラの作成を行うことにした。
- 通信フレーム
PC - FPGA間の通信は以下のような通信フレームで行う。
FPGAはcommand frameに対してACK(受信成功時), NAK(受信失敗時)応答を返す。
// UART I/F
//
// [frame format]
//
// *command frame (PC -> FPGA)
// +---+---+---+---+---+---+---+---+
// |STX|CMD| B3| B2| B1| B0|ETX|SUM|
// +---+---+---+---+---+---+---+---+
//
// command_frame := {STX, CMD, B3, B2,
// B1, B0, ETX, SUM}
// STX := 0x02
// CMD := {cmd_rw, cmd_addr[6:0]}
// B3 := cmd_data[31:24]
// B2 := cmd_data[23:16]
// B1 := cmd_data[15: 8]
// B0 := cmd_data[ 7: 0]
// ETX := 0x03
// SUM := sum[7:0]
// sum = STX + CMD + B3 + B2
// + B1 + B0 + ETX
//
// *response data (FPGA -> PC)
// response := ACK | NAK
// ACK := 0x06
// NAK := 0x15
//
// *readback frame (FPGA -> PC)
// +---+---+---+---+---+---+---+---+
// +---+---+---+---+---+---+---+---+
//
// response_frame := {STX, TYP, B3, B2,
// B1, B0, ETX, SUM}
// STX := 0x02
// TYPE := rd_typ[7:0]
// B3 := rd_data[31:24]
// B2 := rd_data[23:16]
// B1 := rd_data[15: 8]
// B0 := rd_data[ 7: 0]
// ETX := 0x03
// SUM := sum[7:0]
// sum = STX + CMD + B3 + B2
// + B1 + B0 + ETX
//
I2Cコントローラはシングルアクセスのみサポートとしたが、連続アクセスにも容易に変更できる構造にした。
出来上がったUART, I2Cコントローラと以下のプログラムでSpartan3A Starter Kitの電源IC LP3906のレジスタ(LDO1VCR, LDO2VCR)をリードしてみた。
Starter Kitの回路図によればLDO1は3.3V(レジスタ値はデータシートによれば0x17), LDO2は1.8V(同0x08)なので、正しくリードできている。
(今回作成したI2CとUARTモジュールはここで公開している。)
(今回作成したI2CとUARTモジュールはここで公開している。)
2010年10月9日土曜日
作業開始!!
さあ、作業開始だ。
リード線のハンダ付けは肉眼で見ながら行うのは困難なため、ルーペを見ながら行っている。このルーペは古道具屋さんで買ったステージ用の照明器具を改造したものだ。
このカメラモジュールの裏側にパッドがあるが、外周にもパッドへの接続用のviaが配置されている。但しviaの中央から基板をカットしているのでviaは半分(半円)のみ残っている。リード線のハンダ付けはこのvia部分に行っている。
オーマイガッ!!
ようやくリード線のハンダ付けが終わったと思ったのも床の間、いや、束の間、リード線の反対側の接続作業を行おうとしたらviaの銅箔ごと剥離してしまった。
予備を買っとくんだった。。 (;_;)
なんとかならんかなぁ~
登録:
投稿 (Atom)
ERROR: Failed to spawn fakeroot worker to run ...
なにかと忙しくてなかなか趣味の時間を確保できない。 ...orz 家の開発機のOSはLinux Mintなのだが、最近バージョンを22に更新したところ、myCNC用のpetalinuxをビルドできなくなってしまった。ビルドの途中で ERROR: Failed to spawn ...
-
ZYBOでLinuxを動かし、その上で X Windowを立ち上げ X アプリを動作させることが出来た。 以下はgnome-terminalとgnome-system-monitorを起動しgnome-screenshotで撮ったscreenshotだ。 これまでDFT ...
-
FT232RというUSB-UART変換ICがある。このICにはBit Bang Modeという機能があって、UART用の端子がGPIO的制御が可能になる。 FT232Rを搭載したUSB-UART変換基板は秋月電子やマルツパーツ等色んなところで売られていて私もSparkfunのF...