Maker Pro
Maker Pro

Stupid 4024 freq divider question (shaft encoder resolution)

L

Larry Brasfield

Jan 1, 1970
0
Fred Bloggs said:
Larry said:
Larry Brasfield wrote:



Mac wrote:


I think all you have to do is make it so that A_OUT is high
when count = 0 or 1, and B_OUT is high when count = 1 or 2.

That's obviously flawed- A and B are then in anti-phase and not
quadrature. I am assuming here that A is LOW when it's not HIGH
and vice-versa, but maybe...

You should not assume that what is obvious to you is true.

A_OUT and B_OUT, as Mac described them, are not anti-phase. Read
more carefully. They are true for a pair of input state sets
that are not disjoint. This means they can both be true at the
same time. And a little more attention to Mac's post (the part
you cut) would show that those outputs are, in fact, in
quadrature for any monotonic counting sequence. [meaningless noise cut]
And what is your "clk"?- an unspecified input.


Irrelevant. What clock can you construct, in this universe, that
will cause A_OUT and B_OUT to be anti-phase when, for some inputs,
they have the same value?

There is no conceivable way a single counter can produce true quadrature outputs synchronous to the appropriate edges. You would
need to use some dumb doubler thing.

Have you ever heard of asynchronous state machines?
Why don't you have the counter count its output as "clk"- that would be as rational as anything else you have suggested thus far.

My preference would be that the divide-by-4
counter effect a grey-code sequence.

I take it, by your change of subject and refusal to
address my point about disjoint sets, that you are
unable to defend your denigration of Mac's post.

You should know, Fred, that it is OK to be wrong
once in a while. You would garner more respect if
you could admit your mistakes.
 
L

Larry Brasfield

Jan 1, 1970
0
Fred Bloggs said:
Controller- shmoller/ there is no way in hell any general purpose positioning system is going to set itself up for "hunting" by
adjusting around what by definition is an encoder boundary - and an encoder that may or may not be detented at that. What are you
going to do? Jog the thing into what you imagine to be mid- resolution cell? Now it will jog into mid- 1/250th instead of
1/1000th.

Are you claiming that general purpose positioning
systems have eliminated hunting? I would love to
learn more about this.

If there is hunting, and it is not around an encoder
boundary, then decreasing encoder resolution is
bound to increase the magnitude of hunting motion.

As you may infer from my statements so far, I am
not proposing any particular way of dealing with
hunting, or even claiming it mattered to the OP.
All of this is dog standard practice- to listen to you, you invented the whole field.

Calm down. You are imagining things now.
 
F

Fred Bloggs

Jan 1, 1970
0
Larry said:
[meaningless noise cut]
There is no conceivable way a single counter can produce true
quadrature outputs synchronous to the appropriate edges. You would
need to use some dumb doubler thing.


Have you ever heard of asynchronous state machines?

Trust me- there will be little to nothing you will be able to tell me.
My preference would be that the divide-by-4 counter effect a
grey-code sequence.

The "grey-code" sequence was invented out of necessity of minimizing
adjacent resolution cell measurement error in multi-bit encoders. It has
little to nothing to do with two separate quadrature one-bit channels.
I take it, by your change of subject and refusal to address my point
about disjoint sets, that you are unable to defend your denigration
of Mac's post.

I will retract the denigration when this magical "clk" input is
specified. AFIK, that encoder is outputting A/B, maybe a direction
signal, and maybe an index. Which one of those is "clk"?
You should know, Fred, that it is OK to be wrong once in a while.
You would garner more respect if you could admit your mistakes.

I am not going to give serious consideration to an underspecified
Verilog file- that's nothing more than an ASCII wish. If Mac could write
it, why couldn't he simulate it? Or was it he would have to figure what
"clk" is?
 
F

Fred Bloggs

Jan 1, 1970
0
Larry said:
Are you claiming that general purpose positioning
systems have eliminated hunting? I would love to
learn more about this.

If there is hunting, and it is not around an encoder
boundary, then decreasing encoder resolution is
bound to increase the magnitude of hunting motion.

I don't think it's that complicated. This is a almost certainly a
controller designed for "cutting" tool applications. The most important
specification there will be feed rate- and this will be some thing much
slower than the controller "dynamics"- the controller can most likely
estimate resolution cell travel per unit time with great accuracy so as
to cut the feed drive with great precision just past one encoder reading
prior to endpoint- or it can start tapering the feedrate down several
cells prior to endpoint which makes the "dynamics" even more irrelevant.
 
J

John Woodgate

Jan 1, 1970
0
I read in sci.electronics.design that Larry Brasfield <donotspam_larry_b
[email protected]> wrote (in <[email protected]>)
about 'Stupid 4024 freq divider question (shaft encoder resolution)', on
Sat, 26 Feb 2005:
Are you claiming that general purpose positioning systems have
eliminated hunting? I would love to learn more about this.

I suppose you could describe the British Labour Party as a general
purpose positioning system, but maybe 'posturing system' would be more
accurate. (;-)
 
M

Mac

Jan 1, 1970
0
That's obviously flawed- A and B are then in anti-phase and not
quadrature. I am assuming here that A is LOW when it's not HIGH and
vice-versa, but maybe...

Your assumption is correct. A and B are low when I haven't explicitly
stated that they are high.

And even so, A and B are obviously NOT in antiphase. The "count" scheme
was described in a previous post in this thread. It is NOT a simple
counter, but a state machine which can count up or down depending on what
the A and B inputs are doing.

Here is a possible cycle of sequential states:

count| a_out | b_out
00 | 1 | 0
01 | 1 | 1
10 | 0 | 1
11 | 0 | 0
00 | 1 | 0
01 | 1 | 1

And so on. Do you now agree that a_out and b_out are in quadrature given
the shown progression of count?

There IS a problem with my verilog (which you snipped) but it has to do
with back-and-forth transitions. For example, if the shaft is manipulated
back and forth in the right place, the count can increase without bound.
This will make the output incorrect. But this can be fixed simply by
changing the way count is calculated. If I am not too lazy, I will post
such a fix later.

The OP won't be reading again until Monday, IIRC.

--Mac
 
M

Mac

Jan 1, 1970
0
Really? And what is your "clk"?- an unspecified input.

clk was discussed earlier in the thread. It is a normal digital clock
which is much faster than the quadrature inputs.

--Mac
 
M

Mac

Jan 1, 1970
0
Larry said:
Larry Brasfield wrote:



Larry Brasfield wrote:





Mac wrote:



I think all you have to do is make it so that A_OUT is
high when count = 0 or 1, and B_OUT is high when count =
1 or 2.

That's obviously flawed- A and B are then in anti-phase and
not quadrature. I am assuming here that A is LOW when it's
not HIGH and vice-versa, but maybe...

You should not assume that what is obvious to you is true.

A_OUT and B_OUT, as Mac described them, are not anti-phase.
Read more carefully. They are true for a pair of input state
sets that are not disjoint. This means they can both be true
at the same time. And a little more attention to Mac's post
(the part you cut) would show that those outputs are, in
fact, in quadrature for any monotonic counting sequence.
[meaningless noise cut]
And what is your "clk"?- an unspecified input.


Irrelevant. What clock can you construct, in this universe, that
will cause A_OUT and B_OUT to be anti-phase when, for some
inputs, they have the same value?


There is no conceivable way a single counter can produce true
quadrature outputs synchronous to the appropriate edges. You would
need to use some dumb doubler thing.


Have you ever heard of asynchronous state machines?

Trust me- there will be little to nothing you will be able to tell me.
My preference would be that the divide-by-4 counter effect a
grey-code sequence.

The "grey-code" sequence was invented out of necessity of minimizing
adjacent resolution cell measurement error in multi-bit encoders. It has
little to nothing to do with two separate quadrature one-bit channels.
I take it, by your change of subject and refusal to address my point
about disjoint sets, that you are unable to defend your denigration
of Mac's post.

I will retract the denigration when this magical "clk" input is
specified. AFIK, that encoder is outputting A/B, maybe a direction
signal, and maybe an index. Which one of those is "clk"?

You haven't denigrated it. You just said it was incorrect. I'm pretty sure
it is only because you didn't read enough context. For the record, clk is
a normal digital clock which is much faster than the encoder period. The
OP said the encoder signals are in the kHz range, so clk could be 10 MHz
or something.
I am not going to give serious consideration to an underspecified
Verilog file- that's nothing more than an ASCII wish. If Mac could write
it, why couldn't he simulate it? Or was it he would have to figure what
"clk" is?

I didn't feel like simulating it because it is NOT MY PROBLEM and I have
real work to do in addition to messing about on usenet. Although I guess I
got sucked in here, didn't I. ;-)

--Mac
 
P

petrus bitbyter

Jan 1, 1970
0
Randy MacKenna said:
Ahhh...now I get it...thanks!



That would be very nice. I suppose that if I go down this route, I'd
have to buy some sort of FPGA programmer (like Digikey sells?) and
learn how to code the solution. A long time ago, I was a grad student
at Syracuse, writing VHDL and doing other digital logic coursework.
Life took a different turn, so I've long forgotten most of it. I do
remember how much fun it was setting up the system clock, mapping out
state transistions, and reducing the problem to a circuit...so if
there's an outside chance I can actually figure this out, that'd be
nice.

All I need to know is the path I need to take, e.g.:

1. learn how a quadrature encoder really works
2. learn how to program a PLD
3. figure out the inputs/outputs and state transistions
4. design the circuit
5. code the PLD

I understand that there's a loss of resolution here (which buys the
added speed)...but we are talking about way below the spec of the
woodworking machine I'm trying to build. The servo driver is tunable,
so using an o-scope, I ought to be able to get the motor to be
critically damped. All I need to do is to decide to go down one of
these paths:

a. sell the encoders I have and buy new ones
b. add the $40 divider box to each encoder circuit
c. sell the drivers I have and buy new ones that have pulse
multipliers onboard
d. explore building my own encoder frequency division circuit.

I'd like to explore 'd' a little bit more, before giving up...if 'd' is
a pipe-dream (for me), then my next viable option is 'c'.

-Randy

Randy,

Your quadrature signals looks like this:

___ ___ ___ ___ ___ ___ ___ ___
A | |___| |___| |___| |___| |___| |___| |___| |
___ ___ ___ ___ ___ ___ ___ __
B __| |___| |___| |___| |___| |___| |___| |___|

When you turn the one direction, and

___ ___ ___ ___ ___ ___ ___ ___
A | |___| |___| |___| |___| |___| |___| |___| |
__ ___ ___ ___ ___ ___ ___ ___ __
B |___| |___| |___| |___| |___| |___| |___| |___|

when you turn the other direction.

Repeating on a smaller scale, along with the signals you want to make:
_ _ _ _ _ _ _ _ _ _ _ _ _
A | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
_ _ _ _ _ _ _ _ _ _ _ _ _
B _| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
_______________ _______________
X | |_______________| |_______
_______________ _______________
Y ________| |_______________| |

For the one direction - let's say clockwise - and

_ _ _ _ _ _ _ _ _ _ _ _ _
A | |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
_ _ _ _ _ _ _ _ _ _ _ _ _
B |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_|
_______________ _______________
X | |_______________| |_______
________ _______________
Y |_______________| |______________

for the other, so counter clockwise.

As you know about state machines, suppose you run a counter using A as a
clock in the following sequence, known as Gray code:

000
001
011
010
---
110
111
101
100
000
001
011
010
---
110

and so on.

A closer look will reveal that the most significant bit can be considered
the X signal and the middle bit the Y signal for the counter clockwise
turning direction.

Now have a look at the next sequence:

000
---
100
101
111
110
010
011
001
000
---
100
101
111
110
010
011
001
000
---

This one counts in the opposite sequence and the most significant bits can
be considered the X and Y signals for the clockwise case.

The only thing you have to build is a three bits Gray code up/down counter.
If you use the positive edge of the A signal for the clock you can use the B
signal for the count direction (i.e. up/down)

The best component for this type of circuit is a PLD. You only need three
flipflops but Gray counting requires quite some glue logic.

petrus bitbyter
 
R

Randy MacKenna

Jan 1, 1970
0
Mac,
Thanks so much for taking the time to post your code. The approach
makes sense to me, athough I admit I'm fuzzy on the details. I will
continue to work on this until I'm convinced that I understand it well
enough to move on it. It's not clear to me how to generate
quadrature-offset pulses, but I need to spend more time looking at it.
For example, in your case statements, I don't see how a_out and b_out
are offset by 90 degrees (or 1/4 pulse width). Maybe they need to be
synched to clocks that are already offset?

To the others that contributed to this thread: First, I'm sorry I
caused an argument - that wasn't my intention by a long shot. Second,
the other suggestions that I do this resolution reduction (or speed
increase) using mechanical methods - this would either introduce
unacceptable high cost to the project or added backlash (or both).

The suggestion that I contact USDigital for a new optical disk for
my encoders would have been a good one -- except I'm not using
USDigital encoders. I'm using a set of old encoders off an X-Ray
positioning system. Replacement disks are not available.

Thanks,
Randy
 
M

Mac

Jan 1, 1970
0
Mac,
Thanks so much for taking the time to post your code. The approach
makes sense to me, athough I admit I'm fuzzy on the details. I will
continue to work on this until I'm convinced that I understand it well
enough to move on it. It's not clear to me how to generate
quadrature-offset pulses, but I need to spend more time looking at it.
For example, in your case statements, I don't see how a_out and b_out
are offset by 90 degrees (or 1/4 pulse width). Maybe they need to be
synched to clocks that are already offset?

To the others that contributed to this thread: First, I'm sorry I
caused an argument - that wasn't my intention by a long shot. Second,
the other suggestions that I do this resolution reduction (or speed
increase) using mechanical methods - this would either introduce
unacceptable high cost to the project or added backlash (or both).

The suggestion that I contact USDigital for a new optical disk for
my encoders would have been a good one -- except I'm not using
USDigital encoders. I'm using a set of old encoders off an X-Ray
positioning system. Replacement disks are not available.

Thanks,
Randy


Don't worry about the argument. You didn't start it. You just provided a
forum for it to continue, and if you hadn't, the argument or a similar one
would have happened anyway.

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


Hope that helps.

--Mac
 
F

Fred Bloggs

Jan 1, 1970
0
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 !@#$%^& 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
 
Top