Problem writing quadrature decoder

Yes # = OR, * = AND, + = my typos (oops), as I re-ordered the terms for clarity.

No, strange thing is ONE direction seems plausible, but the other dirn seems wrong.... ? (This was Xilinx webpack) What does your report say ?

-jg

Reply to
Jim Granville
Loading thread data ...

Typos corrected, "+" changed to "*" where "*" is and while "#" is or.

For the upper bits, the down count will happen when the rQuad is behind the count by 1 or 2 phases and the count[1:0] is 00 and the up count will happen when the rQuad is in front of the count by 1 phase and the count[1:0] is 11. Because the logic you're using is a toggle, the upper bits will only change when the count[1:0] is 00 and the rQuad is 10 or 11 (down) or the count[1:0] is 11 and the rQuad is 00 (up).

This matches your (de-typoed) logic above.

Since the count is used to judge the retained quadrant rather than a registered version of the quadrature inputs, the up/down toggle points work in nicely with the quadrant detection.

- John_H

Reply to
John_H

This is a general comment: It was said that you can just "ignore the counter LSBs" if they bother you. That is not true. Imagine the counter oscillating between 99 and

100 (if it were decimal) or between FFF and 1000. That would be pretty upsetting. Wow, we got the thread-count up to 63. Isn't it amazing. Never has so much been argued (in a friendly way) about so little... Peter
Reply to
Peter Alfke

Looks like a Xilinx tool bug ? If I create a node for either dir, or dir and CEnable, then it changes, and Webpack seems to cope better. [ perhaps the code is too terse for it ;) ]

It creates a (bizarely named) pair of clock enables, that are now symmetric, and look plausible.

rQuad := quad; rQuad := quad;

dir = count $ count * !rQuad # !count * rQuad;

--Created node, seems to be CE_DOWN rQuad.COMB = !count * !count * rQuad * dir # !count * !count * rQuad * dir;

--Created node, seems to be CE_UP rQuad.COMB = count * count * !rQuad * !dir # count * count * rQuad * !dir;

count.T := rQuad.COMB * !count # rQuad.COMB * count;

Given rQuad is a Quad registered input, seeing rQuad.COMB used as something tool-created, is strange....

Wonder what a brand new Xilinx tool chain does here....?

-jg

Reply to
Jim Granville

Not only that: the 'so little' is reducing even more, as the register count is falling ;)

-jg

Reply to
Jim Granville

Ah, yes - I missed the 2-phase instance. In my code, only one-quadrant is used for count, and a 2 quadrant delta is ignored by MSBs and can be flagged as an error. LSBs lock on the next clock.

It could be the 2 quadrant instance is also contained in here, just not so visible ?

dir = count $ count * !rQuad # !count * rQuad;

rQuad.COMB = count * count * !rQuad * !dir # count * count * rQuad * !dir;

rQuad.COMB = !count * !count * rQuad * dir # !count * !count * rQuad * dir;

Which brings the question: How would you recode your version to Trap a 2 Quadrant error and not propogate a MSB count on it ?

-jg

Reply to
Jim Granville

No. John has pointed out the 2-quad delta in his code causes a clock, so the eqn result is not as symmetric as I was expecting. PBKAC.

Likely behaves the same, just the 2-quad case is less visible.. ?

-jg

Reply to
Jim Granville

I hope you agree that the original upper bits were performing properly. The LSbits can carry through from a similar argument, I imagine. Just figure the four count[1:0] quadrants in order are 00,

01, 10, and 11 while the corresponding rQuad quadrants are 00, 01, 11, and 10. If these were LUTs and not counters, the 2 LSbits would be entirely dependent on rQuad and count[1:0] in one level of 4-input LUT logic.

There should be NO illegal codes in a properly working system after initialization. I use the starting quadrature input phase to move the starting count to a range of -2 to +1, inclusive. During this init, the "illegal" phase will help move a 180 degree out-of-phase starting code to a count of -2. After this init, any instance of 180 degrees out of phase (((rQuad-count[1:0])&2'h3)==2'h2) is an illegal code and CANNOT be properly interpreted. The illegal code could set a flag but only after the first few clocks of the initialization have fed through the system. It might be the best way to gate the signal is to use the first time the count is outside the -2 to +1 initialization range.

I don't know the proper way to apply a "preserve" attribute in XST to guarantee that these flops don't get optimized to high steady states independent of the init state with the opposite "reg name=1'b0;" Synplify may not yet support this form of register initialization though XST tries to do the right thing.

reg gate = 1'b0; reg err = 1'b0; always @(posedge clk) begin if( count>8'h1 & count < 8'hfe ) gate

Reply to
John_H

Correct, but it seems to vary

- My Code uses just 1 and 2 Product terms, because I split the 2 LSB out and effectively code binQuad = {rQuad[1],^rQuad[1:0]} in registers. ( which has an implicit next-clock-lock )

- but my code is more lines, and 'splits' the counter, which is not as 'visually appealing' :)

- Your code compiles to either 4.TFF & 6.TFF PT, with a DIRN node or

4.TFF & 3.DFF PT on no Dirn node.

- which I think is the +2 complicating things ?

I think the problem is fundamental : with one counter line, if you code to remove the +2 case, you do not sync, but leaving it in, means you propogate an error.... :(

I suppose you could rule that it WILL sync on the next quad click, and so that could be tolerable, to allow just +/-1 ? (effectively this is a hold-on-illegal ?)

It could be a sensor error, or a rate error (clk too slow), which is why I am keen to catch it.

-jg

Reply to
Jim Granville

Using this rule, I re-coded as

wire OutByOne = ( count[1:0]-binQuad == 2'b01 ) | ( binQuad-count[1:0] == 2'b01 ); always @(posedge clk) begin rQuad

Reply to
Jim Granville

There is NO protection from illegal states. If you get an illegal state because BOTH input channels have flipped polarity, the first input that comes back to correct polarity might not be the correct one giving you a count of -1 instead of +1 that should occur; the bouncing continues, possibly coming back through the original phase back to where it SHOULD have been with the +1 count but with a -3 instead. There CANNOT be protection from the illegal state, only an indicator that it happened.

If the 180 degree phase difference is removed from the init in my code, the 180 degree difference will stay until a change in the encoder finally happens. I'd recommend keeping the "illegal code" treatment as a negative step of 1 for init purposes. That is the ONLY time it SHOULD occur.

- John

Reply to
John_H

Correct (I said similar earlier) which is why I prefer to flag it as well, - the hold-on-illegal suggests you _missed_ an edge, but have no way of knowing if it was CW or CCW. A novice might not realise there even ARE illegal states.

In a FPGA with trucklods of resource, you could run an Error counter, and read it periodically as a sensor integrity check.

It's a philosphy thing I guess, I prefer to keep any error away from the counter, and think the one-click to lock at power up, is no real problem - a Quad system always has power up problems anyway.

It gets moot, because a system with frequent errors needs remedy either way!.

A user might complain more about a double-step (which they will see) than a late-step (which they will hardly notice a few degrees on a knob?

Peter's Anti-Jitter block can bolt on the front of any of these, if you want to avoid flicker effects.

-jg

Reply to
Jim Granville

There ARE NO illegal states unless the system is very hosed such as the extreme shock problems mentioned earlier. If the system is being jarred to that degree, the count will make no sense especially if the bounce is many 10s (100s?) of bogus transitions on both channels.

There is no missing an edge because it isn't edges we're tracking, it's quadrants. As long as the encoder visits each quadrant there will be NO missed counts and therefor no post-init illegal states.

I allow the phase difference between the quad inputs and the count of

180 degrees on startup to transition to the count of -2 in a stable manner.

- John_H

Reply to
John_H

Correct: A correctly operating, Quadrature encoder with good clk margin, should have no illegal states.

Also, if your sensor is damaged/worn/dirty, then this will be one way to sense that.

Suppose the CLK is too slow, relative to the Quad signals ?

Now, you WILL have a 'missing edge', and as CLK freq is a design choice, knowing you have made an error is a good thing :)

This is a real-word interface, and the real-world can throw some failure modes into the mix....

I'm looking for an encoder that uses SPCO contacts, (allows micro-power encoder), but that seems to be unobtanium.

-jg

Reply to
Jim Granville

Consider a shaft running at an outrageous 100k rpm and a 1024 phase per revolution encoder. That's about 1.6 MHz to guarantee operation. Of someone shooses to use a slower clock, they sure aren't doing their job. An error indicator isn't going to help much in that situation. It's a little like having a warning system in your shoe that says "your foot is on fire." Is it really useful? Sure it could happen, but come on....

Rather than exotic metal contacts, how about using an optical encoder? It's hard to bounce 2 channels of light at the same time.

- John_H

Reply to
John_H

The problem with optical encoders is power consumption. You can pulse them with low duty cycles to save power, but suddenly that clock speed issue becomes important... (as does the power of the oscillator, used to derive the pulses.. )

-jg

Reply to
Jim Granville

Here is my bird's eye conclusiont: The least demanding shaft encoders use two sets of contacts to read manual rotation. Usually there is a mechanical detent, which precludes any resolution finer than the detent. Activation speed is max 10 or 20 Hz. My original proposal serves that purpose just fine, and is very simple and cheap (4 LUTs)

At the other extreme are high-speed optical quadrature encoders in robotics, where they might control an arm that moves up to a few meters per second with a resolution of 1 micrometer, which means a few MHz. There is no detent, and highest resolution without hysteresis is desirable. The computer can suppress counter changes due to mechanical oscillations. John H. presented a synchronous circuit that covers that application, and is also very simple.

It has been an interesting, albeit lengthy discussion. Peter Alfke

Reply to
Peter Alfke

Peter Alfke wrote: (snip of mechanical encoder)

Just another thought, what happens for slow moving systems and an optical encoder where it might generate a voltage in between '1' and '0'?

-- glen

Reply to
glen herrmannsfeldt

Normally hysteresis is employed to handle that.

-jg

Reply to
Jim Granville

With the asynchronous crossing, the registered quadrature encoder signals in the synchronous domain will come to a conclusion as to what that intermediate voltage should be: high or low. This will often result in chatter between two quadrants in much the same way as switch bounce because the threshold voltage may be modulated by noise giving a different full-scale registered result on various consecutive cycles.

The techniques is still completely stable. That's why quadrature encoders are so great.

- John_H

Reply to
John_H

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.