Jump to content

A Guide to Using DDR in the all HDL Design Flow


zygot

Recommended Posts

You should definitely use the 100 MHz DDR3_CLK100 for the source of any MMCM clocks generated for use with the DDR controller clock domain.

The Digilent master constraints files assigns the DDR3_CLK100 pin IOSTANDARD as SSTL135 so you should follow those settings in your main constraints file.

The 12 MHz UCLK is on IO bank 15 should use the IOSTANDARD assigned in the master constraints file.

The error message about conflicting IOSTANDARDS means that bitgen DRC has found inconsistencies of compatible IOSTANDARD assignments for pins in the same bank. Somewhere, you've connected sys_clk_i to the wrong pin. The signal names in your toplevel entity port have to match exactly the names in your constraint files. I always refer to the master constraint file and schematic to understand connectivity before doing a design involving external interfaces that I haven't used before. Sometimes the master constraint file is wrong, but the schematic for Digilent boards can be considered as "golden". I don't always use the same name as either the master constraints file or the schematic... but all of my project sources must be consistent and. One needs to check connectivity from pin number through to the toplevel entity port name making sure that the name is exactly the same in all project source files. It's easy to get confused by signal naming. Even the Digilent master constraints files aren't always consistent with the schematic or demo HDL source files. Don't mindlessly use the same signal names in demo HDL files; check pin connectivity to the schematic pin numbers.

Your board is a rarity among Digilent FPGA boards in that is has a external clock module connected to the same IO bank as the DDR interface. You shouldn't be getting a warning about Sub-optimal placement for a clock-capable IO pin and MMCM pair if the input clock to your MMCM clock input is connected to pin R2.

Edited by zygot
Link to comment
Share on other sites

Hi again @zygot

Thanks again for helping out.

I do not get a warning if I just use the 100Mhz clock directly with MIG. I only get a warning about sub-optimal placement if I call clock generator IP first.

So basically this works:

    example_top u_example_top
    (
     .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),
     .ddr3_ck_n(ddr3_ck_n),
     .ddr3_cke(ddr3_cke),
     .ddr3_dm(ddr3_dm),
     .ddr3_odt(ddr3_odt),
     .sys_clk_i(sys_clk_i),
//     .clk_ref_i(clk200),
     .tg_compare_error(tg_compare_error),
     .init_calib_complete(init_calib_complete),
     .sys_rst(sys_rst)
     );

 

But this does not:

clk_gen clk_gen_inst (
    .clk_out1(CLK_40Mhz),
    .clk_out2(CLK_200Mhz),
    .clk_out3(DDR_CLK),
    .resetn(rst_n),
    .clk_in1(sys_clk_i)
    );

    example_top u_example_top
    (
     .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),
     .ddr3_ck_n(ddr3_ck_n),
     .ddr3_cke(ddr3_cke),
     .ddr3_dm(ddr3_dm),
     .ddr3_odt(ddr3_odt),
     .sys_clk_i(DDR_CLK),
//     .clk_ref_i(clk200),
     .tg_compare_error(tg_compare_error),
     .init_calib_complete(init_calib_complete),
     .sys_rst(sys_rst)
     );

 

Link to comment
Share on other sites

@Mathias, Could you post the entire toplevel source file and the .xdc constraints file in your project? I'm assuming that this is your port of the imp_top.v that implements the DDR controller example design.

My guess is that sys_clk_i is not on your toplevel port and constraints. In this case Vivado will just assign it to an arbitrary pin that it picks out of the air ( or if I was an optimist I'd say intentionally picks a pin that will cause a bitgen error so that you know that you have a problem). This is why you are getting a weird message about IOSTANDARD incompatibility.

It's important to read all warning messages carefully, especially if you get an error message. It's also important to look at the final pin report after successfully generating a bitstream file to make sure that the pins are correct before running a design on hardware.

Don't freak out about how many warning message you might encounter; many can be ignored.

Edited by zygot
Link to comment
Share on other sites

Are you using the mig project file from Digilent or one that you created through the IP Wizard? I notice that Digilent only supplies sources for the Arty-S7-50.

I notice that your constraints file is for the Arty-S7-25 and the mig-a-prj has this line: <selected>7s/xc7s50-csga324</selected>

I'm not familiar with the Spartan 7 devices so I don't know if there are any clocking restrictions that are different than for other Series 7 devices. I don't see why the code as presented in your git would make Vivado think that sysclk is a LVCMOS33 signal or "Sub-optimal placement for a clock-capable IO pin".

I suspect that you might not be able to follow the tutorial exactly by providing the Mig controller IP a single 200 MHz clock ( or whatever value the datasheet says is in the range for a reference clock. ). You could try following the Digilent Mig reference for your board. The problem is that you will need another clock source for your other system clocks ad they will be unrelated to the DDR clock domain.

Vivado has a problem handling multiple create_clock constraints for the same signal. If you connect sysclk to an MMCM it will create it's own constraints file with a create_clock constraint and generate errors. Did you get a synthesis warning about over-riding this timing constraint? If your design connects sysclk to an MMCM then your toplevel constraint file should not have one. If you connect sysclk directly to HDL logic then you need to have the create_clock timing constraint in your constraint file. If you follow the Digilent Mig project and connect the 100 MHz sysclk directly into the Mig Controller IP then it will ( I believe ) create it's own xdc files and a create_clock constraint.

Vivado doesn't make it easy to round up all of the constraint file in a design that uses its IP.

Link to comment
Share on other sites

@Mathias

I have Vivado 2020.2 installed on my Centos box so I brought up your project. I had to "upgrade" the MMCM because Vivado keep changing the way it handles IP.

I found problems.

I had to change the Mig Project settings to match your imp_top.v source.

  • unchecked the Pin Compatible FPGAs
  • select a 4:1 controller
  • selected 200 MHz for Input Clock Period ( Vivado 2020.2 has a bug that keeps changing this every time you open the IP Wizzard !!) Use the drop-down selector to choose from the list because Vivado has a problem with clock periods specified in ns.
  • selected Use System Clock for Reference clock

I hate context sensitive IP Wizards, because they don't show the same choices depending on previous selections and devices.. it can cause a lot of problems.

Your ddr3_addr width is wrong in the imp_top port causing placement errors.

I had to add this line to the Arty-S7-25-Master constraints file:

 set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets sysclk]

This got me past your DDR problems. You still have some work to do though with constraint assignments.

I don't know why Vivado creates an issue with the clock. Likely, you need to assign the location of the MMCM directly, though Vivado should be smart enough to figure this out on its own. It could be for some other restriction that I haven't tracked down yet.

I posted some files to help you fix the DDR controller issues. Make sure that the mig_a.prj pin location assignments are correct.

The xc7s25 is a really small part in terms of resources so designs involving external DDR memory might be an issue.

datasheet.txt

mig_a.prj

Edited by zygot
Link to comment
Share on other sites

@zygot

Thank you for compiling my ddr test project. If I make the changes you pointed out it seems to work without errors or warnings. Also I got the best timing so far when I included my application (that is using ddr) into the design. However I feel that it is a lost cause, as you pointed out, xc7s25 is small and ddr functionality almost takes up the whole thing :O. It will probable be impossible to get the speed I need out from the thing. Anyway, thanks again taking the time to help me!

Link to comment
Share on other sites

You may still want to work through more parts of the tutorial as ditching the Mig example core will save resources.

Theoretically, there's a lower limit to how fast you can operate DDR memory, but if you are trying to stuff a lot of design into a small part and are having timing closure issues you might try running the DDR controller PHY at a lower data rate. For a lot of applications it might still be plenty fast enough, if all you need is a large storage bucket; see part 2 of the tutorial.

Then again, sometimes one has to abuse the piggy bank a bit more vigorously in order to work with a platform more amendable toward fulfilling one's dream of glory. :)

Link to comment
Share on other sites

On 2/4/2022 at 6:31 PM, Mathias said:

@zygot

Thank you for compiling my ddr test project. If I make the changes you pointed out it seems to work without errors or warnings. Also I got the best timing so far when I included my application (that is using ddr) into the design. However I feel that it is a lost cause, as you pointed out, xc7s25 is small and ddr functionality almost takes up the whole thing :O. It will probable be impossible to get the speed I need out from the thing. Anyway, thanks again taking the time to help me!

Very interesting board you have there. At the risk of going off topic, I'll point you to the fact that DDR chips have a DLL off mode that you can read more about in various datasheets. If DLL on mode for DDR3 modules supports clock periods of 3300ps and lower, DLL off mode allows for periods of 8ns and higher, the only condition is to satisfy the refresh period of 7.8 us. Of course MIG doesn't support this, but it's a nice thought experiment. And at least for the Arty S7-50, there's an actual PHY and controller built around it online (with proper DFI and AXI).

Have a look at this project, the uploader claims it works with a 100 MHz clock. https://github.com/ultraembedded/core_ddr3_controller Should be much smaller than the entire MIG IP, though one can't vouch for high bandwidth operation seeing as the PHY in this project requires a DDR clock plus a clock that's 4 times faster (here it's 100 MHz and 400 MHz). Then again, 200 MT/s might be enough for your application?

(I am also currently in the process of creating a similar controller and PHY for higher -- DLL on -- speeds, albeit any real result might take months, if I manage to reach one at all. The basis of the PHY ought to be SERDES and IDELAY blocks, just as in MIG or in any other DDR project, really.)

Edited by jb9631
Link to comment
Share on other sites

@jb9631,

Thanks for the information. Interesting....

Xilinx has no incentive to make their IP resource thrifty. They do have an incentive to make their IP consume lots of resources. Just an observation.

IO SERDES can be tricky to implement. Fortunately, there are application notes to help. Before trying out a design on hardware I suggest doing a timing simulation ( after the RTL simulation ) on the implemented design.

Edited by zygot
Link to comment
Share on other sites

  • 2 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...