0
\$\begingroup\$

I have an Input which provides DDR data, I need to capture it and output it from the FPGA in one register (12bit).

How can I do it?

What I did for now is to capture the input data with always block in the rising edge and store in reg1. capture the input data with another always block on the falling edge and store in reg2.

Now i have data of the rising edge on reg1[12bit] and falling edge on reg2[12bit], how can I send this data now to another output register of 12 bit?

my code:

module ADC(
 input rstn,
 input clk, 
 input [11:0] data_in, 
 output [11:0] data_out
 );
 reg rst;
 reg [11:0] posedge_data;
 reg [11:0] negedge_data;
 always @(posedge clk or negedge rstn)
 begin
 rst <= ~rstn;
 end
 always @(posedge clk, posedge rst)
 begin
 if (rst) begin
 posedge_data <= 12'b100000000000;
 end else begin
 posedge_data <= data_in;
 end
 end
 always @(negedge clk, posedge rst)
 begin
 if (rst) begin
 negedge_data <= 12'b100000000000;
 end else begin
 negedge_data <= data_in;
 end
 end
endmodule

assuming that doubling the clk frequency with PLL is not an option. Im using Lattice ECP3 FPGA. If you can help me with Lattice IPs and how to connect them that also would help.. but I think there is possible way without IPs no?

thanks.

Edit:

after Oldfart comment

if I change data_out to 24 bits and add this line of code:

assign data_out = {posedge_data,negedge_data};

does it make it good DDR design? or there is a better way?

asked Feb 24, 2020 at 17:04
\$\endgroup\$
4
  • \$\begingroup\$ It's not clear to me what you are trying to accomplish. Suppose at some instant in time posedge_data = 12'h123 and negedge_data=12'hABC. What 12-bit data value would you want as an output? What clock edge should cause the output data to be latched? \$\endgroup\$ Commented Feb 24, 2020 at 17:17
  • \$\begingroup\$ my goal is to output the data in posedge_data and neg_edge data into output in falling edge and rising edge of the clock.. make the data DDR. it means that in 1 clock cycle I will see the negedge_data and posedge_data in the output register \$\endgroup\$ Commented Feb 24, 2020 at 18:39
  • \$\begingroup\$ The EPC3 has dedicated DDR blocks on its inputs for this very purpose \$\endgroup\$ Commented Feb 24, 2020 at 19:36
  • \$\begingroup\$ @TomCarpenter Hi thanks for the comment, I tried using the DDR, more specific I trying to use: GDDRX1_RX.SCLK.PLL.Aligned that I created from IPexpress on Diamond -> DDR_GENERIC -> and specified my needs. When Im adding the verilog file to the project and add the Instantation to my Top level the project syntisized but after that REVEAL thinks that the ddr IP is my top level design! and I cant add signals to REVEAL from my Top level file, when Im changing top level to my top file its making problems. Do you know why? \$\endgroup\$ Commented Feb 24, 2020 at 21:22

2 Answers 2

4
\$\begingroup\$

The normal procedure is to use double the data width inside a DDR receiver.

So with a 12-bit DDR bus you must output the data to a 24 bit wide port/register.

The alternative is to use double the clock frequency (or higher) inside but as you said that is often not an option.

You would NOT keep processing the data internally on alternate clock edges. That is bad design.

answered Feb 24, 2020 at 17:20
\$\endgroup\$
2
  • \$\begingroup\$ I cant transfer the neg/pos edge data from the 2 registera to 24 bit register? Or I should use DDR reciever inside the FPGA? \$\endgroup\$ Commented Feb 24, 2020 at 18:19
  • 1
    \$\begingroup\$ That is the way to do it. The negedge arriving data has only half a clock edge to the next register so normally you would try NOT to add any logic in that stage. \$\endgroup\$ Commented Feb 24, 2020 at 19:06
1
\$\begingroup\$

I have modified ur code and added reset synchronizers and normal synchronizers incase if u need u can add them too.. from ur port connections assumed its 12 bit input data bus with DDR rate so output will be 12*2=24 bits and u need to transmit it linear manner that is data_out [1:0] corresponding to falling edge data and rising edge data respectively..

u can use Lattice default macros IDDR* for this case anyways u can recode also , i have coded in system verilog in case if ur tool doesn't support the SV please use verilog data types respectively in the below code.. As i have worked closely with xilinx tools i have used some tool directives like (* Dont_touch and ASYNC_REG*) for synchronizes to place them closely useful for meta-stability condition.. please use such directives in ur code by modifying them according to the lattice tool directives..

module ADC(
 input rstn,
 input clk, 
 input [11:0] data_in, 
 output [23:0] data_out
);
 reg rst;
 reg [11:0] posedge_data;
 reg [11:0] negedge_data;
 always @(posedge clk or negedge rstn) // expecting reset is synchronous to this clock domain if not use 
 rst <= ~rstn; // reset synchronizer in ur code to remove metastability during reset removal and recovery
 always @(posedge clk, posedge rst)
 if (rst) posedge_data <= 12'b1000_0000_0000;
 else posedge_data <= data_in; // Assuming data_in in synchronous to the design else u need to atleast 2-FF stage synchronizer
 always @(negedge clk, posedge rst)
 if (rst) negedge_data <= 12'b100000000000;
 else negedge_data <= data_in;// Assuming data_in in synchronous to the design else u need to atleast 2-FF stage synchronizer
 for (int i=0;i<12;i++)
 assign data_out[i+:2]={negedge_data[i],posedge_data[i]};
endmodule
module reset_sync #(
 parameter TCQ = 100,
 parameter NUM_OF_STAGES = 2,
 parameter IN_ACTIVE_HIGH_RESET = 1,
 parameter OUT_ACTIVE_HIGH_RESET = 1
)(
 input dest_clk, async_rst,
 output logic sync_rst_dest_clk
 output logic async_rst_out;
);
 (* DONT_TOUCH = "TRUE" , ASYNC_REG = "TRUE" *) logic [NUM_OF_STAGES-1:0] sync = 0;
 logic sync_rst_out;
 reg rst_out = 0;
 if(IN_ACTIVE_HIGH_RESET)begin: ASYNC_RESET
 always_ff @(posedge dest_clk or posedge async_rst)
 if (async_rst) sync <= #TCQ OUT_ACTIVE_HIGH_RESET ? '1 : '0;
 else sync <= #TCQ OUT_ACTIVE_HIGH_RESET ? {sync[NUM_OF_STAGES-2:0],1'b0}
 : {sync[NUM_OF_STAGES-2:0],1'b1} ;
 end else begin: ASYNC_RESET
 always_ff @(posedge dest_clk or negedge async_rst)
 if(~async_rst) sync <= #TCQ OUT_ACTIVE_HIGH_RESET ? '1 : '0;
 else sync <= #TCQ OUT_ACTIVE_HIGH_RESET ? {sync[NUM_OF_STAGES-2:0],1'b0}
 : {sync[NUM_OF_STAGES-2:0],1'b1} ;
 end
 assign async_rst_out = sync[NUM_OF_STAGES-1];
 sync # (
 .SYNC_MTBF (2)
 ,.WIDTH (1)
 ) u_dest_rst_sync(
 .clk (dest_clk)
 ,.data_in (async_rst_out)
 ,.data_out (sync_rst_out)
 );
 assign sync_rst_dest_clk = sync_rst_out;
endmodule
module sync #(
 parameter SYNC_MTBF = 2
 ,parameter WIDTH = 1
 ,parameter TCQ = 100
)(
 input clk
 ,input [WIDTH-1:0] data_in
 ,output [WIDTH-1:0] data_out
);
 for (genvar wd=0; wd<WIDTH; wd=wd+1) begin : SYNC
 (* dont_touch = "true" *) (* ASYNC_REG = "TRUE" *) reg [SYNC_MTBF-1:0] sync_reg;
 always @(posedge clk)
 sync_reg <= #TCQ {sync_reg[0+:SYNC_MTBF-1], data_in};
 assign data_out[wd] = sync_reg[SYNC_MTBF-1];
 end
endmodule
answered Mar 1, 2020 at 12:22
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.