====== Memory tutorial for USB-FPGA-Modules 2.12, 2.13, 2.14 and 2.18 ====== This tutorial explains the generation of the memory controller IP Core for for the [[memfifo|memfifo Example]] [[http://www.ztex.de/usb-fpga-2/usb-fpga-2.12.e.html|USB-FPGA-Modules 2.12]], [[http://www.ztex.de/usb-fpga-2/usb-fpga-2.13.e.html|USB-FPGA-Modules 2.13]], [[http://www.ztex.de/usb-fpga-2/usb-fpga-2.14.e.html|USB-FPGA-Modules 2.14]] and [[http://www.ztex.de/usb-fpga-2/usb-fpga-2.18.e.html|USB-FPGA-Modules 2.18]]. ===== Creating the IP Core ===== This section describes how the IP Core is created using MIG version 2.1 (Viavado Version 14.2). The settings for other versions should be very similar. - In the Project Manager: click on ''Memories & Storage Elements'' -> ''Memory Interface Generators'' -> ''MIG'' - Verify the Settings in the first dialog box (FPGA type, speed grade, ...) - On the next screen "Create Design" has to be selected and a component name can be entered.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-02.png|MIG Screen 2}} - Here you can chose to create constraints for pin-compatible parts. If you change the part you must replace the constraint file which are a little bit hidden. The constraint for the base part is located in ''.srcs/sources_1/ip///user_design/constraints/.xdc''. This one needs to be replaced by another one from the directory ''.srcs/sources_1/ip///user_design/constraints/compatible_ucf''.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-03.png|MIG Screen 3}} - DDR3 memory has to be selected.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-04.png|MIG Screen 4}} - The correct clock period (2500ps) and memory type (MT41J128M16XX-125) have to be entered and "Data mask" should bee enabled.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-05.png|MIG screen 5}} - Chip select must be disabled, on-die termination must be set to ''RZQ/6'' and output impedance control can be set either to ''RZQ/7'' or ''RZQ/6'' (This are the termination settings of the memory component).\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-06.png|MIG screen 6}} - System and reference clock buffers must be set to "No buffer" and "Internal Vref" should be disabled.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-07.png|MIG screen 7}} - Input termination must be set to "60 Ohm". (This is the on-die termination of the FPGA. Due to the output termination of the driver this is not the actual transmission line impedance).\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-08.png|MIG Screen 8}} - Fixed pin out has be selected on the next screen.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-09.png|MIG Screen 9}} - In the next dialog box, first click "Read XDC/UCF" and load the file ''constraints/usb-fga-2.1[3|4]-mem.xdc'' from SDK package. Then click "validate" and "next".\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-10.png|MIG screen 10}} - The status signals on the next screen are not used.\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-11.png|MIG screen 11}} - The last dialog box shows a summary. Click "next" in order to create the core:\\ {{:en:ztex_boards:ztex_fpga_boards:memfifo:a7-ddr3-12.png|MIG screen 12}} ===== Instantiation of the core===== Templates with description for instantiation can be found in the file ''.srcs/sources_1/ip//.v[o|h]e'' of the Vivado project. In the memfifo example this looks like mig_7series_0 mem0 ( // Memory interface ports .ddr3_dq(ddr3_dq), .ddr3_dqs_n(ddr3_dqs_n), .ddr3_dqs_p(ddr3_dqs_p), .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_reset_n(ddr3_reset_n), .ddr3_ck_p(ddr3_ck_p[0]), .ddr3_ck_n(ddr3_ck_n[0]), .ddr3_cke(ddr3_cke[0]), .ddr3_dm(ddr3_dm), .ddr3_odt(ddr3_odt[0]), // Application interface ports .app_addr( {1'b0, app_addr, 3'b000} ), .app_cmd(app_cmd), .app_en(app_en), .app_rdy(app_rdy), .app_wdf_rdy(app_wdf_rdy), .app_wdf_data(app_wdf_data), .app_wdf_mask({ APP_MASK_WIDTH {1'b0} }), .app_wdf_end(app_wdf_wren), // always the last word in 4:1 mode .app_wdf_wren(app_wdf_wren), .app_rd_data(app_rd_data), .app_rd_data_end(app_rd_data_end), .app_rd_data_valid(app_rd_data_valid), .app_sr_req(1'b0), .app_sr_active(), .app_ref_req(1'b0), .app_ref_ack(), .app_zq_req(1'b0), .app_zq_ack(), .ui_clk(uiclk), .ui_clk_sync_rst(ui_clk_sync_rst), .init_calib_complete(init_calib_complete), .sys_rst(!reset), // clocks inputs .sys_clk_i(clk400), .clk_ref_i(clk200) ); ===== Clocks on USB-FPGA Modules 2.13 ===== On USB-FPGA Modules 2.13 the clock are generated on-chip from the 48 MHz output clock of the EZ-USB. A ''PLLE2'' is recommended for this purpose as used in the memfifo example: wire pll_fb, clk200, clk400, uiclk, fxclk; BUFG fxclk_buf ( .I(fxclk_in), .O(fxclk) ); PLLE2_BASE #( .BANDWIDTH("LOW"), .CLKFBOUT_MULT(25), // f_VCO = 1200 MHz (valid: 800 .. 1600 MHz) .CLKFBOUT_PHASE(0.0), .CLKIN1_PERIOD(0.0), .CLKOUT0_DIVIDE(3), // 400 MHz, memory clock .CLKOUT1_DIVIDE(6), // 200 MHz, reference clock .CLKOUT2_DIVIDE(CLKOUT2_DIVIDE), // unused .CLKOUT3_DIVIDE(CLKOUT3_DIVIDE), // unused .CLKOUT4_DIVIDE(CLKOUT4_DIVIDE), // unused .CLKOUT5_DIVIDE(CLKOUT5_DIVIDE), // unused .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), .CLKOUT0_PHASE(0.0), .CLKOUT1_PHASE(0.0), .CLKOUT2_PHASE(CLKOUT2_PHASE), .CLKOUT3_PHASE(CLKOUT3_PHASE), .CLKOUT4_PHASE(CLKOUT4_PHASE), .CLKOUT5_PHASE(CLKOUT5_PHASE), .DIVCLK_DIVIDE(1), .REF_JITTER1(0.0), .STARTUP_WAIT("FALSE") ) dram_fifo_pll_inst ( .CLKIN1(fxclk), // 48 MHz input clock .CLKOUT0(clk400), // 400 MHz memory clock .CLKOUT1(clk200), // 200 MHz reference clock .CLKOUT2(), .CLKOUT3(), .CLKOUT4(), .CLKOUT5(), .CLKFBOUT(pll_fb), .CLKFBIN(pll_fb), .PWRDWN(1'b0), .RST(1'b0) ); ===== Clocks on USB-FPGA Modules 2.14 and 2.18 ===== On USB-FPGA Modules 2.14 and 2.18 the clock are generated on-chip from the 26 MHz on-bord oscilator. A ''PLLE2'' is recommended for this purpose as used in the memfifo example: wire pll_fb, clk200, clk400, uiclk, fxclk; wire pll_fb, clk200_in, clk400_in, clk200, clk400, uiclk, fxclk; BUFG fxclk_buf ( .I(fxclk_in), .O(fxclk) ); BUFG clk200_buf ( // sometimes it is generated automatically, sometimes not ... .I(clk200_in), .O(clk200) ); BUFG clk400_buf ( .I(clk400_in), .O(clk400) ); PLLE2_BASE #( .BANDWIDTH("LOW"), .CLKFBOUT_MULT(31), // f_VCO = 806 MHz (valid: 800 .. 1600 MHz) .CLKFBOUT_PHASE(0.0), .CLKIN1_PERIOD(0.0), .CLKOUT0_DIVIDE(2), // 403 Mz .CLKOUT1_DIVIDE(4), // 201.5 MHz .CLKOUT2_DIVIDE(CLKOUT2_DIVIDE), .CLKOUT3_DIVIDE(CLKOUT3_DIVIDE), .CLKOUT4_DIVIDE(CLKOUT4_DIVIDE), .CLKOUT5_DIVIDE(CLKOUT5_DIVIDE), .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), .CLKOUT0_PHASE(0.0), .CLKOUT1_PHASE(0.0), .CLKOUT2_PHASE(CLKOUT2_PHASE), .CLKOUT3_PHASE(CLKOUT3_PHASE), .CLKOUT4_PHASE(CLKOUT4_PHASE), .CLKOUT5_PHASE(CLKOUT5_PHASE), .DIVCLK_DIVIDE(1), .REF_JITTER1(0.0), .STARTUP_WAIT("FALSE") ) dram_fifo_pll_inst ( .CLKIN1(fxclk), .CLKOUT0(clk400_in), .CLKOUT1(clk200_in), .CLKOUT2(clkout2), .CLKOUT3(clkout3), .CLKOUT4(clkout4), .CLKOUT5(clkout5), .CLKFBOUT(pll_fb), .CLKFBIN(pll_fb), .PWRDWN(1'b0), .RST(1'b0) ); {{indexmenu_n>5010}}