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: http://www.xilinx.com/support/answers/14047.htm. 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 <= cnt + 1; encval <= "000000" & enc_b & enc_a; end if; end process; process (enc_a, enc_b) begin if (rising_edge(enc_a) and enc_b = '1') then enccnt <= enccnt - 1; elsif (rising_edge(enc_a) and enc_b = '0') then enccnt <= enccnt + 1; elsif (falling_edge(enc_a) and enc_b = '1') then enccnt <= enccnt + 1; elsif (falling_edge(enc_a) and enc_b = '0') then enccnt <= enccnt - 1; elsif (rising_edge(enc_b) and enc_a = '1') then enccnt <= enccnt + 1; elsif (rising_edge(enc_b) and enc_a = '0') then enccnt <= enccnt - 1; elsif (falling_edge(enc_b) and enc_a = '1') then enccnt <= enccnt - 1; elsif (falling_edge(enc_b) and enc_a = '0') then enccnt <= enccnt + 1; end if; end process; led <= std_logic_vector(cnt(30 downto 23)) when switches(0)='0' else std_logic_vector(encval); end rtl;
Problem writing quadrature decoder
Started by ●April 20, 2008
Summary
A beginner VHDL developer encountered synthesis errors while attempting to write a quadrature decoder by using multiple signal edges as clocks.
A beginner VHDL developer encountered synthesis errors while attempting to write a quadrature decoder by using multiple signal edges as clocks. The discussion clarifies that reliable FPGA design requires a synchronous approach where inputs are sampled by a high-speed system clock rather than being treated as asynchronous clock sources.
Experienced engineers recommend using a state-machine or a LUT-based sampling method to ensure the design is robust against mechanical switch bounce and meets standard synthesis requirements.
- Avoid using asynchronous signal edges ('event or rising_edge) on data inputs as they lead to non-synthesizable code or timing issues.
- Mechanical encoders require debouncing or a robust sampling state machine to prevent false counts from switch chatter.
- A recommended approach involves sampling the quadrature phases with a fast system clock and using a 2-bit state engine to detect movement and direction.
- Synchronous designs should ideally keep all logic within a single clock process to simplify timing and resource allocation.
VHDLQuadrature DecoderDigital DesignXilinx Spartan-3E
Reply by ●April 20, 20082008-04-20
Michael wrote:> What exactly am I doing wrong1. 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 by ●April 20, 20082008-04-20
Michael wrote:> In theory this method of quadrature decoding should work perfectly, > unless I'm forgetting something.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 by ●April 20, 20082008-04-20
On Apr 20, 6:42 pm, Mike Treseler <mike_trese...@comcast.net> wrote:> Michael wrote: > > What exactly am I doing wrong > > 1. Using inputs as clocks. > 2. Using two clocks in a process.So rising_edge() and falling_edge() can only be used with clocks?> and is there a way to fix it? > > Declare as many registers as you need, > but put everything in your first process.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?> Have a look at my examples. > > -- Mike TreselerWhat examples are you referring to? Thanks! -Michael
Reply by ●April 20, 20082008-04-20
On Apr 20, 6:50=A0pm, Frank Buss <f...@frank-buss.de> wrote:> Michael wrote: > > In theory this method of quadrature decoding should work perfectly, > > unless I'm forgetting something. > > 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 BussHi 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 by ●April 20, 20082008-04-20
Michael, you might prefer my much simpler solution, as described in a recent blog on the Xilinx forums website. http://forums.xilinx.com/xlnx/blog/article?message.uid=3D9394 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 by ●April 20, 20082008-04-20
> 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.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 by ●April 20, 20082008-04-20
Michael wrote: (snip on quadrature decoders)> 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.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 by ●April 20, 20082008-04-20
On Apr 20, 5:12=A0pm, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:> Michael wrote: > > (snip on quadrature decoders) > > > 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. > > 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. =A0Bounces 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 =A0subsequent ones. > > -- glenBounces should (or must) be missed.. That's the whole purpose of the circuit .:-) Peter..
Reply by ●April 20, 20082008-04-20
Michael wrote:> So rising_edge() and falling_edge() can only be used with clocks?For synchronous designs, yes.> Why does everything have to be in one process?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





