4
\$\begingroup\$

I have this simple program running on the Altera EPM240 that’s sometimes not doing the counter increment.

reg trigger_state;
reg [7:0] trigger_count;

always @ (posedge clk)
begin
    if (trigger != trigger_state) begin
      trigger_state <= !trigger_state;
      trigger_count <= trigger_count + 1;
    end
end

clk is running at 50 MHz, and the trigger signal in the picture at 1-2 kHz.

Enter image description here

In the picture (trigger=6, trigger_state=4, trigger_count[1]=1, trigger_count[0]=2)

As you can see, trigger_state always follows the input signal (trigger), but the counter (2) is sometimes not incremented.

What could explain such a behavior?

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Where is "Trigger" coming from? Is it from an external signal or switch? If so, have you put any synchronisation on it? \$\endgroup\$ Commented Jan 21, 2018 at 14:52

3 Answers 3

7
\$\begingroup\$

Fist of all:
Your trigger is coming in a-synchronous to the clock. You must first synchronize it before you can safely use it. The code for that is:

reg sync_trigger,safe_trigger;
always @(posedge clk)
begin
    sync_trigger <= trigger;
    safe_trigger <= sync_trigger;
end

The behavior your are seeing is because the hardware will more look like this:

if (trigger != trigger_state) 
  trigger_state <= !trigger_state;

if (trigger != trigger_state) 
  trigger_count <= trigger_count + 1;

As the trigger is a-synchronous you can have that one if is true and the other is false. Thus one is acted up and the other not. In fact it is implemented for every BIT of your counter so some bits may increment and others not.

Post thought:
Your trigger must be slower then your clock otherwise you will miss triggers!

\$\endgroup\$
1
  • \$\begingroup\$ What about storing the external signal in a SR latch to prevent missing the trigger? \$\endgroup\$ Commented Aug 20, 2021 at 15:46
9
\$\begingroup\$

Is the trigger input completely asynchronous to the 50MHz clock? If so, it probably violates the setup and hold time requirements from time to time. You need to synchronize it to the clock through at least two FFs before you use it in any decision making.

I can hear you saying, "But it's only used in one if statement. If the trigger_state gets updated, doesn't that guarantee that trigger_count gets updated, too?"

The answer is "no."

trigger_state and trigger_count represent a total of nine separate FFs, and each one of them has its own combinatorial logic to determine what its next state will be. Each one takes trigger as an input, and they each make an independent decision about what the value of trigger is. If you violate the setup/hold time requirements, you can no longer guarantee that those independent decisions will be consistent, leading to the behavior that you observe.

Note that this has nothing to do with metastability, although synchronizing asynchronous inputs mitigates that problem, too.

\$\endgroup\$
4
\$\begingroup\$

The problem is most likely meta-stability caused by using an asynchronous signal (your input trigger) to control your counter.

When bringing any signal in, you need to make sure it is synchronised to the clock signal using a multi-register synchroniser chain. Something like:

reg [1:0] triggerSync;
always @ (posedge clk) begin
    triggerSync <= {triggerSync[0],trigger}
end

Then use triggerSync[1] in your code. The first register triggerSync[0] will synchronise the signal but may go metastable if the input changes as the clock is changing (setup/hold violation). The second register triggerSync[1] catches the metastable state and stops it propagating through the rest of your logic causing weird glitches.

Your logic itself also seems weird. I would suggest splitting it up into your edge detector logic, and your counter:

reg triggerDly;
wire triggerEdge;
always @ (posedge clk) begin
    triggerDly <= triggerSync[1];
end
assign triggerEdge = (triggerDly != triggerSync[1]);

always @ (posedge clk) begin
    if (triggerEdge) begin
        trigger_count <= trigger_count + 1;
    end
end

Splitting everything up makes the code easier to follow and debug. You can also easily modify the edge detector logic to be rising edge, falling edge, or both. You might as well also make the edge detector a submodule as its a useful bit of code to reuse.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ It basically impossible to observe metastability events at 50 MHz on modern technology unless you've got a congested design with no slack. As Dave elucidates, this is probably a coherency issue. The solution is the same (sync FFs), but the problem is different. \$\endgroup\$
    – jalalipop
    Commented Jan 22, 2018 at 14:41

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.