Fred said:

My outputs are only approximately in quadrature, because I have

synchronized all inputs and outputs to the clk frequency. This clk signal

is intended to be, say, a 10 MHz clock.

I don't think this would cause any problems. Afterall, the period of a

10 MHz clock is only 100 nS, and a delay of a few hundred nanoseconds

shouldn't cause any problem for an encoder running in the KHz range.

Here is the basic idea:

__ __ __ __ __ __ __ __ __ __ _

a_in _| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__|

__ __ __ __ __ __ __ __ __ __

b_in __| |__| |__| |__| |__| |__| |__| |__| |__| |__| |__

cnt 0 1 2 3 0 1 2 3 0 1 2

__________ __________ __________

a_out |____________| |____________| |_____

___________ ___________ __________

b_out ____| |___________| |___________|

If the encoder is rotating in the other direction, everything is the

same,

but swapped left to right, which is exactly what we want.

The rule for calculating a_out is: a_out is high when count is 0 or 1,

and

low otherwise.

The rule for calculating b_out is: b_out is high when count is 1 or 2,

and

low otherwise.

The rule for calculating cnt is a little bit tricky, so stick with me.

There are four input encoder states:

state | a_in | b_in

======|======|=====

i | 0 | 0

ii | 1 | 0

iii | 1 | 1

iv | 0 | 1

As the states progress from 'i' to 'iv' as shown above, the shaft is

rotating (let's just say) clockwise. To calculate count, what we want to

do is pick one of those transitions and define it as the key transition.

For example, we could say that whenever we go from state 'i' to state

'ii', we should increment cnt. Likewise, when we go from state 'ii' to

state 'i' we should decrement cnt. Then, if the shaft goes back and forth

at the i/ii boundary, count will also go back and forth, and a_out and

b_out will behave correctly (that is, as if they were real encoder

signals).

So, assuming, once again, that we have some fast clock lying around (10

MHz would probably work fine), I would just sample a_in and b_in every

clock period, and look for the transitions mentioned above. These would

cause cnt to increase and decrease in the desired way, and a_out and

b_out would then track cnt, thus giving the correct output.

Probably there is another way to do this which doesn't involve using a

separate clock, but it isn't coming to me immediately, and since this

will

probably work on a small PLD anyway, why bother trying to screw with it?

Here is another untested verilog module. This one differs from the

earlier

one because I use a much more sophisticated (and correct) way of

calculating cnt, and I changed the outputs so they are no longer

clocked, but just depend combinatorially on cnt. Note that cnt is still

synchronous to clk.

module quad_div(a_in, b_in, clk, rst, a_out, b_out);

input a_in, b_in, clk, rst;

output a_out, b_out;

reg [1:0] cnt;

reg a_in_r, b_in_r, a_in_d, b_in_d; // r for register, d for delayed.

assign a_out = ((cnt == 0) || (cnt == 1));

assign b_out = ((cnt == 1) || (cnt == 2));

always @(posedge clk or posedge rst)

begin

if (rst) begin

cnt <= 0;

a_in_r <= 1;

b_in_r <= 1;

a_in_d <= 1;

b_in_d <= 1;

end

else begin

a_in_r <= a_in;

b_in_r <= b_in;

a_in_d <= a_in_r;

b_in_d <= b_in_r;

if (({a_in_d, b_in_d} == 0) && ({a_in_r, b_in_r} == 2))

cnt <= cnt + 1;

else if (({a_in_d, b_in_d} == 2) && ({a_in_r, b_in_r} == 0))

cnt <= cnt - 1;

end

end

Your algorithm also accumulates error and your mistake is to fix the AB

condition at which you make an increment/decrement decision. I have

included what I believe to be 'a' Verilog specification of a working

machine that expands upon your original idea- but one never knows when

using online Verilog "manuals" written by

[email protected]#$%^& imbeciles who wouldn't

know precision of expression if it blew up in their face. What is it

with this weak language that it has no multidimensional conditional

assignments?- can't believe that. To make a long story short: you must

expand the 'cnt' register to a 4-bit, the a/b_out variables are now a

function of the msb two bits per your original formulation, the lsb two

bits bidirectionally count transitions on the AB state with increments

on CW rotation and decrements on CCW rotations. The lsb two bits

naturally over/under-flow into the two msb bits of cnt modulo 4,

everything stays modulo 4, all motion is accumulated modulo 4 by cnt at

each encoder boundary crossing. At any instant cnt[3,2] contains the

modulo-16 sum of the net total of CW - CCW encoder increments off its

state when quad-div was 'rst', cnt[1,0] is the modulo-4 sum of this

total, and cnt[3,2] is the modulo-4 sum of the cnt[1,0] over/underflows.

So that mathematically you will have CW-CCW= q*4 + r where r=0,1,2, or 3

, and q=q'*4+r' where r'=0,1,2, or 3. Then CW-CCW=q'*16+r'*4+r so that

CW-CCW MOD 16= r'*4+r. The content of cnt[1,0] is obviously r, and the

total number of overflows into cnt[3,2] from cnt[1,0] is obviously q, so

that cnt[3,2] contains q MOD 4 or r' making cnt[3,0] binary value r'*4+r

or CW-CCW MOD 16 as required. If CW-CCW is negative, CW-CCW=q''*16+r''

where r''=0,1,2,...,15 and q''*16<=CW-CCW so that this is a composite

motion of q'' groups of 16 CCW encoder transitions, which land cnt[3,0]

at state 0, followed by r'' CW encoder transitions. Then r''=q*4 +r as

before, q>=0 and r=0,1,2,3, with q=q'*4+r', r'=0,...,3, with cnt[3,2]=r'

and cnt[1,0]=r.

In summary then, the instantaneous state of cnt[3,0] is exactly the net

number of signed encoder increments off its arbitrary state at quad_div

rst, cnt[1,0] is always the net number of encoder cell signed

transitions off the initial state, and cnt[3,2] is the net number of

signed encoder cell groups of 4 or the DIV 4 output sought. This one

*never* slips- *never* accumulates error-*never* delays, and is easily

extended to any DIV number except the quadrature output transitions

become impractical to compute in the PLD, will have to make that an

external register entry of some kind- at any rate you can run this one

at arbitrarily high speeds without limitation. If you want direction

outputs then set CW=1 whenever you do a cnt<=cnt+1, so make this

variable CW/CCW I suppose.

View in a fixed-width font such as Courier.

module quad_div(a_in, b_in, clk, rst, a_out, b_out);

input a_in, b_in, clk, rst;

output a_out, b_out;

reg [3:0] cnt;

reg abr[1,0], abd[1,0]; // r for register, d for delayed.

assign a_out = ((cnt[3,2]== 0) || (cnt[3,2]== 1));

assign b_out = ((cnt[3,2]== 1) || (cnt[3,2]== 2));

always @(posedge clk or posedge rst)

begin

if (rst)

begin

cnt <=0;

abr<=0;

abd<=0;

end

else

begin

abr<= {a_in,b_in};

abd<= abr;

if ( abd != abr )

case abd

0: case abr

1: cnt<=cnt-1;

2: cnt<=cnt+1;

default: cnt<=cnt;

endcase

1: case abr

3: cnt<=cnt-1;

0: cnt<=cnt+1;

default: cnt<=cnt;

endcase

2: case abr

0: cnt<=cnt-1;

3: cnt<=cnt+1;

default: cnt<=cnt;

endcase

3: case abr

2: cnt<=cnt-1;

1: cnt<=cnt+1;

default: cnt<=cnt;

endcase

endcase

end

end

Let's take this one step further and duplicate the performance of that

DigitalControls divide by user selected N for N=1 to 4096 or a 12-bit

divisor, with quadrature outputs at "exactly" 50% each. The PLD running

off of a high speed external clock makes this very easy. The way to

achieve 50% duty at arbitrary divide ratios is to note that the actual

divide of encoder resolution cell transitions is 4xN which happens to be

Nx4, so that by counting these transitions in 4 groups of N, you

naturally end up with your processed encode output using the rule that

a_out is high during the 1st and 2nd N-group count, and b_out is high

during the second and 3rd N-group count, both a_out and b_out low during

4th N-group count. The simplest conceptual implementation of this would

be a bidirectional counter that counts between states 1 and N

inclusively where overflow out of state N is to state 1, and underflow

from state 1 is to state N. The accumulator functions as before totaling

out to the net CW-CCW resolution cell travel off the reset zero point. A

simple state machine in a_out, b_out transitioning on these counter

over/under-flows then produces the required outputs. I am assuming the

use of these so-called "non-blocking" state assignments in Verilog, and

this works out nicely even in the usually degenerate case of N=1 which

is no problem in a machine working from a much higher frequency external

clock. The state machine logic on a_out,b_out is then simply

a_out<=~b_out and b_out<=a_out on N-count overflow, and a_out<=b_out and

b_out<=~a_out on N-count underflow, initial state a_out=1, b_out=0 on

'rst'. The original Verilog routine is now easily upgraded since it

already contains the encoder transition logic- pasting this thing

together-(may or may not be totally correct):

View in a fixed-width font such as Courier.

module quad_div(a_in, b_in, clk, rst, a_out, b_out,n11,...,n0,cw,ccw)

input a_in, b_in, clk, rst, n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0

// n11,n10,...,n0 division ratio

output a_out, b_out, cw, ccw; //cw , ccw direction outputs

reg [11:0] cnt;

reg [1:0] abr;// r for register

reg [1:0] abd;// d for delayed

reg [1:0] abo;// o for divided a,b outputs

reg [1:0] dir;// direction output dir[1]=cw dir[0]=ccw

assign a_out=abo[1];

assign b_out=abo[0];

assign cw=dir[1];

assign ccw=dir[0];

always @(posedge clk or posedge rst)

begin

if (rst)

begin

cnt <=0;

abr<=0;

abd<=0;

abo<=2;

dir<=0;

end

else

begin

abr<= {a_in,b_in};

abd<= abr;

if ( abd != abr )

case abd

0: case abr

1:begin //cnt<=cnt-1

dir<=1;

if(cnt==1)

cnt<={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0};

abo<={abo[0],~abo[1]};

else

cnt<=cnt-1;

end

2:begin //cnt<=cnt+1

dir<=2;

if (cnt=={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0})

cnt<=1;

abo<={~abo[0],abo[1]};

else

cnt<=cnt+1;

end

default: cnt<=cnt;

endcase

1: case abr

3: begin //cnt<=cnt-1

dir<=1

if(cnt==1)

cnt<={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0};

abo<={abo[0],~abo[1]};

else

cnt<=cnt-1;

end

0: begin //cnt<=cnt+1

dir<=2;

if (cnt=={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0})

cnt<=1;

abo<={~abo[0],abo[1]};

else

cnt<=cnt+1;

end

default: cnt<=cnt;

endcase

2: case abr

0:begin //cnt<=cnt-1

dir<=1;

if(cnt==1)

cnt<={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0};

abo<={abo[0],~abo[1]};

else

cnt<=cnt-1;

end

3:begin //cnt<=cnt+1

dir<=2;

if (cnt=={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0})

cnt<=1;

abo<={~abo[0],abo[1]};

else

cnt<=cnt+1;

end

default: cnt<=cnt;

endcase

3: case abr

2:begin //cnt<=cnt-1

dir<=1;

if(cnt==1)

cnt<={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0};

abo<={abo[0],~abo[1]};

else

cnt<=cnt-1;

end

1:begin //cnt<=cnt+1

dir<=2;

if (cnt=={n11,n10,n9,n8,n7,n6,n5,n4,n3,n2,n1,n0})

cnt<=1;

abo<={~abo[0],abo[1]};

else

cnt<=cnt+1;

end

default: cnt<=cnt;

endcase

endcase

end

end