Clock Data Recovery with the ice40 pll

146 views
Skip to first unread message

Moritz Meissner

unread,
Aug 6, 2025, 9:10:04 AMAug 6
to FPGAwars: explorando el lado libre

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:

Alexander Phase Detector.png



LED_optimized_for_wave_gtk_new_uart_sim_and_lowpassfilter_rebuild.ice

charli va

unread,
Aug 6, 2025, 10:20:55 AMAug 6
to fpga-wars-explora...@googlegroups.com

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:

Captura de pantalla 2025-08-06 a las 16.17.11.png
And connect to the output of the inverse clock from not gate:

Captura de pantalla 2025-08-06 a las 16.17.36.png

This is a good point to continue your tests.

Have a nice day!




--
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.

Moritz Meissner

unread,
Aug 6, 2025, 11:29:55 AMAug 6
to FPGAwars: explorando el lado libre
Thank you for the suggestion, but when we connected the clocks in the way you suggested the signal didn’t change. And the clock update that you suggested doesn’t seem to match how the clocks are shown in the Alexander Phase detection documentation we found. We thought that the second FF with the non inverted clock was to realign the signals, is that not true?

We also found a bug in the filter code that could have caused the filter to oscillate, but this didn’t fix the issue either.

// Parameters
parameter TAPS = 32;
parameter DATA_WIDTH = 4;

// 4-bit filtered output
reg [DATA_WIDTH-1:0] control_voltage;

// Array for the delay line of the FIR filter
// delay_line[0] is the current input, delay_line[1] is t-1, etc.
reg [DATA_WIDTH-1:0] delay_line [0:TAPS-1];

// Majority voting for input signals
reg [2:0] up_history, down_history;

// Loop variable
integer i;

reg [8:0] sum; // 9 bits wide: 32 taps * 4-bit max (15) = 480 max, needs 9 bits

// Majority voting logic - only act if 2 out of 3 recent samples agree
wire majority_up = (up_history[2] + up_history[1] + up_history[0]) >= 2;
wire majority_down = (down_history[2] + down_history[1] + down_history[0]) >= 2;

// This block handles the sequential logic: the up/down counter and the delay line.
// It is triggered on the rising edge of the clock.
always @(posedge clk) begin
    if (!rst_n) begin
        // On reset, all delay line registers and history are cleared to 0.
        for (i = 0; i < TAPS; i = i + 1) begin
            delay_line[i] <= {DATA_WIDTH{1'b0}};
        end
        up_history <= 3'b0;
        down_history <= 3'b0;
    end else begin
        // Update majority voting history
        up_history <= {up_history[1:0], up};
        down_history <= {down_history[1:0], dn};
       
        // Shift the delay line: move all samples one position down
        for (i = TAPS-1; i > 0; i = i - 1) begin
            delay_line[i] <= delay_line[i-1];
        end
       
        // The delay_line[0] acts as an up/down counter.
        // This simulates a changing input signal for the filter.
        // Use majority vote (2 out of 3 recent samples agree)
        if (majority_up & !majority_down) begin
            if (delay_line[0] != {DATA_WIDTH{1'b1}}) begin // Check for maximum value
                delay_line[0] <= delay_line[0] + 1;
            end
        end else if (majority_down & !majority_up) begin
            if (delay_line[0] != {DATA_WIDTH{1'b0}}) begin // Check for minimum value
                delay_line[0] <= delay_line[0] - 1;
            end
        end
        // If both majority votes are true, both are false, or no majority, hold current value
    end
end

// This block handles the combinational logic of the FIR filter.
// It calculates the output based on the current and delayed input values.
// This is a simple moving average filter.
always @(*) begin

    sum = 9'b0; // Initialize sum to 0
   
    // Sum all taps
    for (i = 0; i < TAPS; i = i + 1) begin
        sum = sum + delay_line[i];
    end
   
    // The output is the sum of the 32 taps divided by 32.
    // Division by 32 is implemented as a right shift by 5 for efficiency.
    // Take bits [8:5] to get the result of sum >> 5
    control_voltage = sum[8:5]; // Right shift by 5 (divide by 32)
end

// Output assignment
assign control_voltage_out = control_voltage;


However we have also now found that the behaviour doesn’t change with or without our delay feedback connected to the PLL. Which could mean that we don’t understand how it works, or it is not connected correctly, can you see if there is a potential error?
LED_optimized_for_wave_gtk_new_uart_sim_and_lowpassfilter_rebuild.ice

charli va

unread,
Aug 6, 2025, 11:43:24 AMAug 6
to fpga-wars-explora...@googlegroups.com
What exactly is your setup, and how are you testing the circuit? Have you tried doing a testbench of the minimal parts first?

Ideally, you should separate each of the functional blocks into independent circuits and test them with controlled inputs, knowing what output you expect.

That is, imagine the filter. You should have a design that only tests the filter, a design that only tests Alexander... and once each piece is working, put them together, knowing that if each piece is working, the problems are in the interconnection and synchronization.

And then, most importantly, try to explain to us clearly what you want to do so we can fully understand it. The design seemed to have "gaps," perhaps because I don't understand the project as a whole, or because there are real conceptual problems. If you tell us a little more in detail, I'll try to help.

charli va

unread,
Aug 6, 2025, 11:52:40 AMAug 6
to fpga-wars-explora...@googlegroups.com
Okay, I've read your email carefully. I think there's a basic problem with your interpretation of Alexander. The first thing is to understand the concepts properly! I'll try to explain briefly.

The four flip-flops capture samples at different points in time.

There is NO "realignment" - you need to maintain the time offset between samples.

If you "realign" the signals, you destroy the phase information you need to detect.

I'm concerned about what you're saying about the PLL because what you're saying indicates that:

  • The PLL isn't configured correctly for dynamic mode
  • Or the control signals aren't reaching the PLL
  • Or the adjustment range is incorrectly configured
I don't have a computer in front of me right now, so I can't calculate the PLL. Did you do the calculations correctly using the Icepll utility? Did you use an oscilloscope to measure whether the generated signal is correct?

If we don't know if Alexander works and the PLL doesn't show any signs of life, talking about the filter is pointless, even if your improvements look good at first glance.

charli va

unread,
Aug 6, 2025, 12:35:57 PMAug 6
to fpga-wars-explora...@googlegroups.com
I've now been able to sit down and look at this calmly. I think there are many misconceptions. We should start from the beginning with just the PLL.

Looking at your implementation, there seems to be fundamental confusion about clock management and PLL usage. Let me clarify some critical points:

Using a PLL to divide 100 MHz → 20 MHz makes no sense. A PLL is a complex analog circuit meant for:

  • Frequency multiplication
  • Phase adjustment
  • Clock cleaning/de-jittering

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.

Your current configuration issues:

  1. FDA_RELATIVE = 0: This means NO dynamic adjustment range at all
  2. FEEDBACK_PATH = "DELAY": Wrong mode for CDR applications
  3. Prescaler N=22: This would divide by 2^22 = 4 million (!), giving you 0.005 Hz, not 5 MHz

What exactly are you trying to achieve?

  • If you just need clock recovery → Simple oversampling works better than PLL phase adjustment
  • If you need phase adjustment → You must fix FDA_RELATIVE and FEEDBACK_PATH
  • If you need frequency tracking → PLL won't help; you need a different approach

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 😉

Moritz Meissner

unread,
Aug 7, 2025, 4:55:17 AMAug 7
to FPGAwars: explorando el lado libre

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

charli va

unread,
Aug 7, 2025, 7:07:53 AMAug 7
to fpga-wars-explora...@googlegroups.com
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?

Moritz Meissner

unread,
Aug 7, 2025, 7:41:21 AMAug 7
to FPGAwars: explorando el lado libre
Hi!

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

charli va

unread,
Aug 7, 2025, 11:05:09 AMAug 7
to fpga-wars-explora...@googlegroups.com
I read the paper and found it to be a very "creative" solution. I found it very intriguing to use the PLL's DYNAMICDELAY to see if there is a frequency difference, and if so, the sweep compensates for it.
"Simulating" a frequency shift is like using phase-based PWM to simulate a frequency shift. Although "suggestive," I find it very complex to implement in a real production system, and debugging can be difficult. I'm not saying it can't work, but it seems to me that it's a solution that requires very high fine tuning, and the probability of misalignment or failure is extremely high (it's my opinion and i could be wrong).

About FDA_RELATIVE with DYNAMIC mode: You're correct about the manual description. In DYNAMIC mode, FDA_RELATIVE sets the center point. With FDA_RELATIVE=0, you might be limiting your adjustment range. Try:

defparam top_pll_inst.FDA_RELATIVE = 4'b0111;

Much better, or so I think, for roughly the middle of the range.

I did some quick calculations and I could have made a mistake. I'm a master at calculator errors, XD. My dyslexia often lets me down. But I got the following calculation for a 256-node chain with RS485:
  • Each transceiver adds ~10-20 ns delay variation.
  • Total chain delay variation could be ~2-5 µs.
  • At 5 Mbps (200 ns bit period), you need aggressive jitter cleaning. 😱
To move forward with this solution, I suggest you ensure you have the following steps under control and with good data:
  • Test with two nodes first - Verify CDR works before scaling
  • Monitor PLL LOCK signal - It should remain stable
  • Scope the DYNAMICDELAY vs. output phase - Verify it's actually changing
  • Check your Alexander detector with the clock polarity fix we discussed, this should work ok.
In any case, I would recommend giving it some thought because I find the solution a bit complex, but that's just my opinion. I could be wrong as said before.

I think one thing that would work very well is to avoid using this scheme with PLL + Alexander + filter and move to a much simpler solution: a simple 8b/10b encoding + CDR + Retiming without PLL.

With this, you would have:
  • a jitter-resistant system
  • Easy to implement
  • Auto-sync with K-chars
  • Remove jitter (CDR+Retiming)
  • Fits perfectly in an iCE40UL1K
Advantages of 8b/10b for 256 Nodes:
  • Self-healing: K-chars allow automatic resynchronization
  • Error detection: Invalid codes indicate problems
  • No "blindness": Maximum 5 equal bits, always have transitions
  • Running disparity: DC balanced, best for RS485
Performing theoretical calculations, I would get:

WITH retiming (CDR + local clock):
Node 1: Jitter = 2 ns (oscillator only)
Node 256: Jitter = 2 ns × √256 = 32 ns (WORKS)

I can't think of anything else to tell you. I hope this helps. If you could send us specific things that can be tested relatively easily, or with a testbench already set up to simulate, it would be easier to help you. But in theory, this is the best I could come up with.

Have a nice day.

Craig

unread,
Aug 8, 2025, 2:28:33 AMAug 8
to FPGAwars: explorando el lado libre
Hi Moritz,

I'm just lurking in the background for this interesting application. Some thoughts for you:

Would you consider encoding your transmit clock with the data, as in an RTZ (return-to-zero) scheme, which should simplify your clock and data recovery a lot?

The extra complexity in combining the clock with the data would be compensated by the simpler and more direct clock recovery block.

What type of cable would you use to connect the nodes, and what kind of distances are you anticipating? Standard RS485 transceivers may only work up to 75 feet at 5 Mbps.

Also, regenerating the signal at every node would mean a single failure would bring down all the downstream nodes.  A bus approach should prevent that, but you still have to deal with interconnecting each node, which hopefully would just be a short interruption while the connections are made. After that, a node failure should just stop that one node from working.  

...Craig

zpl...@gmail.com

unread,
Aug 8, 2025, 2:28:41 AMAug 8
to fpga-wars-explora...@googlegroups.com
Hi Moritz,

I'm just lurking in the background for this interesting application. Some thoughts for you:

Would you consider encoding your transmit clock with the data, as in an RTZ
(return-to-zero) scheme, which should simplify your clock and data recovery a lot?

The extra complexity in combining the clock with the data would be compensated by the simpler and more direct clock recovery block.

What type of cable would you use to connect the nodes, and what kind of distances are you anticipating? Standard RS485 transceivers may only work up to 75 feet at 5 Mbps.

Also, regenerating the signal at every node would mean a single failure would bring down all the downstream nodes.  A bus approach should prevent that, but you still have to deal with interconnecting each node, which hopefully would just be a short interruption while the connections are made. After that, a node failure should just stop that one node from working.  

...Craig

On Thu, Aug 7, 2025 at 7:41 AM Moritz Meissner <facebo...@gmail.com> wrote:
Hi!

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?

Screenshot 2025-08-06 at 16.17.11.png
And connect to the output of the inverse clock from not gate:

Screenshot 2025-08-06 at 16.17.36.png
--
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 .

--
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 .

Craig

unread,
Aug 8, 2025, 11:03:55 AMAug 8
to FPGAwars: explorando el lado libre
Sorry about the duplicate. Original email was sent early Aug 7 but took many hours to pass the moderation test and the contact link for the Owners resulted in Google's "group does not accept emails addressed to the group owner or admin.", so I wasn't sure it was going through.

By then, Charliva's excellent post had a similar and more detailed suggestion!

...Craig

charli va

unread,
Aug 8, 2025, 11:09:41 AMAug 8
to fpga-wars-explora...@googlegroups.com
Hi Craig! Sorry for the confusion. The forum is monitored for the first 1-2 messages a user posts, then they go immediately. The next one you send will probably appear almost immediately ;)

Thanks for your contributions. I hope they're helpful to Moritz. I thought what you suggested about points of failure and bus mode was very important. It's a great idea to have a bus where elements can fall without stopping the system.

And regarding the encoding protocol, it's another excellent option. The important thing here is not to lose the bit! And if possible, do it as simply as possible.

What you mentioned about RS485 in terms of distance makes me wonder if you have any restrictions on choosing RS485. Migrating the solution to LVDS would be a great improvement to the system and would save you a lot of problems.

Have a good evening!

--
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.

Alexander Lang

unread,
Aug 8, 2025, 11:25:29 AMAug 8
to fpga-wars-explora...@googlegroups.com
I must admit as soon as I heard the application I wondered why DMX - a version of RS485 wasn't being employed as that is what most professionally controlled lighting systems use.

Alex

charli va

unread,
Aug 8, 2025, 12:45:21 PMAug 8
to fpga-wars-explora...@googlegroups.com
I love it when there's interaction, you learn a lot. I didn't know the DMX protocol, and I have no idea about the professional lighting world, but I found it super interesting.

Thanks so much, Alex!

Moritz Meissner

unread,
Aug 14, 2025, 7:54:19 AMAug 14
to FPGAwars: explorando el lado libre

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 12Mhz:


PLL from 12Mhz to 60Mhz:


PLL from 12Mhz to 160Mhz:



The last question is: In the screenshot "PLL from 12MHz to 160MHz," we see a massive voltage drop. What is the cause of this?

Thank you very much and best regards,

Moritz

Craig

unread,
Aug 14, 2025, 9:23:05 AMAug 14
to FPGAwars: explorando el lado libre
Hi Moritz, you need to keep in mind that whatever oscillator and dividers you use, your final accuracy can never be better than that of the oscillator. So if you use a 25 MHz TCXO (fairly inexpensive) rated at 3-5 PPM initial accuracy (ignoring aging and temperature, etc), it may give you a final accuracy of +/- 10 PPM over the life of the product. For 1,000 bytes, or 8,000 bits, the sampling clock may then drift by 8,000 x 1E-5 or 8%. A 5 MHz bit rate gives you 200 nSec to play with, so after resyncing, the data sampling clock edge could be off by 8% of 200 nSec = 16 nSec. Adding the initial reference starting uncertainty (say, two TCXO clock periods at 40 nSec each) gets you to 96 nSec worst case. Looks fine to me. No PLL required, though it could be useful for other things, like loss-of-signal detection, etc.

I still think that RS485 (or DMX) may max out at less than 100 feet at 5 Mbps though. Check the distance vs data rate charts for that.

...Craig

charli va

unread,
Aug 14, 2025, 10:15:09 AMAug 14
to fpga-wars-explora...@googlegroups.com

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!


Reply all
Reply to author
Forward
0 new messages