Synchronization: Setting and Clearing a Value using Different Clocks/Processes

My FPGA has 50Mhz clock (clk). From this clock I have a module that generates a 9600 baud clock (baudTick).

UART_BaudRate_generator #(baudRate) BaudGen1(
    .Clk( clk ),
    .Tick( baudTick ) );

Every 50000000 clk cycles (every second) I want to transmit some text to my PC.

always_ff @( posedge clk )
begin
  counter ++;
  
  if( counter > 50000000 ) // 1Hz
  begin
    counter = 0;
    secondCount ++;
    
    myString = getStr();
    addStringToQueue = 1;
  end
end

I have a CharacterTransmitter module which adds a copy of myString to an internal queue when addStringToQueue is high.

CharacterTransmitter charTransmitter( myString, addStringToQueue, baudTick, o101 );

CharacterTransmitter runs off the baudTick clock.

What I want to do is reset addStringToQueue after one baudTick clock cycle has passed.

My problem is that I cannot set it inside the always_ff @( posedge clk ) block/process and within another always_ff @( negedge baudTick ) process because of the “mulitple constant drivers” error I receive. I understand that only one always block should be setting an output.

So how would I go about setting and clearing my addStringToQueue flag in this scenario? I know I could use the clk block to keep it high for a number of clk cycles but I’d prefer to clear the flag when an actual baudTick has elapsed.

The only way I can think of doing this is to get the CharacterTransmitter to return a gotString output that is high for one baudTick upon consumption. Is this the way I should be going?

My software brain is longing for something like a shared semaphore in this case.

In reply to SparkyNZ:

Welcome to FPGA design. You want everything synchronous to the one clk. (Ask why perhaps in another thread/somewhere else).

Since “baudTick” is (one assumes) generated from clk, you can make a (synchronous) falling edge detector.


bit baudTick_d;
always @( posedge clk )
  baudTick_d <= baudTick;  // Note change all your assignments to non-blocking in your clocked procedural block!

wire fall_baudTick = baud_Tick_d & ~baudTick;

Now use your new falling edge detector synchronously, in the same procedural block:

always_ff @( posedge clk )
begin
  if( fall_baudTick )
    addStringToQueue <= 0;
  
  counter <= counter + 1'b1;   // non-blocking!! 
  if( counter > 50000000 ) // 1Hz
  //...
end

Note: Also consider your requirements of your comparison for 1 Hz. If you can change your comparitor to a power of 2, you’re implementation will be quite a bit smaller.

In reply to Mark Curry:

Thanks Mark. Fundamentally, I think I know where you’re coming from. :-) Yes, my baud clock is generated from the master clk so I can see what you’re suggesting on principle - ie - the baudTick will either rise or fall on one of the clk transitions. I will have try and get my head around this.

I get that the <= operators are non-blocking but I’m still very grey about the actual assignment behaviour (more learning I’m going to have to research). For example, I get how an assign statement asynchronously works… but when the non-blocking assignments appear within and before conditions, I have to question this behaviour:

counter <= counter + 1'b1;   // non-blocking!! 
  if( counter > 50000000 ) // 1Hz
    counter <= counter + 2'b1;

For example, in the code snippet above, the 2 counter assignments would still occur in sequence wouldn’t they?

Some of the CDC stuff I was reading earlier this morning was far too much to digest. However, you have given me a new sense of hope in that I may be able to avoid cross-domain concerns for now. I honestly thought I was going to have to follow something like this:

https://www.fpga4fun.com/CrossClockDomain3.html

In reply to SparkyNZ:

I’ve done some more reading on blocking vs non-blocking assignments and I’m confused even more. The use of language seems contradictory to me:

always @(posedge i_clock)
begin
  r_Test_1 <= 1'b1;
  r_Test_2 <= r_Test_1;
  r_Test_3 <= r_Test_2;
end

The always block in the Verilog code above uses the Nonblocking Assignment, which means that it will take 3 clock cycles for the value 1 to propagate from r_Test_1 to r_Test_3.

OK, that’s a new concept for me to grasp but I can - at least where there are no if() statements involved. It’s defining a chain and value propagation is linked to i_clock cycles.

*Now consider this code:
*

always @(posedge i_clock)
begin
  r_Test_1 = 1'b1;
  r_Test_2 = r_Test_1;
  r_Test_3 = r_Test_2;
end

*See the difference? In the always block above, the Blocking Assignment is used. In this example, the value 1 will immediately propagate to r_Test_3. The Blocking assignment immediately takes the value in the right-hand-side and assigns it to the left hand side. Here’s a good rule of thumb for Verilog:

In Verilog, if you want to create sequential logic use a clocked always block with Nonblocking assignments.*"

That last sentence confuses me completely. “Sequential logic” to me suggests steps - things (assignments) that happen in sequence. But what does “sequential logic” really mean in this context? Does “sequential” really mean “logic associated with a clock” rather than “logic evaluation in the order of Verilog statements” ?

So… when I read “sequential logic” (and use of non-blocking assignments), should I be trying to think of how a value will propagate every clock cycle rather than thinking about the ordering of the lines of code?

I read that the last non-blocking assignment will always be the one which is evaluated in a clock cycle. OK.

So do if() statements really affect non-blocking assignments in a different way to a blocking assignment? I guess not… unless a sequence of if() statements are provided:

if( flag )
  val <= val + 1'b1;

if( val % 2 == 0 )
  val <= val + 1'b3;

What would happen here? if flag is true and (val % 2) is 0, does that mean that only the val <= val + 1’b3 statement would be take effect in this clock cycle? (ie. the val <= val + 1’b1 statement is irrelevant in this case?

In reply to SparkyNZ:

There’s lots of papers and tutorials regarding non-blocking vs blocking operators and when to use them, so I won’t repeat that here. The canonical paper, IMHO, is Cliff Cummings:
Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!

But to quickly answer a misconception: What is sequential logic? It’s any memory element (i.e. a Flip-Flop, or a memory) that’s triggered by a clock. (Let’s ignore latches or other more esoteric kinds of memory out of the discussion).

If you’re not describing “sequential” logic, you’re describing “combinational” logic. Most (normal) logic can be broken down into one of these two types.

Edit to add: You can safely ignore the CDC stuff for now, since you’re operating on just one clock.

Regards,
Mark

In reply to Mark Curry:

Haha. Cliff’s paper was the one I spent most time with yesterday. There were a couple of things missing that stopped his examples from clicking. It’s often just a matter of findin a number of different explanations on the same thing unless I’m lucky enough to find one with just the right language and examples.

Thanks regarding “sequential”. That all makes sense now. So “combinational” is basically things like a bunch of AND/OR gates wired together that change immediately when inputs is varied but don’t involve saving states in relation to a clock (as do flip-flops). Great. Got it. Hopefully this will now me committed to my memory :-)

I hope I don’t have to revist CDC any time soon - I’ll be wanting to get a DRAM controller working next (the serial transmission I was working on was supposed to help me debug my DRAM controller and VGA controller larger project). Every little helps the learning experience. But both the VGA and DRAM controller should also be derived from the main clock.

I haven’t played around with PLL modules at all yet. I’m hoping they would also not require CDC if they’re derived from the same clock but I’ll cross that bridge when I come to it.