Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Novice
71 Views

All code not being run every time

Jump to solution

I have a verilog module designed to process an encoder signal, I have been having problems so have cut it down to a minimum that demonstrates the kind of problem.  File is attached (and cited below).

The code receives a clk signal (25MHz output of a PLL), and a time (now, count of a 1MHz clock).  enc is an input from an encoder on a motor (provides pulses approximately 20kHz).

The if block is activated on a negative edge of the encoder.  For the majority of pulses the code behaves correctly and all code in the block is executed.  Occasionally, some or none of the code is executed.  I do not understand how this can be the case.

This image shows a signal tap of most of the block's signals.  At just after t=-1280, there is a negative edge, the enc_pulse is taken high, but the count is not incremented, the enc_prev_time and enc_time are not updated.

The image also shows a 'well-behaving' edge just after t=-2560.

Could someone explain how this can be?

Q.png

module encoder (
	input clk,
	input enc,
	input [31:0] now,
	output reg [15:0]	count,
	output reg enc_pulse,
	output missed_enc
	);

reg enc_prev;
reg marker_prev;
reg new_marker;

reg [31:0] enc_time;
reg [31:0] enc_prev_time;

initial begin
	count <= 16'd512;	// Start count mid rev.  First rev will be invalid.
	enc_pulse <= 0;
end

assign missed_enc = (enc_time - enc_prev_time) > 64;

always @ (posedge clk) begin
	
	if (enc == 0 && enc_prev == 1) begin	// trigger on encoder falling edge
		enc_pulse = 1;
		count = count + 16'd1;
		enc_prev_time = enc_time;
		enc_time = now;
	end
	else begin
		enc_pulse = 0;
	end
	enc_prev = enc;
end
endmodule

 

0 Kudos

Accepted Solutions
Highlighted
Retired Employee
62 Views

It's hard to tell without zooming in, but it looks like enc and enc_prev are going low simultaneously, so they wouldn't trigger the if statement at all.  You might be seeing glitches because enc is not registered.  It looks like a truly asynchronous input, so there's no guarantees with that if statement.  I'd register enc and then do the if check.

If you do, you might also think about doing negedge enc in the sensitivity list.

#iwork4intel

View solution in original post

4 Replies
Highlighted
Retired Employee
63 Views

It's hard to tell without zooming in, but it looks like enc and enc_prev are going low simultaneously, so they wouldn't trigger the if statement at all.  You might be seeing glitches because enc is not registered.  It looks like a truly asynchronous input, so there's no guarantees with that if statement.  I'd register enc and then do the if check.

If you do, you might also think about doing negedge enc in the sensitivity list.

#iwork4intel

View solution in original post

Highlighted
Novice
53 Views

Thanks for the reply.

The enc and enc_prev are not quite simultaneous, since enc_prev is enc clocked at the next clock edge.

I have zoomed in to show it more clearly.

What is truly confusing me is if block has 4 lines.

  1. enc_pulse is taken high.
  2. count is incremented.
  3. enc_prev_time becomes enc_time.
  4. enc_time becomes now.

As you can see from the diagram (1) is being run, but (2-4) are not.  How can this be?
n.b. I am currently using blocking assignments.  I originally used non-blocking, but changed during my investigation.  It made no difference.

	if (enc == 0 && enc_prev == 1) begin	// trigger on encoder falling edge
		enc_pulse = 1;
		count = count + 16'd1;
		enc_prev_time = enc_time;
		enc_time = now;
	end



Q2.png

I'm relatively new to verilog.  What do you mean exactly by "registering enc"?

0 Kudos
Highlighted
Novice
50 Views

I've worked out what you mean by "registering" by giving it more thought.

The code below does what I think you suggested.  The 'missing_enc' line is my error detector that I trigger from in Signal Tap.  This never triggers, so I think this is fixed.  The alternative is that I have broken my error detector.

module encoder (
	input clk,
	input enc,
	input [31:0] now,
	output reg [15:0]	count,
	output enc_pulse,
	output missed_enc
	);

reg enc_reg;
reg enc_prev;

reg [31:0] enc_time;
reg [31:0] enc_prev_time;

assign enc_pulse = enc_prev & !enc_reg;
assign missed_enc = (enc_time - enc_prev_time) > 64;

// No initial block.  First rev will always be invalid anyway.
// System has no interest until up to speed.

always @ (posedge clk) begin
	enc_prev <= enc_reg;
	enc_reg <= enc;
end

always @ (negedge enc_reg) begin	
	count <= count + 16'd1;
	enc_prev_time <= enc_time;
	enc_time <= now;
end

endmodule

 

0 Kudos
Highlighted
Retired Employee
44 Views

Yes, this is what I was talking about.  Glad it's working correctly now.

#iwork4intel