Author Topic: Why does this dds code fail (Solved)  (Read 6340 times)

0 Members and 1 Guest are viewing this topic.

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #25 on: March 21, 2022, 05:36:25 pm »
Note that depending on your PLL's settings, the phase may be in negative degrees, or negative nanosecond/picosecond settings.  I just used to how Quartus' PLL configuration does it.
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #26 on: March 21, 2022, 05:50:10 pm »
By what I have seen of it the PLL phase is set in positive degrees and it is possible to do it in nanoseconds too. Have not tested your clock trick in the actual FPGA yet. Working on the MCU interface now. See my other post with a question about write enable.

Edit: With the three clocks out of the PLL and using inverters between the PLL clocks and the outputs I got rid of the warnings about the source/sink problem, but I can see with the scope that the signals are not very accurate phase wise, so do need to switch to your solution.

Managed to get ModelSim working in a standalone manner to test the separate modules first.

Attached is a screen cap of the Tang Dynasty IDE PLL IP generator window for setting the clocks.
« Last Edit: March 21, 2022, 05:53:34 pm by pcprogrammer »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #27 on: March 21, 2022, 05:56:57 pm »
You should only need 2 clocks, #1 will be the 125MHz at 0 degrees (this is where everything in your design should be clocked from), #2 will be 250MHz, at an optional negative phase shift.  (this is reserved exclusively for synthesizing the DAC CLK pins.)

You are using a negative phase shift since the data coming in from the 125MHz side needs to be clean and ready before the 250MHz clocked logic samples the 'clk_half' which should be running in parallel with the global system 125MHz clock.  If you place a positive number here and the reg 'clk_half' barely makes it in time since it may be super fast, like ready in 1ns, the 250MHz side may sample this signal randomly as a 1 or 0 as it grabs that nets data in the middle of a transition.

Note that in some systems, it may be advantageous to make the 250MHz first, then the 125MHz second.  However, since you will be tuning the 250MHz only, and it only has something like 8 logic cells in that section, I would place it second.
« Last Edit: March 21, 2022, 05:59:48 pm by BrianHG »
 
The following users thanked this post: pcprogrammer

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #28 on: March 24, 2022, 05:00:19 pm »
Did you ever get the .sdc file to be properly recognized & used?
Does your compiler claim that the timings were met?
Did you get rid of the output dac spikes?

Note that to do so, you may need add more lines to your .sdc file.  You will need to define your DAC's IO output setup and hold times.

I do know in Quartus, once I pass ~200MHz, if I do not define the setup and hold, each output on a bus may have + or - skewing compared to the clock output.
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #29 on: March 24, 2022, 05:57:27 pm »
Yes the .sdc file works. With the MCU interface cleaned up, I had to remove some constraints since some signals were removed and now all the warnings are gone. :-+

Still have the spikes in the output, but might have to do with the DAC write and clock signals not being implemented like you showed yet. Did the MCU with your help interface first.

The timing report states a max freq on the core_clock (125MHz signal) of ~220MHz, so there appears to be enough room for more logic.

Getting to know the IDE and what has to do with FPGA more and more.

Cheers,
Peter

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #30 on: March 31, 2022, 10:38:52 am »
Working with higher frequencies is definitely a pain in the bum |O

There is so much interference that it is difficult to pin point problems when measuring the signals. With the 32 bit logic analyzer in my Yokogawa DL9705L I can hook up all the signals of the two DAC's, and then sync on the spikes with a trigger delay, but with the different latches involved it is hard to spot the cause. >:(

With experimenting on the phase of the two signals loading the data in a DAC I was able to get rid of the spikes.

The suggested solution did not do the trick and I ended up with just using two 250MHz outputs of the PLL clocking two dividers to make the signals.

Also found that the given directives (*preserve*)(* useioff = 1 *) do nothing in the Tang Dynasty compiler. I tried with different formats like (* preserve = 1 *) or (* preserve = "yes" *) but it makes no difference. There is a "schematic" viewer in the IDE with which I can follow the signals and it just refuses to put the registers in the IO blocks :o

Played a bit with the chipviewer that is available in the IDE. It is usable for "slower" signals. Within the bit stream logic is added to capture the signals you specify to be monitored. This is extra logic is connected to a clock you assign to it. This means extra fan out on this clock and thus lowers the maximum frequency. Tried a setup with an extra high speed clock from the PLL, but that needs to be connected to some "logical" logic, because otherwise it is optimized out and not available to connect to the chipviewer. Maybe disabling optimization can help there, but then it might screw up the intended logic.

For the DAC clock signals it did not work due to the clock phases and speed. In the viewer the four signals all had the same phase as the core clock, which I know is not the case based on the external measurements.

At least I learned new things and got rid of the spikes.

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #31 on: March 31, 2022, 05:17:11 pm »
Note that with some FPGAs, you might be able to use / instantiate an IO block.  In the parameters for said IO block, can request features like DDR, IO cell on the IO pin, fine delay, drive strength, differential...

In LAttice/Quartus, we may use an IO_BUF.

Such IO buffers will contain a DFF clock, Enable, OE, and a few other options.
Also note that such a piece of code will lock you into you IDE's device, so make this code at the top hierarchy just before the IOs.

The other choice is to continue filling out the .sdc file.  Placing strict output delay and output hold times will force the compiler to use DFF blocks either close to of on the IO pin, if not, it will still have to clean up the timing according to your .sdc settings.  This is more standard and would be recognized within n Quartus and Xilinx.  For some reason, Lattice has moved away from the .sdc standard and you need to fill in the same values elsewhere in their IDE.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #32 on: March 31, 2022, 05:29:56 pm »
Note that if you use an IO buffer and use it's DDR output function, (I'm not talking about the DDR inside your DAC), you can change your 250MHz clock to 125MHz.  Get rid of my PSEUDO DDR 125MHz clock generator and for all your data lines, tie them into the IO buffers Hi and Low while for the clock outputs, tie the output buffers Hi to 1'b1, and the low to 1'b0 with an option to invert.  Also, for those clock outs, use the separate 125MHz output so you may precisely tune it's phase output.

Note that some IO on you fpga might not support DDR.  If those are on your dac, they will need to be moved.  This will provide super clean timing as DDR IO buffers usually can make it into the GHz.
« Last Edit: March 31, 2022, 05:49:18 pm by BrianHG »
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #33 on: March 31, 2022, 06:58:06 pm »
I have looked at what the IDE does for the DAC data pins, and there it is using the DFF within the IO block, so it is capable of doing it. This with or without the "useioff" directive.

These DAC data pins are on the 125MHz clock, while the other DAC signals are on the 250MHz clocks, so could it be that it can't route these clock signals to the IO blocks with the high speed clock routes, and therefore refuses to do it?

I will try with the timing constraints if I can force the DAC clock signals to do the same. The DFF's it is using now are in slices near the IO pins, so timing might not change that much. For the DAC to work properly on the 125MHz, the two lines (wrt and clk) either have to be rising on the same moment or well out of phase. Measurements showed that the"same" on two different FPGA pins does not fly on these higher frequencies. I noticed shifts in the order of 600 - 1200ps, which the DAC does not like. With the signals made from two 90 degree shifted 250MHz clocks it solved the problem.

Thinking about your DDR option on these pins. That way they would still deliver 125MHz while being clocked on 125MHz. Only shifting 90 degree in phase is not an option then?

I thought about using low level macro's to control the usage of the DFF in the IO block, but like you stated this kills portability. I noticed that the compiler uses these macro's when prepping for simulation. It creates flat verilog files to load into the simulator.

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #34 on: March 31, 2022, 07:11:19 pm »
Thinking about your DDR option on these pins. That way they would still deliver 125MHz while being clocked on 125MHz. Only shifting 90 degree in phase is not an option then?

Inverting the Hi and Low data inputs on the DDR will allow 180 degree shift.

Adjusting the phase of the second 125MHz PLL output will allow 90 degree shift, or 45, or many other multiples depending on the phase setting of that PLL output.  Since it is now 125MHz, this setting should have more precise sub-divisions.  The plus here is that those DDR output cells for your clocks on the phase shifted 125MHz have a fixed data inputs of 1'b1 and 1'b0, no connection to your main 125MHz 0 degree data clock.  Hence, no cross clock domain communication eliminating such metastability issues you may have had when going from the 125MHz clock domain to the 250MHz clock domain when using my 2 clock code.

The advantage of using the same DDR output buffers for the DAC data, those on the master 0 degree clock with the Hi and Low tied to the same data, is that all the DDR buffers should have a very refined parallel performance as they were designed to communicate exceedingly fast to DDR2/3 external ram.  This is so long as you have chosen all IOs which have DDR capability.
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #35 on: March 31, 2022, 07:32:11 pm »
Ahh, I see your point now.

The whole DDR thing is a bit new to me. I knew it meant clocking data on both the positive as well as the negative going edge, but did not think about how this worked with the data on these drivers. Two separate inputs for the two data stages makes sense.

A 180 degree phase shift might also solve the spikes problem. As it stands now the PLL setup is 0 degree for the 125MHz and 90 degree on the 250MHz for the wrt lines and 180 degree on the 250MHz for the clk lines. There is no mixing of the clock's like you did in your code. Not behind my dev machine so can't post the code, but it is a simple divide by two setup like:

Code: [Select]
always @(posedge clk_250_phase_90)
  begin
    dac1_wrt <= !dac1_wrt;
    dac2_wrt <= !dac2_wrt;
  end

The compiler optimizes this to a single DFF connected to both the outputs.

Guess there is more to experiment with. :)

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #36 on: March 31, 2022, 08:01:06 pm »
Ahh, I see your point now.

The whole DDR thing is a bit new to me. I knew it meant clocking data on both the positive as well as the negative going edge, but did not think about how this worked with the data on these drivers. Two separate inputs for the two data stages makes sense.

A 180 degree phase shift might also solve the spikes problem. As it stands now the PLL setup is 0 degree for the 125MHz and 90 degree on the 250MHz for the wrt lines and 180 degree on the 250MHz for the clk lines. There is no mixing of the clock's like you did in your code. Not behind my dev machine so can't post the code, but it is a simple divide by two setup like:

Code: [Select]
always @(posedge clk_250_phase_90)
  begin
    dac1_wrt <= !dac1_wrt;
    dac2_wrt <= !dac2_wrt;
  end

The compiler optimizes this to a single DFF connected to both the outputs.

Guess there is more to experiment with. :)

No, you need to instantiate a DDR PHY, 1 per pin.
I never used your FPGA, so I do not know how it works or what the IO Buffer is called.
But when you instantiate one, it will be placed on the FPGA.  In your verilog, you should also be able to define the IO voltage, slew rate, output current, and much more, even maybe PAD / pin IO number/name.

If you run the DDR at 250MHz, your output clock would be 250MHz.
You need to run it at 125MHz.

The HI and LOW inputs are internally samples on the positive clock edge, ie 125MHz which you are clocking it at.
For the outputs, while the clk input is high, the output pin will show the HI input value sampled at the positive edge of the 125MHz source.  When clk input is low, the output pin will show what the LOW input was sampled also at the positive edge of clk in.  So, inside the DDR buffer, there are special sample DFF gate which can operate at 2x speed to shift the main 125MHz clock from the positive to the next negative edge.  Remember, it is the goal of the FPGA to internally all operate with 1 clock at 1 phase, all positive clocked to achieve the best FMAX performance.  It is the job of just the DDR circuitry in the IO buffer alone to send and receive data to the core at 1 positive edge main clock while implementing the half phase shift only at the IO pins.
« Last Edit: March 31, 2022, 08:13:57 pm by BrianHG »
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #37 on: April 01, 2022, 05:28:23 am »
Guess there is more to experiment with. :)

No, you need to instantiate a DDR PHY, 1 per pin.
I never used your FPGA, so I do not know how it works or what the IO Buffer is called.

The code sniplet I showed is from how it is working at the moment, and not a setup for DDR. That is why at the end I stated about the more to experiment with.

I have to research how and even if DDR PHY's are available on this FPGA. There is an .adc file in which IO constraints are set, so it will probably be the place to setup an IO pin as DDR. The calling it DDR PHY is an other clue that helps :-+

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #38 on: April 01, 2022, 05:36:31 am »
Careful, DDR PHY sometimes points you to a complete DDR2/3 ram interface module.  You are looking for a DDR IO Buffer.
 
The following users thanked this post: pcprogrammer

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #39 on: April 01, 2022, 10:00:11 am »
Found how to use the DDR output in the Anlogic FPGA. Within the Tang Dynasty IDE an ODDR IP has to be generated. This gives a verilog module for a DDR output with the ability to hook on the needed signals.

For now just did it for the DAC control signals and the output on the scope looks to be spike free. At least on the Hantek DSO2D10. (This one starts the quickest and makes no noise)

Have to find a way to use this ODDR IP in a bus manner because having to hook up this module to every DAC data pin takes a lot of code. Maybe there is some way to use macro's for this? Not sure if it is needed though, since it is already using the DFF of the IO block for these signals. But as BrianHG pointed out the DDR logic might be faster.

In this top level code it needs the four module connections near the end to hook up the control signals. I checked with the schematic viewer and it is using the AL_PHY_PAD for the ODDR logic.

Code: [Select]
//---------------------------------------------------------------------------
//Main module for connections with the outside world

module FA201_Lichee_nano
(
  //Input signals
  input wire i_xtal,                     //50 MHz clock
  input wire i_mcu_data_strobe,          //Active low going pulse from the mcu to strobe the data
  input wire i_mcu_control_srobe,        //Active low going pulse from the mcu to strobe the control
  input wire i_mcu_read_write_select,    //Read 0 / write 1

  //Bi-directional parallel data bus to / from the mcu       
  inout wire [7:0] io_mcu_data,

  //Output signals
  output o_dac1_clk,
  output o_dac1_wrt,
  output o_dac2_clk,
  output o_dac2_wrt,

  output wire [13:0] o_dac1_d,
  output wire [13:0] o_dac2_d
);

  //---------------------------------------------------------------------------
  //Internal wires

  wire core_clock; 
   
  wire [47:0] channel1_negative_signal_step;
  wire [47:0] channel1_positive_signal_step;
  wire [47:0] channel2_negative_signal_step;
  wire [47:0] channel2_positive_signal_step;

  //---------------------------------------------------------------------------
  //Connection with the sub modules
 
  pll_clock pll 
  ( 
    .refclk   (i_xtal),
    .reset    (1'b0),
    .clk0_out (core_clock)
  );
 
  mcu_interface mcu 
  ( 
    .i_main_clk                      (core_clock),
    .i_data_strobe                   (i_mcu_data_strobe),
    .i_control_strobe                (i_mcu_control_srobe),   
    .i_read_write_select             (i_mcu_read_write_select),
    .io_data                         (io_mcu_data),   
    .o_channel1_negative_signal_step (channel1_negative_signal_step),
    .o_channel1_positive_signal_step (channel1_positive_signal_step),
    .o_channel2_negative_signal_step (channel2_negative_signal_step),
    .o_channel2_positive_signal_step (channel2_positive_signal_step)
  ); 
 
  awg dac1
  (
    .i_main_clock           (core_clock),
    .i_negative_signal_step (channel1_negative_signal_step),
    .i_positive_signal_step (channel1_positive_signal_step),
    .o_dac_d                (o_dac1_d)
  );

  awg dac2
  (
    .i_main_clock           (core_clock),
    .i_negative_signal_step (channel2_negative_signal_step),
    .i_positive_signal_step (channel2_positive_signal_step),
    .o_dac_d                (o_dac2_d)
  );
 
  output_ddr dac1_wrt
  ( 
    .clk   (core_clock), 
    .rst   (1'b0),
    .d1    (1'b0),
    .d2    (1'b1),   
    .q     (o_dac1_wrt)
  ); 
 
  output_ddr dac1_clk
  ( 
    .clk   (core_clock), 
    .rst   (1'b0),
    .d1    (1'b1),
    .d2    (1'b0),   
    .q     (o_dac1_clk)
  ); 
 
  output_ddr dac2_wrt
  ( 
    .clk   (core_clock), 
    .rst   (1'b0),
    .d1    (1'b0),
    .d2    (1'b1),   
    .q     (o_dac2_wrt)
  ); 

  output_ddr dac2_clk
  ( 
    .clk   (core_clock), 
    .rst   (1'b0),
    .d1    (1'b1),
    .d2    (1'b0),   
    .q     (o_dac2_clk)
  ); 
 
endmodule

//---------------------------------------------------------------------------

It did drop the max frequency a bit.

Code: [Select]
Timing group statistics:
Clock constraints:
  Clock Name                                  Min Period     Max Freq           Skew      Fanout            TNS
  core_clock (125.000MHz)                        5.528ns     180.897MHz        0.078ns       227        0.000ns

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #40 on: April 01, 2022, 10:32:05 am »
Have to find a way to use this ODDR IP in a bus manner because having to hook up this module to every DAC data pin takes a lot of code. Maybe there is some way to use macro's for this?

You can use compiler's 'genvar & generate' within your own single function to call multiple instances of the 'output_ddr'.
Your function should take in a data bus in H and L of parameter X bits and CLK of course, and output a data bus DDR with x bits.

Take a look at lines 148, 153 through 156 here:
https://github.com/BrianHGinc/BrianHG-DDR3-Controller/blob/main/BrianHG_DDR3_GFX_source_v16/BrianHG_GFX_Layer_mixer.sv

I have a home made module 'ALPHA_ADJ' I am calling multiple times.  You would be placing the 'output_ddr' inside such a loop.

Properly written, your home made 'multibit_output_ddr' function should be something like 6 lines of code.
You would run 1 for the output data bus set to 12 or 24 bits, and another 1 set to 4 bits for all your clocks.
Use the concatenation in the IO port to stack the IO pins.
 
The following users thanked this post: pcprogrammer

Online Someone

  • Super Contributor
  • ***
  • Posts: 4959
  • Country: au
    • send complaints here
Re: Why does this dds code fail
« Reply #41 on: April 01, 2022, 11:43:42 am »
You can use compiler's 'genvar & generate' within your own single function to call multiple instances of the 'output_ddr'.
Yep, thats the HDL-agnostic concept. Verilog has a shortcut where you can broadcast single control signals to arrays of instances care of its lax typing rules in a very readable one liner:
https://stackoverflow.com/questions/21615210/instantiating-multiple-modules-in-verilog
Works great for exactly this common issue of sending a bus through some vendor primitives.
 
The following users thanked this post: BrianHG, pcprogrammer

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #42 on: April 02, 2022, 09:13:07 am »
Used the vector option pointed out by Someone and it works. It is spike free with the right order of the DAC wrt and clk signals. When I swap them the spikes come in again. Less frequent then with the earlier designs, but there.

So the foundation has been laid. Next up is more work on the MCU interface part to allow updating of the two step registers in a single action and also allow for setting the signal phase registers.

Attached is the project so far.

Below is the module with the ODDR vector approach:

Code: [Select]
//----------------------------------------------------------------------------------
//Module for generating the DAC signals

module awg
(
  //Input
  input i_main_clock,
   
  input [47:0] i_negative_signal_step,
  input [47:0] i_positive_signal_step,   

  //Output
  output wire o_dac_clk,
  output wire o_dac_wrt, 

  output wire [13:0] o_dac_d
);

  //--------------------------------------------------------------------------------
  //Registers

  reg [47:0] signal_phase = 0;

  //--------------------------------------------------------------------------------
  //Logic
 
  always@(posedge i_main_clock)
    begin 
      if(signal_phase[47] == 1'b0)       
        signal_phase <= signal_phase + i_negative_signal_step;     
      else
        signal_phase <= signal_phase + i_positive_signal_step;     
    end
   
  output_ddr dac_data[13:0]   
  ( 
    .clk   (i_main_clock), 
    .rst   (1'b0),
    .d1    (signal_phase[47:34]),
    .d2    (signal_phase[47:34]),   
    .q     (o_dac_d)
  );   

  output_ddr dac_wrt
  ( 
    .clk   (i_main_clock), 
    .rst   (1'b0),
    .d1    (1'b0),
    .d2    (1'b1),   
    .q     (o_dac_wrt)
  ); 
 
  output_ddr dac_clk
  ( 
    .clk   (i_main_clock), 
    .rst   (1'b0),
    .d1    (1'b1),
    .d2    (1'b0),   
    .q     (o_dac_clk)
  ); 

endmodule

//----------------------------------------------------------------------------------

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #43 on: April 02, 2022, 12:00:26 pm »
? Your project disappeared...

Anyways, it should be like this (as I saw it in the DAC data sheet):

Code: [Select]
//----------------------------------------------------------------------------------
//Module for generating the DAC signals

module awg
(
  //Input
  input i_main_clock,  // This is the main PLL 125MHz output clock set to 0 degrees.
  input i_dac_clock,   // This is a second 125MHz clock from your PLL, output #2, but set to 90 degrees offset.
   
  input [47:0] i_negative_signal_step,
  input [47:0] i_positive_signal_step,   

  //Output
  output wire o_dac_clk,
  output wire o_dac_wrt, 

  output wire [13:0] o_dac_d
);

parameter bit INVERT_CLK = 0 ; // Set to 1 to invert the clock output.

  //--------------------------------------------------------------------------------
  //Registers

  reg [47:0] signal_phase = 0;

  //--------------------------------------------------------------------------------
  //Logic
 
  always@(posedge i_main_clock)
    begin 
      if(signal_phase[47] == 1'b0)       
        signal_phase <= signal_phase + i_negative_signal_step;     
      else
        signal_phase <= signal_phase + i_positive_signal_step;     
    end
   
  output_ddr dac_data[13:0]   
  ( 
    .clk   (i_main_clock), 
    .rst   (1'b0),
    .d1    (signal_phase[47:34]),
    .d2    (signal_phase[47:34]),   
    .q     (o_dac_d)
  );   

  output_ddr dac_wrt
  ( 
    .clk   (i_dac_clock), 
    .rst   (1'b0),
    .d1    (INVERT_CLK),
    .d2    (!INVERT_CLK),   
    .q     (o_dac_wrt)
  ); 
 
  output_ddr dac_clk
  ( 
    .clk   (i_dac_clock), 
    .rst   (1'b0),
    .d1    (INVERT_CLK),
    .d2    (!INVERT_CLK),   
    .q     (o_dac_clk)
  ); 

endmodule

//----------------------------------------------------------------------------------


With this setup, probing the dac_clk outputs and data outputs on 2 different scope channels should reveal a perfect 90 degree phase delay relationship as shown to be optimal in the dac's data sheet.

You may need to toggle the 'INVERT_CLK', or swap one of the '!' invert clks for the dac clk.
« Last Edit: April 02, 2022, 12:03:31 pm by BrianHG »
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #44 on: April 02, 2022, 12:39:51 pm »
? Your project disappeared...

How strange, but well here is a new one. I added the possibility to reset the signal phase registers and a way to add a set value to either one of them to change the phase relation between the two channels. Also made it so that the step values are loaded simultaneous on a separate control.

I will try the 90 degree phase option next.

Edit: The 90 degree phase option also works. Without measuring the actual write and clock signals I can't tell the difference. The saw tooth outputs look good and stable.
« Last Edit: April 02, 2022, 01:06:42 pm by pcprogrammer »
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #45 on: April 02, 2022, 02:18:38 pm »
Another question about verilog I can't find an answer for:

To allow the selection of the different wave-forms the data going to the DDR output needs a different assignment but using a case statement or an if else structure seems to be only possible within always blocks and then can't assign data to a wire. This means I would have to make another register to clock the selected data into and use that register as input for the DDR output.

I have tested different assignments for making the different signals and they work, but I need a way to select one of them based on data in a register.

Code: [Select]
  assign dac_signal_data = signal_phase[47] ? 14'h3FFF : 14'h0;

//This is ok for ramp down
//  assign dac_signal_data = ~signal_phase[47:34];
 
  //This is ok for ramp up
//  assign dac_signal_data = signal_phase[47:34];

Is there a proper way of doing this or do I need the register approach?

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #46 on: April 02, 2022, 07:20:00 pm »
It's pen and paper time...
Please visually illustrate to me what you want to achieve with your waveform.
I think you are going about things in a completely backwards manner.
I need to see the function output you are trying to generate.
Also, do you have a modelsim testbench of your code?
 

Online pcprogrammerTopic starter

  • Super Contributor
  • ***
  • Posts: 4325
  • Country: nl
Re: Why does this dds code fail
« Reply #47 on: April 02, 2022, 07:35:13 pm »
This is something for tomorrow 8)

Unfortunately I have not yet managed to get the simulator to work with the Anlogic code. I did do some separate simulation on the MCU interface and some clock stuff, but with the PLL and now the ODDR code in there it gets a bit complicated.

I saw your post in the other thread about the registered instead of combinatoral control lines. I see your point that using registers gives a cleaner setup then using the combinational stack of gates. I assume the compiler will reduce the number of registers down to the ones that are actually used.

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 8089
  • Country: ca
Re: Why does this dds code fail
« Reply #48 on: April 02, 2022, 07:41:59 pm »

Unfortunately I have not yet managed to get the simulator to work with the Anlogic code. I did do some separate simulation on the MCU interface and some clock stuff, but with the PLL and now the ODDR code in there it gets a bit complicated.

Skip the ODDR and PLL.
Those 2 should only be at your top hierarchy driving the IO.
But yes, you need the -l library include on the -vsim line.
 

Online Someone

  • Super Contributor
  • ***
  • Posts: 4959
  • Country: au
    • send complaints here
Re: Why does this dds code fail
« Reply #49 on: April 02, 2022, 10:47:04 pm »
using a case statement or an if else structure seems to be only possible within always blocks and then can't assign data to a wire. This means I would have to make another register to clock the selected data into and use that register
Sounds like yo have picked up Verilog on a as-needs basis rather than learning it from scratch (have met several people who have done this). Recommendation, STOP! HDL coding is nothing like other software even if it looks the same. If you jump in without understanding the basics, and learning the strict terminology, it will be very confusing.

Sadly the freely available references/guides/courses for Verilog are not as numerous or quality as VHDL, but there are some out there that cover these sorts of fundamentals:
https://verilogguide.readthedocs.io/en/latest/verilog/procedure.html

Just because Verilog calls it a register doesn't mean that becomes a register in implementation, confusing!
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf