Jump to content
  • 0

Does Arty support two external clocks in?


rnelsonee

Question

So I must admit I'm more a software guy than a hardware guy, so hopefully this is an easy one. I want to read in bits on pins at 8.192 MHz, buffer them, and send them out on Ethernet via UDP. Ethernet requires 50 MHz and 25 MHz (not a multiple of 8.192 MHz).

I have everything working in simulation, and even in the hardware realm by using the Ethernet clock for my fake data (I just have a counter that counts to N*(25/8.192) instead of counting to N before sending the packet, sending N bits). It's based off the excellent ArtyEthernetTX project which has this for line 1 of the XDS

# Clock signal
set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk100MHz]
create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk100MHz]

So I tried to add a new clock with an I/O pin, like

set_property -dict { PACKAGE_PIN R11   IOSTANDARD LVCMOS33 } [get_ports { sample_clock }]; #IO_0_14 Sch=ck_io[30]

But I got errors saying it was "poor placement routing" and the solution from Xilinx is to move it to a clock-capable in. Unfortunately, I can't find any reference in the Arty manual to a clock capable pin! I tried the clock pin for the SPI header, but that had the same error.

I figure there's three solutions
1) Find a clock capable pin (there has to be one, right?) and you guys can help me find one!

2) Since Arty has a 100MHz "internal" clock, somehow tap that in my VHDL file and use E3 for my external clock

3) Wrap my whole thing in a Custom IP, duplicate every input and output to the wrapper, connect my external clock to pin E3, use Clocking Wizard to generate 100 MHz.

 

I think 3 will work, but it just seems like overkill - certainly you can drive a development board with an external clock and still be able to send data out via Ethernet.

Thank you all for any help! I hope I'm missing something obvious here :)

Link to comment
Share on other sites

9 answers to this question

Recommended Posts

@rnelsonee,

If what you need is a ~8MHz signal, then you don't need a clock capable pin.  Just resample the clock at your 100MHz rate, cross clock domains with it, and use the sampled clock to control when you sample the data.

Be aware, though, there are all kinds of pitfalls you need to be aware of when crossing clock domains, so you might need to do some research on the topic.

Dan

Link to comment
Share on other sites

@D@n

Thank you for the response. I'd assumed that was not good design since it's not a multiple. For those who find this in the future, here is some GPL code in which you provide the ratio of clocks (256/3125 in my example) and it generates a clock.

And sure enough, it's working! The clock drift in simulation worries me, but I guess that's just how it is - the drift corrects in time.

And that link makes for some good reading. I think I'm okay with my buffer, but with my terribly newbie assumption above, maybe I'm making a wrong assumption here too.

But the 8MHz process reads  bits, saves to a buffer, and when it's full, it does a one-line assignment of one array to another (say 'buffer' to 'value'), and then set another signal to high. When my 25MHz sees the signal goes high, it starts the send process with the 'value' array, and it takes plenty of clock cycles to get to 'array' (it's building the Ethernet and IP headers). So while it's not a bi-directional handshake, I can't conceptualize a pitfall. 

Thanks again! 

Link to comment
Share on other sites

45 minutes ago, rnelsonee said:

@D@n

Thank you for the response. I'd assumed that was not good design since it's not a multiple. For those who find this in the future, here is some GPL code in which you provide the ratio of clocks (256/3125 in my example) and it generates a clock.

And sure enough, it's working! The clock drift in simulation worries me, but I guess that's just how it is - the drift corrects in time.

And that link makes for some good reading. I think I'm okay with my buffer, but with my terribly newbie assumption above, maybe I'm making a wrong assumption here too.

But the 8MHz process reads  bits, saves to a buffer, and when it's full, it does a one-line assignment of one array to another (say 'buffer' to 'value'), and then set another signal to high. When my 25MHz sees the signal goes high, it starts the send process with the 'value' array, and it takes plenty of clock cycles to get to 'array' (it's building the Ethernet and IP headers). So while it's not a bi-directional handshake, I can't conceptualize a pitfall. 

Thanks again! 

If you do want to use your input pin as a clock you can, by routing the signal through a BUFG primative - after you include the something like:

-- include the library of primitives
library UNISIM;
use UNISIM.VComponents.all;

........

i_BUFG: BUFG PORT MAP (
  i => raw_pin,
 o => slow clock);

The downside is that the skew between the input clock and the clock signal inside the FPGA isn't the best - but for 8.x MHz or it will have no impact.

You might also want to consider using a FIFO, esp if the amount of data is high. Assigning one array to the other requires two flip-flops per bit, however a FIFO can use either Block RAM or distributed RAM and only needs to hold one copy of the data, so will use a lot less resources. The FIFO can also do data width conversion and provide flow control signals too.

Link to comment
Share on other sites

@hamster,

Thank you for that post! I just had my weekly status meeting and I mentioned to the engineer working on the board going into mine that I wasn't going to use the clock he's providing and I don't think that was what he wanted to hear. I put in a new bufg call like so

i_bufg:  bufg port map (i => CLK100MHz, o => CLK100MHz_buffered);
i_bufg2: bufg port map (i => my_clk_ext, o => my_clk_int);

but am still getting place errors for poor routing. I don't know why it's so hard to just find a suitable clock pin - it seems like my dev board just wasn't designed for it.

[Place 30-574] Poor placement for routing between an IO pin and BUFG. If this sub optimal condition is acceptable for this design, you may use the CLOCK_DEDICATED_ROUTE constraint in the .xdc file....

	my_clk_ext_IBUF_inst (IBUF.O) is locked to IOB_X0Y39 and i_bufg2 (BUFG.I) is provisionally placed by clockplacer on BUFGCTRL_X0Y0

Is the issue using two bufg's, or do I need to keep trying different pins?

Link to comment
Share on other sites

@rnelsonee,

Why wouldn't you use his clock, but just as logic source instead of a clock that you can trigger off of the positive and negative edges of?  I mean, what's wrong with:

input	wire	i_sys_clk, i_data_clk;
input	wire	i_data;
output	reg		o_stb;
output	reg		o_data;

// First, perform a quick clock transfer
reg	[2:0]	clock_transfer;
always @(posedge i_sys_clk)
	clock_transfer <= { clock_transfer[2:0], i_data_clk };

// Now, look for any positive edges to that data clock
always @(posedge i_sys_clk)
	r_stb <= (!clock_transfer[2])&&(clock_transfer[1]);

// No transfer needs to be done on the data wires, since they've been valid for two clocks now
// (the time it took to do the clock transfer)
//
// The rest of your logic can use o_data now, but only when o_stb is true.
// That'll help you gate an 8.125MHz input clock with a 100 MHz internal clock.
always @(posedge i_sys_clk)
	if (r_stb)
    	o_data <= i_data;

// o_stb will be true for once clock any time there is new input from the data port
always @(posedge i_sys_clk)
	o_stb <= r_stb;

Following this, you'd reference if (o_stb) then do whatever logic you need to do, rather than @(posedge i_sys_clk).

If you don't get an input clock for input data, you'll then need to recover that clock and synchronize to it somehow.  That can be annoying and difficult.  The above logic will synchronize to that clock, without having to deal with clock capable pins, etc.

Dan

Link to comment
Share on other sites

@D@n

Haha, yeah, I like that idea - it's similar to what I first tried - just treating it like any old signal. I must have been using a rising_edge(my_clk) somewhere though because of those warnings I got (I didn't 'specify' that the signal coming in was a clock in any special way, so I guess the implementer just knows I'm using it as a clock by seeing such rising_edge statements).

I'll see if I can work your idea into my code - my code is all VHDL and broken into components, so I'll have to play with it for a while. I actually have 3 components currently based on this slower clock, so I'd like to modularize it. Is it fair to do this:

module clock_converter(
    input	wire i_sys_clk,
    input   wire i_data_clk,
    output  reg  r_stb);

    reg	[2:0]	clock_transfer;

    always @(posedge i_sys_clk)
    begin
        clock_transfer <= { clock_transfer[2:0], i_data_clk };
        r_stb <= (!clock_transfer[2])&&(clock_transfer[1]);
    end	
endmodule

And then in my components I change  

"if rising_edge(clk) then" to "if (r_stb) then"? If I'm missing something, just let me know - I'm not sure what r_stb or o_stb stand for.

Link to comment
Share on other sites

@rnelsonee,

Looks like you understand the concept.

So ... the idea behind the _stb (strobe) signals is that they would be logic signals that would be true on the same clock that new data was valid.  The difference between them was that I used r_stb to make certain that everything following would be constant between strobes.  Doing so moved the timing of the strobe by one clock, hence the o_stb value.  If you don't care whether or not the data changes between strobes, and only care that it is valid at the next strobe, than you can just use r_stb as o_stb.

I was also trying to guarantee that the input data was sampled on your clock at the location your clock was available.  My reasoning was the sooner you can get it into your clock domain in a guaranteed fashion, the better.

Dan

Link to comment
Share on other sites

@D@n

Just for closure, thanks again - it looks like I got it. I talked to the other engineer and he also figured I was creating a problem where there wasn't one: he said he'll just delay the data so it's mid-clock and I can just use two D flip-flops, which is your solution.

Link to comment
Share on other sites

@rnelsonee,

Looks like you are well on your way.

Be aware ... adjusting the delay of the input value can be ... problematic.  You can make it work without the other engineer delaying things, or you can make it work with.  Just ... watch the delay, and think through how you are going to handle it.

Dan

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...