Problem writing quadrature decoder

Hi there - I am continuing to attempt to learn VHDL this weekend! Currently I'm trying to interface to the quadrature encoder on my Spartan 3E Starter Kit. It outputs normal quadrature signals. So, I tried to write a very simple bit of code for this purpose, which just checks which edge on which signal occurred and then checks the state of the other signal and infers if the count should be incremented or decremented from that. My code is at the bottom of my post.

In theory this method of quadrature decoding should work perfectly, unless I'm forgetting something. But for some reason which I'm afraid I don't understand this is not synthesizable. I liked the idea of using this method for quadrature decoding as it didn't require me to deal with storing the previous state - the use of the falling_edge() and rising_edge() functions did that for me. Xilinx ISE help brought me to this page:

formatting link
However, I don't have any embedded 'event statements, or any 'event statements at all, for that matter (unless again I'm missing something).

What exactly am I doing wrong, and is there a way to fix it? Thanks so much!

-Michael

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all;

entity hello_world is port ( clk, enc_a, enc_b : in std_logic; switches : in std_logic_vector (3 downto 0); led : out std_logic_vector (7 downto 0) ); end hello_world;

architecture rtl of hello_world is signal cnt : unsigned (30 downto 0); signal encval : unsigned (7 downto 0); signal enccnt : unsigned (7 downto 0); begin process(clk) begin if rising_edge(clk) then cnt

Reply to
Michael
Loading thread data ...

  1. Using inputs as clocks.
  2. Using two clocks in a process.

and is there a way to fix it?

Declare as many registers as you need, but put everything in your first process. Have a look at my examples.

-- Mike Treseler

Reply to
Mike Treseler

The quadrature encoder on the Spartan 3E Starter Kit is mechanical, you should implement some debouncing. Maybe some simple holdoff is sufficient, but if there are fast crosstalk glitches, a simple low pass filter (in VHDL) would be a good idea, too.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

So rising_edge() and falling_edge() can only be used with clocks?

Why does everything have to be in one process? Is there a reason it's objectionable to have one process that is sensitive to only my clock and one process that's only sensitive to a couple inputs? And so you're suggesting I go with a state based approach? Or something else? What are these extra registers for?

What examples are you referring to?

Thanks!

-Michael

Reply to
Michael

Hi Frank - I thought about debouncing and - unless I'm being dumb - I think as long as only one input is changing at a time, bounce won't affect this approach in the steady state. I mean that if I turn it 4 counts, it might count something like 0 1 2 3 2 3 4 3 4. But the final value will be correct.

-Michael

Reply to
Michael

Michael, you might prefer my much simpler solution, as described in a recent blog on the Xilinx forums website.

formatting link

I designed this a few years ago, and we use it in our programmable frequency gererator, that I have mentioned here a few times. Ken Chapman then took the exact same shaft encoder for the Spartan eval board. The design is absolutely bounce-proof, no Mickey Mouse low-pass filters or other analog nonsense. I hope the explanation is sufficient.

Viel Spa=DF Peter Alfke

Reply to
Peter Alfke

There are different classes of Quad encoder. The Simplest feed one phase into a CLK and the other into DIRN, but that counts only once per whole cycle.

The best designs can count on every edge, and can tolerate a chattering edge. You might also want to catch illegal state jumps (missed states), as that indicates something is amiss in your design. One easy to understand way to code this, is to create a internal 2 bit phase engine, and lock it to the external sampled edges. That design makes illegal state jumps easy to catch. You have a simple state engine, with 2 IP bits,

2 Present bits, [16 combinations] and output CE, DIRN, and ERR, as well as 2 bits for Next state.

-jg

Reply to
-jg

Michael wrote: (snip on quadrature decoders)

As long as the bounce isn't faster than the counter can count, yes.

I like the clocked design that Peter A. has in another post. I believe that one works as long as the clock is faster than the fastest possible real count. Bounces might be missed, but the count will be right.

Also, I believe one should reset the counter on the first index pulse and not on subsequent ones.

-- glen

Reply to
glen herrmannsfeldt

Bounces should (or must) be missed.. That's the whole purpose of the circuit .:-) Peter..

Reply to
Peter Alfke

For synchronous designs, yes.

It doesn't. Just a suggestion.

Peter has the problem solved for you. Post a question to comp.lang.vhdl if you need more help.

-- Mike Treseler

Reply to
Mike Treseler

Hi Peter - I didn't see any code attached to the post. Does this look right?

signal Q1, Q2 : std_logic; process (A, B) begin if (A =3D '1' and B =3D '1') then Q1

Reply to
Michael

D2

Check it with pencil and paper. Yes, A and B are 90 degree offset, that's why it's called a quadrature decoder. Then check if for a monotonic "friendly" rotation, and you see how it works. The trickery is that it also works for any non-monotonic move. Peter

Reply to
Peter Alfke

d D2

Michael, you start simply by ignoring the clock, just assume that it is always there, and is very fast, so each look-up table output is immediately registered. Then you move A and B, realizing that they are 90 degree offset. Then you just inspect the two Qs, and you see that you can consider one of them (either one) as the outgoing clock, and the other as the direction. Seems trivial, but the beauty is that it also works for any and every kind of irregular operation. It's not "rocket science" but it is simple and clever, if i may say so. Peter

Reply to
Peter Alfke

a

and D2

So this is what I got (for the two different directions):

A _--__--__- B --__--__-- Q1 _--__--__- Q2 --__--__-- D1 _--__--__- D2 --__--__--

A _--__--__- B __--__--__ Q1 __--__--__ Q2 -__--__--_ D1 __--__--__ D2 _--__--__-

I want to be able to count every edge. I think this method will give me half (or a quarter?) of the resolution that I want, unless I'm missing something?

Either way - what exactly is the idea here... I really don't understand the post you linked to. Is it saying that one of these signals can be used as a direction and one as the clock. However - if one of these was a direction signal - I'd expect it to be constant as my quadrature signals are just going in one direction...

-Michael

Reply to
Michael

n a

k

t,

ve

, and D2

Michael, you get one increment or decrement for every complete cycle, not for every edge. Since the direction polarity only matters exactly at the rising edge of Q1 (assuming you use Q1 as the clock) there is no need for Q2 to be stable at any other time. It just indicaates direction when it is needed. You can look at Q1 and Q2 just as cleaned up versions of A and B, without any bounce, but also insensitive to small changes in direction. There may be a way to double the resolution, by running Q1 through a frequency doubler while conditionally inverting Q2. That would double the total LUT count, but would still be quite simple. I had no need for the increased resolution in my application, but I'll take a look at it. The fundamental issue is to ignore the unavoidable contact bounce, and also to count correctly (up and down) even when the shaft encoder moves in any crazy way. You have to solve both these different issues: contact bounce and strange reversal of direction at any time. Otherwise any solution is worthless and just gives you a headache. And a digital designer wants to stay away from capacitors and filters and other analog stuff... Peter

Reply to
Peter Alfke

I'm looking to count every single edge. I had another idea about how to do it:

process(enc_a, enc_b) begin if enc_a'event then case prevstate is when "00"=3D>

enc_cnt enc_cnt enc_cnt enc_cnt enc_cnt enc_cnt enc_cnt enc_cnt enc_cnt enc_cnt

Reply to
Michael

Michael, when you say: count every single edge", do you mean every edge of A, or every edge of either A or B ? One is 2 edges per 360 deegrees, the other one is 4. Mine is 1. Incidentally, why is this important? For manual control, you have too many edges to start with... Peter

Reply to
Peter Alfke

I

al

I'm looking for 4 counts/360 degrees. My final use for quadrature decoding will be with motor control - so increasing the resolution of my encoder counting is very beneficial.

-Michael

Reply to
Michael

A-ha! I realized I could get rid of the edge checking and just compare with my saved previous state. It synthesizes! Unfortunately, it gives me some warnings during synthesization, and then (I believe due to the warnings) it won't give me a programming file. The warnings are:

the following signal(s) form a combinatorial loop: led, enc_cnt, Maddsub_enc_cnt14.

(for led - led)

Then it gives me a bunch of errors during mapping, like this one:

ERROR:MapLib:661 - LUT4 symbol "Maddsub_enc_cnt41" (output signal=3DMaddsub_enc_cnt4) has input signal "Maddsub_enc_cnt" which will be trimmed. See the t

I'm so close now (I think!) Can anybody tell me what is wrong with my code? I've never had a problem with mapping before - so this is very odd for me. I've posted the full code below. Thanks so much!

-Michael

library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.all;

entity hello_world is port ( clk, enc_a, enc_b : in std_logic; switches : in std_logic_vector (3 downto 0); led : out std_logic_vector (7 downto 0) ); end hello_world;

architecture rtl of hello_world is signal cnt : unsigned (30 downto 0); signal encval : unsigned (7 downto 0); signal enc_cnt : unsigned (7 downto 0); signal prevstate : std_logic_vector (1 downto 0); begin process(clk) begin if rising_edge(clk) then cnt

Reply to
Michael

In a full precision (one count per edge) you cannot ignore bounce, you have to accept it, and 'count with it, so the counter goes

+1,-1 +1 as it follows the bounce. Similarly with edge jitter (also possible in control systems) you need to follow. That's why it is a good idea to sample the IPs, and the CLK speed needs to be no more than the total counter speed (normally well over 10MHz)

Did you look at the links I gave before on the HCTL-2001 etc. ?

Jim Granville,

Reply to
-jg

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.