Hello,
We are currently implementing a Clock Data Recovery (CDR) circuit on a Lattice iCE40 FPGA.
Our design uses an Alexander phase detector (also known as a bang-bang phase detector), whose output signals ("up" and "down") are fed into a digital low-pass filter. The filtered output then drives a counter which adjusts the phase shift via the DYNAMICDELAY input of the iCE40's hardware PLL.
The high-level architecture is as follows:
Incoming Data Stream → Alexander Phase Detector → Digital Low-Pass Filter (Loop Filter) → Hardware PLL (via DYNAMICDELAY) → Recovered Clock
We think its metastability because our output is oscillating. Specifically, we observe that the phase detector's outputs for "early" (down) and "late" (up) are sometimes simultaneously high, which should not happen in theory. Which results in us missing data transitions.
We have a 100 MHz clock input at the hardware PLL, which we divide down to 20 MHz. The output of the hardware PLL then passes through a divider that further divides the frequency down to 5 MHz. This is necessary because we are recovering a UART TTL signal with a data rate of 5 Mbit/s, which corresponds to a fundamental frequency of 5 MHz.
We are using iCEstudio for development.
I have provided you with the configuration of the hardware PLL and our iCEstudio project file. Thank you very much!!!!!!
PLL Config:
SB_PLL40_CORE top_pll_inst(.REFERENCECLK(REFERENCECLK),
.PLLOUTCORE(PLLOUTCORE),
.PLLOUTGLOBAL(PLLOUTGLOBAL),
.EXTFEEDBACK(),
.DYNAMICDELAY(DYNAMICDELAY),
.RESETB(RESET),
.BYPASS(1'b0),
.LATCHINPUTVALUE(),
.LOCK(),
.SDI(),
.SDO(),
.SCLK());
//\\ Fin=100, Fout=20;
defparam top_pll_inst.DIVR = 4'b0100;
defparam top_pll_inst.DIVF = 7'b0000000;
defparam top_pll_inst.DIVQ = 3'b000;
defparam top_pll_inst.FILTER_RANGE = 3'b010;
defparam top_pll_inst.FEEDBACK_PATH = "DELAY";
defparam top_pll_inst.DELAY_ADJUSTMENT_MODE_FEEDBACK = "FIXED";
defparam top_pll_inst.FDA_FEEDBACK = 4'b0000;
defparam top_pll_inst.DELAY_ADJUSTMENT_MODE_RELATIVE = "DYNAMIC";
defparam top_pll_inst.FDA_RELATIVE = 4'b0000;
defparam top_pll_inst.SHIFTREG_DIV_MODE = 2'b00;
defparam top_pll_inst.PLLOUT_SELECT = "GENCLK";
defparam top_pll_inst.ENABLE_ICEGATE = 1'b0;
Alexander Phase Detector:
Hi! interesting project! your main error i think is that you have an error in the FF4 clock that should be the same as FF3 to track the falling edge, you nee to remove this:
--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el...@googlegroups.com.
Para ver este debate, visita https://groups.google.com/d/msgid/fpga-wars-explorando-el-lado-libre/13a87e1c-0322-4fe8-b608-c634599009b8n%40googlegroups.com.
Using a PLL to divide 100 MHz → 20 MHz makes no sense. A PLL is a complex analog circuit meant for:
For simple division, just use a counter:
reg [2:0] counter;
always @(posedge clk_100mhz)
counter <= (counter == 4) ? 0 : counter + 1;
wire clk_20mhz = (counter == 0);
The DYNAMICDELAY
port only adjusts phase, not frequency. Your PLL will always output the same frequency regardless of the DYNAMICDELAY value. This might explain why you see no behavioral changes.
What exactly are you trying to achieve?
The fact that DYNAMICDELAY changes nothing suggests your PLL isn't configured for dynamic operation at all. But more importantly, you probably don't need a PLL for example for basic UART CDR - simple 2x or 4x oversampling with your Alexander detector should work fine.
Could you clarify what specific problem you're trying to solve with the PLL? this is the first question we need to follow 😉
Hi!
Thank you very much for your efforts and the prompt reply. I would like to briefly explain our project and the technical challenge we are currently facing.
We are a small startup based in Berlin and are currently developing a professional lighting system. The architecture is based on a high-speed serial daisy-chain (approx. 5 Mbit/s) with up to 256 nodes. Each node uses an iCE40UL1K FPGA and is equipped with two RS485 transceivers to receive and re-transmit differential signals.
We have determined that a simple asynchronous "receive-and-forward" approach will fail over such a long chain. The accumulation of jitter, mainly from the switching times of the transceivers, as well as other effects, compromises the signal integrity. Therefore, our solution is to implement a Clock and Data Recovery (CDR) circuit in each FPGA to recondition the signal at every node.
Our design approach is to realize a hybrid CDR by combining a digital phase detector (in Verilog) with the iCE40's sysCLOCK PLL
After extensive research, there seems to be no simpler solution than to recover the source clock and achieve phase alignment using the hardware PLL. By oscillating the PLL's DYNAMICDELAY value, it appears that even small frequency differences between the transmitter and receiver clocks can be compensated. While this is theoretically difficult to grasp, it seems to be possible in practice. We have based our work on the following research paper, which pursues a very similar approach with a low-cost FPGA:
https://github.com/gitmors/attachments/blob/main/IP2_04.PDF
The prescaler in our design is correctly set with a constant value of 2. Only the default scaler value is 22. We also have all the necessary measurement equipment (logic analyzer, oscilloscope, etc.) to verify the signals at various points.
I thought FDA_RELATIVE is a fixed value that is set, not a "range". Isn´t that correct? The description in the manual is:
"The PLLOUTGLOBALA and PLLOUTCOREA signals are additionally delayed by (n+1)*150 ps, where n = FDA_RELATIVE. Used if DELAY_ADJUSTMENT_MODE_RELATIVE is set to FIXED."
I will test your other suggestions right away.
Thank you very much for your time and effort.
Best regards,
Moritz
This architecture makes the most sense for our lighting system's intended purpose. While we plan to potentially expand the system with appropriate switches in the future, there are no concrete considerations for this at the present time.
We also looked into other technologies, such as Single-Pair Ethernet. However, we decided against it for a few reasons. It's a relatively new and complex technology, and its current specification has many limitations. Since we don't have the necessary expertise to develop it further, we abandoned this option.
It has been a long journey with considerations in many directions to get to this point. Currently, we cannot estimate whether our signal will maintain its integrity after such a long chain, even with a functioning clock data recovery.
RegardsHi!
Thank you for replying!This architecture makes the most sense for our lighting system's intended purpose. While we plan to potentially expand the system with appropriate switches in the future, there are no concrete considerations for this at the present time.
We also looked into other technologies, such as Single-Pair Ethernet. However, we decided against it for a few reasons. It's a relatively new and complex technology, and its current specification has many limitations. Since we don't have the necessary expertise to develop it further, we abandoned this option.
It has been a long journey with considerations in many directions to get to this point. Currently, we cannot estimate whether our signal will maintain its integrity after such a long chain, even with a functioning clock data recovery.
Regards
Moritz
charliva wrote on Thursday, August 7, 2025 at 13:07:53 UTC+2:
Wow! Your problem is more complex than I thought, and with your explanation, everything makes sense, including the PLL configuration. Now I have the complete picture.
Give me some time to read the article and understand the solution. It's a very interesting problem, and... wow, the accumulated jitter is absolutely insane.
Just a question to help me understand everything: why do you use serial connections instead of star or tree connections?
And connect to the output of the inverse clock from not gate:
--------
You are receiving this message because you are subscribed to the Google Groups group "FPGAwars: Exploring the Open Source."
To unsubscribe from this group and stop receiving messages from it, send an email to fpga - wars - exploring-the ... @ googlegroups.com .
To view this discussion, visit https://groups.google.com/d/msgid/fpga-wars-exploring-the-open-source/13a87e1c-0322-4fe8-b608-c634599009b8n%40googlegroups.com .
You are receiving this message because you are subscribed to the Google Groups group "FPGAwars: Exploring the Open Source" .
To unsubscribe from this group and stop receiving messages from it, send an email to fpga - wars-exploring-the ... @ googlegroups.com . To view this
discussion, visit https://groups.google.com/d/msgid/fpga-wars-exploring-the-open-source/03e87c21-3752-4436-810f-8b0650e77b95n%40googlegroups.com .
You are receiving this message because you are subscribed to the "FPGAwars: Exploring the Freeform Side" Google Groups group.
To unsubscribe from this group and stop receiving messages from it, send an email to fpga-wars-exploring-the...@ googlegroups.com .To view this discussion, visit https://groups.google.com/d/msgid/fpga-wars-explorando-el- lado -libre/7ffe400b-76f5-4a1b -9022-08371d98eea8n% 40googlegroups.com .
You are receiving this message because you are subscribed to the Google Groups group "FPGAwars: Exploring the Free Side." To unsubscribe from
this group and stop receiving messages from it, send an email to fpga-wars-exploring-th...@googlegroups.com . To view this
discussion, visit https://groups.google.com/d/msgid/fpga-wars-exploring-the-free-side/32f4f24e-d63a-471a-868d-da68dc50a5bdn%40googlegroups.com .
--
Has recibido este mensaje porque estás suscrito al grupo "FPGAwars: explorando el lado libre" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a fpga-wars-explorando-el...@googlegroups.com.
Hello,
Please excuse the delayed response. We have been very busy rethinking our design and verifying certain approaches. Thank you again for your great support.
We have now concluded that we will pursue a hybrid solution without clock recovery. We will reset our reference point with each frame, reduce the frame size to approximately 1000 bytes or less, and sample with the unadjusted, divided 5 MHz clock from each FPGA that performs the retiming.
This method is very simple and works in practice without any issues, as we always have an idle state that is more than long enough to "reset" and set a new reference point, i.e., the beginning of the data frame.
Our actual question now concerns the trade-off regarding which oscillator you would recommend. We have the choice between a higher-frequency oscillator with higher inaccuracy or a lower-frequency oscillator with higher accuracy. We're considering options like 100 MHz at 20 ppm versus 25 MHz at 10 ppm, but this doesn't factor in temperature fluctuations and aging, etc., which, as far as I know, are not as significant with the low-frequency oscillators as they are with the high-frequency ones.
Accuracy plays the most important role in our case. However, there is a break-even point, as we also need to determine the reference point (the start of the frame) precisely. Therefore, the best option for us would be a high frequency with high accuracy, but this is not possible for cost reasons.
Now the question is: If we scale up the more accurate 25 MHz clock maybe to 200 MHz using the internal iCE40 PLL, do we lose ppm accuracy? Or is it better to use a less accurate 100 MHz oscillator and multiply it to 200 MHz, hoping the final accuracy is better because the multiplication factor is smaller? Or would you say it's better to avoid the hardware PLL altogether and perhaps compromise by just using the 100 MHz clock directly? 25 MHz is definitely too slow here for detecting our reference point.
Thank you very much for your support. I have attached a few screenshots below that show how the PLL distorts our square wave signal after the individual stages of frequency scaling, but it seems that this isn't a problem when it comes to jitter and accuracy, isn't it?, and that leads to my final question:
PLL from 12Mhz to 60Mhz:
The last question is: In the screenshot "PLL from 12MHz to 160MHz," we see a massive voltage drop. What is the cause of this?
Moritz
Thank you for sharing the oscilloscope captures - they're very revealing about the PLL behavior and very interesting to show your process.
The dramatic voltage reduction (4.5V → 488mV) is due to the FPGA output driver limitations at high frequencies. The output transistors simply can't switch fast enough to maintain full rail-to-rail swing. This is normal behavior - the slew rate limitation acts like a low-pass filter, i think , it should error in the measure but in your last screenshot appears a frequency of 313Mhz , i understand is zoomed beaviour, but check it.
Your new strategy,remember me an "start-stop" protocol, appears solid! With 1000-byte frames at 5 Mbps, even 20ppm drift only amounts to 32ns - well within a bit period. About the PLL theoretically maintains ppm accuracy (25MHz@10ppm → 200MHz@10ppm), BUT adds phase noise and jitter.
I think you should use 100MHz @ 20ppm directly without PLL, as Craig said, this is not needed, without PLL you have 20ppm is sufficient for 1000-byte frames (32ns drift << 200ns bit period), avoids PLL jitter completely and provides 20 samples/bit at 5Mbps (excellent oversampling). At the end, simpler, lower power, more predictable. A must.
The slightly worse ppm accuracy (20 vs 10) is negligible compared to the benefits of avoiding PLL artifacts. Your frame-based resynchronization makes absolute accuracy less critical than clean, jitter-free sampling.
And as Crag said, review the distance.
Nice day!