« 持ち運び便利なミューオン検出器 | トップページ | FPGAや回路設計をしてくれるスタッフ(社員・アルバイト)募集しています »

2015.06.20

Kintex-7でDDR3 SD-DIMMを使う

いま受託でやっている仕事で、Kintex-7にDDR3のSO-DIMMをつないで読み書きしようとしています。

ISEとCoreGenの環境でやっているのですが、なかなかうまく動いてくれません。

CoreGenでSODIMMを選択すると、なぜか最後までインプリメントが通らないで、とりあえず単一のDDR3メモリを選択して、SODIMMの8分の1だけ動かそうとしています。

まず最初の設定画面。AXI4を選択しておきます。

AXI4を使わないapp何とかという信号を操作する使い方だと、最高性能が出せるけどポートは1つだし自分でユーザクロックとの同期とかしなければならず、面倒です。

AXI4にするとその辺の面倒なことは全部コアがやってくれます。

K7ddr3_1

次。ここが肝心。

まず、ここで設定する速度はDDR3メモリに行くクロックの速度。ここで800MHzと指定したらDDRのレートはクロックの倍の1600Mb/sになります。とりあえず控えめの500MHzにしました。これならDDRメモリのレートは1Gb/sになるはず。

4:1という設定は重要ですが、このままにしておきます。

K7ddr3_2

その次の設定画面。

データバスの幅はDDR3メモリの幅の8倍だから、これでよい。この画面では特に変更なし。

K7ddr3_3

次の設定画面。ここが超重要!

Input Clock Periodというのは、おそらくコアのsys_clkのクロックのことですが、これをメモリクロックの4分の1にします。4分の1というのは、前の設定で4:1にしたから。

DDRのレートはクロックの倍だから、メモリの速度が1000Mb/sなら、ユーザインタフェースの速度は8分の1になって、データバスは8倍の幅になる、と考えるとつじつまが合います。

この関係をstrictに保たないと、何だかAXIコアが途中で止まってしまうようです。

(AXIコアが途中で止まるという現象で2週間ほど悩みました)

それ以外の設定は特に変更なし。

K7ddr3_4

その次の設定も重要。ClockをNoBufferにしたのは、自分で作ったデザインの中にあるMMCMからクロックを供給するためです。基板上のオシレータからMRCCのピンを通して直接MIGのコアに入れるならば設定は変わってくるでしょう。

IO Power ReductionはOFFにすると、エラーが出て途中で止まる。

XADCを使うと、FPGAの温度を測って、再キャリブレーションとかデータアイの中央に合わせるだとか、そういうことをやってくれるらしい。でも、現在の基板でXADCはVREFPをGNDにつないでしまったのでXADCが使えないので、これはOFFにする。

※XADCをDisableにすると、device_temp_iという信号を自分で与えなければならなくなる。とりあえず2509という数値を12bitで与えることにしている。これは40℃前後を示す値だったはず。

K7ddr3_5

インプリメントするときは、こんな感じ。

	inst_axi_ddr : axi_ddr3 port map (
		ddr3_dq         => ddr3_dq,
		ddr3_dqs_n      => ddr3_dqs_n,
		ddr3_dqs_p      => ddr3_dqs_p,
	-- Outputs
		ddr3_addr       => ddr3_addr,
		ddr3_ba         => ddr3_ba,
		ddr3_ras_n      => ddr3_ras_n,
		ddr3_cas_n      => ddr3_cas_n,
		ddr3_we_n       => ddr3_we_n,
		ddr3_cs_n       => ddr3_cs_n,
		ddr3_reset_n    => ddr3_reset_n,
		ddr3_ck_p       => ddr3_ck_p,
		ddr3_ck_n       => ddr3_ck_n,
		ddr3_cke        => ddr3_cke,
		ddr3_dm         => ddr3_dm,
		ddr3_odt        => ddr3_odt,
	-- Inputs
	-- Single-ended system clock
        sys_clk_i       => clk125m,
        clk_ref_i       => clk200m,        
		ui_clk          => ui_clk,
		ui_clk_sync_rst => ui_clk_sync_rst,
        mmcm_locked     => mmcm_locked,
		aresetn         => aresetn,
		app_sr_req      => app_sr_req,
		app_sr_active   => app_sr_active,
		app_ref_req     => app_ref_req,
		app_ref_ack     => app_ref_ack,
		app_zq_req      => app_zq_req,
		app_zq_ack      => app_zq_ack,
	-- Slave Interface Write Address Ports
		s_axi_awid      => ddr_axi_awid,
		s_axi_awaddr    => ddr_axi_awaddr,
		s_axi_awlen     => ddr_axi_awlen,
		s_axi_awsize    => ddr_axi_awsize,
		s_axi_awburst   => ddr_axi_awburst,
		s_axi_awlock    => ddr_axi_awlock,
		s_axi_awcache   => ddr_axi_awcache,
		s_axi_awprot    => ddr_axi_awprot,
		s_axi_awqos     => ddr_axi_awqos,
		s_axi_awvalid   => ddr_axi_awvalid,
		s_axi_awready   => ddr_axi_awready,
	-- Slave Interface Write Data Ports
		s_axi_wdata     => ddr_axi_wdata,
		s_axi_wstrb     => ddr_axi_wstrb,
		s_axi_wlast     => ddr_axi_wlast,
		s_axi_wvalid    => ddr_axi_wvalid,
		s_axi_wready    => ddr_axi_wready,
	-- Slave Interface Write Response Ports
		s_axi_bready    => ddr_axi_bready,
		s_axi_bid       => ddr_axi_bid,
		s_axi_bresp     => ddr_axi_bresp,
		s_axi_bvalid    => ddr_axi_bvalid,
	-- Slave Interface Read Address Ports
		s_axi_arid      => ddr_axi_arid,
		s_axi_araddr    => ddr_axi_araddr,
		s_axi_arlen     => ddr_axi_arlen,
		s_axi_arsize    => ddr_axi_arsize,
		s_axi_arburst   => ddr_axi_arburst,
		s_axi_arlock    => ddr_axi_arlock,
		s_axi_arcache   => ddr_axi_arcache,
		s_axi_arprot    => ddr_axi_arprot,
		s_axi_arqos     => ddr_axi_arqos,
		s_axi_arvalid   => ddr_axi_arvalid,
		s_axi_arready   => ddr_axi_arready,
	-- Slave Interface Read Data Ports
		s_axi_rready    => ddr_axi_rready,
		s_axi_rid       => ddr_axi_rid,
		s_axi_rdata     => ddr_axi_rdata,
		s_axi_rresp     => ddr_axi_rresp,
		s_axi_rlast     => ddr_axi_rlast,
		s_axi_rvalid    => ddr_axi_rvalid,
		
	-- System reset - Default polarity of sys_rst pin is Active Low.
	-- System reset polarity will change based on the option 
	-- selected in GUI.
		init_calib_complete => init_calib_complete,
		device_temp_i       => conv_std_logic_vector(2509,12),
		sys_rst             => sys_rst_n
	);

リセットが2つありますよね。sys_rst_nは、コアのリセット。aresetnはAXIのリセットです。

sys_rst_nを解除してからしばらく(16クロックでいいという話があるが、私はms単位待たせている)経ってからaresetnを解除します。

クロックはui_clk。ユーザ側ステートマシンはui_clkで動くようにする。ui_clkの速度は、メモリクロックの4分の1。つまり、↑の設定では125MHzになります。

これで何とかDDR3メモリが動くようになりました。

Kintex_ddr3

でも、XORSHIFTを使って作った乱数を読み書きしてみると、たまにリードエラーが発生しています。

K7ddr3_6

よく見ると、バースト的にエラーが発生していて、以下の特徴があります。

  • AXIの次のバーストサイクルにはエラーを持ち越していない。直っている。
  • リフレッシュと関係がありそう
  • XORSHIFTはずれていない。つまり、AXIのRVALIDやWREADY,WVALIDなどの問題ではない

K7ddr3_7

書き込むアドレスが、AXIコアの中で変わってしまっているのかもしれません。

まだまだ道は長そうです。

◆追伸

続きはメーリングリストで流しました

|

« 持ち運び便利なミューオン検出器 | トップページ | FPGAや回路設計をしてくれるスタッフ(社員・アルバイト)募集しています »

コメント

コメントを書く



(ウェブ上には掲載しません)




« 持ち運び便利なミューオン検出器 | トップページ | FPGAや回路設計をしてくれるスタッフ(社員・アルバイト)募集しています »