UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Explorer
Explorer
11,608 Views
Registered: ‎08-23-2011

Reg: quadrature encoder interfaced with FPGA misses counts ...

hi,

 

i wrote a code to interface a quadrature encoder with an FPGA. the quadrature encoder has 2 outputs A and B. when A leads B, the encoder is moving in clockwise dir and i increase the count and if B leads A, then i dececrease the count.

 

I also have an input dir mode ... if dir_mode = 01, then i consider it as uni-dir mode and i just increase the counter on every rising edge of A, irrespective of weather A leads or lags B. but when the dir_mode = 10, (bi-dir) then i check if A leads or lags B and update my counter accordingly. 

 

the problem i am facing is that in the uni-dir mode, the encoder works properly  and gives the proper counts. but in bi-dir mode (10), i start missing counts when i speed up the encoder in clockwise dir. if i hold a steady speed, then the count seems to be fine. 

 

the fpga is working at 50 MHz and the encoder does not work faster than that. and I have taken care of the fact that the encoder A and B signals are asynchronous by sending them through a series of FFs. I've attached the code below and as a seperate file. 

 

it will be great if someone could shed some light on what i might be doing wrong? or if there is some form of timing issue ...

 

thanks and regards,

zubin.

 

THE CODE - 

 

entity QuadEncTop is
Port (
clk: in STD_LOGIC; --Module clock
rst: in STD_LOGIC; --Module reset
DIR_MODE : in STD_LOGIC_VECTOR (1 downto 0); --To indicate if uni or bi directional mode
BIT_A : in STD_LOGIC; --To get A and B dir bits
BIT_B : in STD_LOGIC;
quad_sig_counter : out STD_LOGIC_VECTOR (31 downto 0)); --The dir counter
end QuadEncTop;

 

architecture Behavioral of QuadEncTop is

 

signal sig_counter : std_logic_vector (31 downto 0) := (others => '0');

--FSM states
type states is (s1, s2, s3);
signal state : states := s1;

 

begin

 

----------------------------------------------------------------------------
--process to handle the asynchronity of A and B
----------------------------------------------------------------------------
process (clk, rst)
begin
if (rst = '1') then
A_TRIGid1 <= '0';
A_TRIGid2 <= '0';
A_TRIGid3 <= '0';
A_TRIGid4 <= '0';
A_TRIGid5 <= '0';
A_TRIGid6 <= '0';
A_TRIGid7 <= '0';
A_TRIGid8 <= '0';
elsif (rising_edge(clk)) then
A_TRIGid1 <= BIT_A;
A_TRIGid2 <= A_TRIGid1;
A_TRIGid3 <= A_TRIGid2;
A_TRIGid4 <= A_TRIGid3;
A_TRIGid5 <= A_TRIGid4;
A_TRIGid6 <= A_TRIGid5;
A_TRIGid7 <= A_TRIGid6;
A_TRIGid8 <= A_TRIGid7;
end if;
end process;

 

process (clk, rst)
begin
if (rst = '1') then
B_TRIGid1 <= '0';
B_TRIGid2 <= '0';
B_TRIGid3 <= '0';
B_TRIGid4 <= '0';
B_TRIGid5 <= '0';
B_TRIGid6 <= '0';
B_TRIGid7 <= '0';
B_TRIGid8 <= '0';
elsif (rising_edge(clk)) then
B_TRIGid1 <= BIT_B;
B_TRIGid2 <= B_TRIGid1;
B_TRIGid3 <= B_TRIGid2;
B_TRIGid4 <= B_TRIGid3;
B_TRIGid5 <= B_TRIGid4;
B_TRIGid6 <= B_TRIGid5;
B_TRIGid7 <= B_TRIGid6;
B_TRIGid8 <= B_TRIGid7;
end if;
end process;

 

----------------------------------------------------------------------------
-- Main Quadrature Encoder process
--
-----------------------------------------------------------------------------

process (clk, rst)

if (rst = '1') then
sig_counter <= (others => '0');
quad_sig_counter <= (others => '0');
state <= s1;

 

elsif rising_edge(clk) then

 

case state is

 

when s1 =>
if (A_TRIGid4 = '0' and A_TRIGid8 = '0') then
state <= s2;
else
state <= s1;
end if;

 

when s2 =>
if (DIR_MODE = "01" or DIR_MODE = "10") then --uni/bi-dir check
if (A_TRIGid4 = '1' and A_TRIGid8 = '0') then --A rising edge
state <= s7;
else
state <= s3;
end if;
end if;

 

when s3 =>
if (DIR_MODE = "01") then --uni-dir
sig_counter <= sig_counter + 1;
elsif (DIR_MODE = "10" and B_TRIGid4 = '0' and B_TRIGid8 = '0') then --bi-dir/+ve ... B is 0
sig_counter <= sig_counter + 1;
elsif (DIR_MODE = "10" and B_TRIGid4 = '1' and B_TRIGid8 = '1') then --bi-dir/-ve ... B is 1
sig_counter <= sig_counter - 1;
else
sig_counter <= sig_counter + 1; --default inc
end if;
quad_sig_counter <= sig_counter; --send quad counter to o/p
state <= s1;

 

when others =>
state <= s1;

 

end case;

 

end if;

 

end process;

 

end Behavioral;

0 Kudos
15 Replies
Teacher eteam00
Teacher
11,599 Views
Registered: ‎07-21-2009

quadrature encoder problems

A few quick comments and suggestions:

 

  • You do not need more than 2 "synchroniser" register stages on any single async input.  A single stage is probably sufficient (especially for quadrature encoder systems).
  • Using more than 2 stages will do neither harm nor good, if feedback delay is unimportant.  If feedback delay is a problem for your motor control system, then the 7/8-stage input delay may wreak havoc.
  • You have very few comments in your code, and you do not explain the operation of your design.  This presents a hurdle (reverse engineering, mind-reading, reading of tea leaves) to anyone who cares to help you, and handicaps their answers.  The very process of preparing a 'how this works' description may help you to understand the source of your problem.
  • In order for your design to have a chance of working, the FPGA clock period must be shorter than the shortest possible encoder input pulse width (high or low).  A prudent operating margin would be doubling (minimum) the FPGA clock frequency with respect to the encoder rate of change.
  • If there is a pattern to the "missing counts", beyond the "bidir mode", this might provide a clue.  Do the missing counts come only in increments of 1, 2, or 4?

The problem i am facing is that in the uni-dir mode, the encoder works properly  and gives the proper counts. but in bi-dir mode (10), i start missing counts when i speed up the encoder in clockwise dir. if i hold a steady speed, then the count seems to be fine.

 

Are these problems seen in simulation or in observations of hardware?  If you have not simulated your logic, you should do so.  There are very few "interesting" sequences of quadrature inputs, and stimulating your logic at the maximum theoretical operating frequency should be straightforward.

 

Do not forget that quadrature encoder output "drivers" are typically open collector and/or opto-isolators -- both are notoriously slow compared to ordinary CMOS logic signals.  You should check the specs of the quadrature encoder, and any buffers or level translators in the path between the encoder and the FPGA.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Explorer
Explorer
11,594 Views
Registered: ‎08-23-2011

Re: quadrature encoder problems

hi,

 

thanks for your reply. I've added more comments to the code to make it more understandable. hope this helps. i've added it below. as for the points you mentioned - 

 

yes - the FPGA clk period is shorter than the min duration of the encoder pulses. the encoder is not being rotated that fast that it be faster than 50MHz, whcih is the fpga clk.

 

the simulations work fine. its on the hardware that im having a problem. the missing counts are as follows - normally if the count is going like - 25, 26, 27, 28, 29, 30, 31 ... and all of a sudden i increase the speed, then the count comes out like - 25, 26, 27, 27, 29, 30, 31 ... (28 is missed) and one count is missed thus messing up rest of the operations. however the correct no. of values are shown and then the count seems to rectify itself. ... which is wierd ... this only happens when i increase the speed in bi-dir mode. in uni-dir mode, it works fine. 

 

please do let me know if i'm doing something wrong?

 

--top level entity
entity QuadEncTop is
Port (
clk: in STD_LOGIC; --Module clock
rst: in STD_LOGIC; --Module reset
DIR_MODE : in STD_LOGIC_VECTOR (1 downto 0); --To indicate if uni or bi directional mode
BIT_A : in STD_LOGIC; --To get A and B dir bits
BIT_B : in STD_LOGIC;
quad_sig_counter : out STD_LOGIC_VECTOR (31 downto 0)); --The counter
end QuadEncTop;

 

architecture Behavioral of QuadEncTop is

 

--encoder count
signal sig_counter : std_logic_vector (31 downto 0) := (others => '0');

 

--FSM states
type states is (s1, s2, s3);
signal state : states := s1;

begin

 

-------------------------------------------------------------------------------------------------
--process to handle the asynchronity of A and B thru cascaded FFs
-------------------------------------------------------------------------------------------------


process (clk, rst)
begin
if (rst = '1') then
A_TRIGid1 <= '0';
A_TRIGid2 <= '0';
A_TRIGid3 <= '0';
A_TRIGid4 <= '0';
A_TRIGid5 <= '0';
A_TRIGid6 <= '0';
A_TRIGid7 <= '0';
A_TRIGid8 <= '0';
elsif (rising_edge(clk)) then
A_TRIGid1 <= BIT_A;
A_TRIGid2 <= A_TRIGid1;
A_TRIGid3 <= A_TRIGid2;
A_TRIGid4 <= A_TRIGid3;
A_TRIGid5 <= A_TRIGid4;
A_TRIGid6 <= A_TRIGid5;
A_TRIGid7 <= A_TRIGid6;
A_TRIGid8 <= A_TRIGid7;
end if;
end process;

 

process (clk, rst)
begin
if (rst = '1') then
B_TRIGid1 <= '0';
B_TRIGid2 <= '0';
B_TRIGid3 <= '0';
B_TRIGid4 <= '0';
B_TRIGid5 <= '0';
B_TRIGid6 <= '0';
B_TRIGid7 <= '0';
B_TRIGid8 <= '0';
elsif (rising_edge(clk)) then
B_TRIGid1 <= BIT_B;
B_TRIGid2 <= B_TRIGid1;
B_TRIGid3 <= B_TRIGid2;
B_TRIGid4 <= B_TRIGid3;
B_TRIGid5 <= B_TRIGid4;
B_TRIGid6 <= B_TRIGid5;
B_TRIGid7 <= B_TRIGid6;
B_TRIGid8 <= B_TRIGid7;
end if;
end process;

 

----------------------------------------------------------------------------
-- Main Quadrature Encoder process
--
-----------------------------------------------------------------------------

 

process (clk, rst)

 

--reset o/p and states if rst = 1
if (rst = '1') then
sig_counter <= (others => '0');
quad_sig_counter <= (others => '0');
state <= s1;

 

--check for rising edge of clk
elsif rising_edge(clk) then\

 

case state is

 

--when A is 0, goto s2 else s1
when s1 =>
if (A_TRIGid4 = '0' and A_TRIGid8 = '0') then
state <= s2;
else
state <= s1;
end if;

 

--if dir mode = 01 or 10, then check if A is rising edge and then goto s3
--else stay in s2
when s2 =>
if (DIR_MODE = "01" or DIR_MODE = "10") then --uni/bi-dir check
if (A_TRIGid4 = '1' and A_TRIGid8 = '0') then --A rising edge
state <= s3;
else
state <= s2;
end if;
end if;

 

--if dir_mode = 01 then uni-dir, inc counter
--if dir_mode = 10, then bi-dir, check if B is 0 and then inc counter
--if dir_mode = 10, then bi-dir, check if B is 1 and then dec counter
--else inc counter by default and assign counter to o/p port and return to s1 to redo the process
when s3 =>
if (DIR_MODE = "01") then --uni-dir
sig_counter <= sig_counter + 1;
elsif (DIR_MODE = "10" and B_TRIGid4 = '0' and B_TRIGid8 = '0') then --bi-dir/+ve ... B is 0
sig_counter <= sig_counter + 1;
elsif (DIR_MODE = "10" and B_TRIGid4 = '1' and B_TRIGid8 = '1') then --bi-dir/-ve ... B is 1
sig_counter <= sig_counter - 1;
else
sig_counter <= sig_counter + 1; --default inc
end if;
quad_sig_counter <= sig_counter; --send quad counter to o/p
state <= s1;

 

when others =>
state <= s1;

 

end case;

 

end if;

 

end process;

 

end Behavioral;

0 Kudos
Teacher eteam00
Teacher
11,590 Views
Registered: ‎07-21-2009

Re: quadrature encoder problems

Your comments are not very helpful.  Please comment on the following lines cut and pasted from your code.

 

if (A_TRIGid4 = '0' and A_TRIGid8 = '0') then

Why are you checking stages 4 and 8, but not the stages between 4 and 8?

 

type states is (s1, s2, s3);

What are the meanings of these three states?

 

if (DIR_MODE = "01" or DIR_MODE = "10") then --uni/bi-dir check

Why is DIR_MODE a 2-bit value for only 2 states (up or down)?  How is DIR_MODE derived?  Source?

 

if (A_TRIGid4 = '1' and A_TRIGid8 = '0') then --A rising edge

If you are checking for a rising edge, then why not check state 4 and stage 5 instead of stage 4 and stage 8?  Can you see a problem with checking 4 and 8, but not 5,6, and 7?

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Explorer
Explorer
11,586 Views
Registered: ‎08-23-2011

Re: quadrature encoder problems

hi,

 

i will add more comments, but is there a set pattern/official template in whcih vhdl code should be commented? can you send me a link to the template if possible?

 

thanks and regards,

zubin kumar.

0 Kudos
Teacher eteam00
Teacher
11,581 Views
Registered: ‎07-21-2009

Re: quadrature encoder problems

i will add more comments, but is there a set pattern/official template in whcih vhdl code should be commented? can you send me a link to the template if possible?

 

The problem is not form or quantity, but substance.  Not enough useful information in the comments!  Comments are for the purpose of informing, not style.

 

Read the questions asked in post #4 in this thread.  They illustrate the sort of information which is missing from your comments and from your descriptions.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Historian
Historian
11,577 Views
Registered: ‎02-25-2008

Re: quadrature encoder problems


@zubin_kumar31 wrote:

hi,

 

i will add more comments, but is there a set pattern/official template in whcih vhdl code should be commented? can you send me a link to the template if possible?


The comments should say WHY you're doing something, especially if the WHY is not obvious. Tell the reader your motivation for doing something in a particular way.

The code tells the reader WHAT you're doing, so there's no need to repeat the WHAT in comments.

 

For example, this is a bad comment:

 

     addr <= addr + 1;    -- increment address

 

This applies to any programming language or HDL.

----------------------------Yes, I do this for a living.
Teacher eteam00
Teacher
11,573 Views
Registered: ‎07-21-2009

Re: quadrature encoder problems

For example, this is a bad comment:

 

     addr <= addr + 1;    -- increment address

 

Agreed!

 

For example, this is a useful comment:

 

     addr <= addr + 1;    -- point to the next character in the string

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Observer larsge
Observer
11,566 Views
Registered: ‎09-12-2007

Re: quadrature encoder problems

Hi,

 

Have a look at this thread.

 

http://forums.xilinx.com/t5/PLD-Blog/Quadrature-Decoding-with-Resolution-Options/ba-p/12348

 

Best Regards

Lasse

0 Kudos
Teacher eteam00
Teacher
11,559 Views
Registered: ‎07-21-2009

Re: quadrature encoder problems

Lasse,

 

Zubin's interest is in learning how to design and write VHDL code.  There are many quadrature encoder routines available for download on the web, but grabbing code which someone else has written does not teach you very much.

 

There's a common saying in the USA, which is wise in any location:

 

If you give me a fish, you feed me for a day.  If you teach me how to fish, you feed me for my entire life.

 

I think Zubin is taking the responsible path, and I (and others) would (and should) encourage him in this pursuit.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Explorer
Explorer
14,656 Views
Registered: ‎08-23-2011

Re: quadrature encoder problems

hi bob,

 

thanks for your inputs.

 

here is a better commented code. please let me know if this is upto standards and if there is something conceptually wrong in what im doing with the quadrature encoder. as i mentioned before - the encoder works fine in uni-dir mode and no counts are missed. but with bi-dir mode, when i increase the speed, the counts are missed in the order - 25, 26, 27, 27, 29, 30, 31 .... (28 missed). please let me know if there is any way of resolving this or if i've done something wrong in the code?

 

--top level entity
entity QuadEncTop is
Port (
clk: in STD_LOGIC; --Module clock (50 MHz)
rst: in STD_LOGIC; --Module reset (push button)
DIR_MODE : in STD_LOGIC_VECTOR (1 downto 0); --To indicate if uni or bi directional mode (dip switch)
BIT_A : in STD_LOGIC; --To get A and B inputs from encoder (from GPIO pins)
BIT_B : in STD_LOGIC;
quad_sig_counter : out STD_LOGIC_VECTOR (31 downto 0)); --The counter
end QuadEncTop;

 

architecture Behavioral of QuadEncTop is

--encoder counter
signal sig_counter : std_logic_vector (31 downto 0) := (others => '0');

--FSM states
type states is (s1, s2, s3);
signal state : states := s1;

 

--fsm states explanation--
--s1 ...
-- wait in s1 till A is 0 and then move to s2
--s2 ...
-- if dir_mode set to 01 or 10 and A rising edge obtained then goto s3 else stay in s2
--s3 ...
-- if dir_mode = 01, then uni-dir, i.e. inc counter
-- if dir_mode = 10, then bi-dir mode, if B is 0, then clkwise dir, hence inc counter
-- if dir_mode = 10, then bi-dir mode, if B is 1, then anti-clk dir, hence dec counter
--return to s1

 

--working explanation------------------------------
--A and B are asynchronous inputs obtained from a quadrature encoder
--the FPGA is working at 50 MHz. The rise time of A and B are 50 ns
--the max. period of the A pulse (or the B pulse) is 880 us with a 50% duty cycle
--when A leads B, i.e. if A is rising edge and B is 0, then its taken as clkwise dir,
--and counter is inc. by 1
--when A lags B, i.e. if A is rising edge and B is 1, then its taken as anti-clk dir,
--and counter is dec. by 1
--dir_mode is set using DIP switches and are not changed in between an operation
--if dir_mode = 01, then its uni-dir mode and on every rising edge of A, counter is inc
--if dir_mode = 10, then its bi-dir mode and then lead/lag or A vs B is checked and
--any value of dir_mode other than 01 or 10 will cause the FSM to stop in s2
--counter is inc or decremented accordingly
--the counter value is sent to a host system via GPIO pins to a host system over the USB
--to a proprietary software which displays the counter values in succession. this software has always worked
--properly without any issues thus far.
--------------------------------------------------------------

 

begin

-------------------------------------------------------------------------------------------------
--process to handle the asynchronity of A and B thru cascaded FFs
--since the rise time of A (or B) is 50ns, and FPGA clk is 50MHz,
--ff 1,2, 3, 4 are used to filter out spikes. and edge is detected using
--ff 4 and 8 so that they are 80ns apart (more than the rise time of the A or B pulse)
-------------------------------------------------------------------------------------------------
process (clk, rst)
begin
if (rst = '1') then
A_TRIGid1 <= '0';
A_TRIGid2 <= '0';
A_TRIGid3 <= '0';
A_TRIGid4 <= '0';
A_TRIGid5 <= '0';
A_TRIGid6 <= '0';
A_TRIGid7 <= '0';
A_TRIGid8 <= '0';
elsif (rising_edge(clk)) then
A_TRIGid1 <= BIT_A;
A_TRIGid2 <= A_TRIGid1;
A_TRIGid3 <= A_TRIGid2;
A_TRIGid4 <= A_TRIGid3;
A_TRIGid5 <= A_TRIGid4;
A_TRIGid6 <= A_TRIGid5;
A_TRIGid7 <= A_TRIGid6;
A_TRIGid8 <= A_TRIGid7;
end if;
end process;

 

process (clk, rst)
begin
if (rst = '1') then
B_TRIGid1 <= '0';
B_TRIGid2 <= '0';
B_TRIGid3 <= '0';
B_TRIGid4 <= '0';
B_TRIGid5 <= '0';
B_TRIGid6 <= '0';
B_TRIGid7 <= '0';
B_TRIGid8 <= '0';
elsif (rising_edge(clk)) then
B_TRIGid1 <= BIT_B;
B_TRIGid2 <= B_TRIGid1;
B_TRIGid3 <= B_TRIGid2;
B_TRIGid4 <= B_TRIGid3;
B_TRIGid5 <= B_TRIGid4;
B_TRIGid6 <= B_TRIGid5;
B_TRIGid7 <= B_TRIGid6;
B_TRIGid8 <= B_TRIGid7;
end if;
end process;

 

----------------------------------------------------------------------------
-- Main Quadrature Encoder process
--
----------------------------------------------------------------------------

 

process (clk, rst)

 

--reset o/p and states if rst = 1
if (rst = '1') then
sig_counter <= (others => '0');
quad_sig_counter <= (others => '0');
state <= s1;

 

--rising edge of clk
elsif rising_edge(clk) then

 

case state is

 

--state s1
when s1 =>
--when A is 0, goto s2 else stay in s1
if (A_TRIGid4 = '0' and A_TRIGid8 = '0') then
state <= s2;
else
state <= s1;
end if;

 

--start s2
when s2 =>
--if dir mode = 01 or 10, then check if A is rising edge and then goto s3
--else stay in s2
if (DIR_MODE = "01" or DIR_MODE = "10") then --uni/bi-dir check
if (A_TRIGid4 = '1' and A_TRIGid8 = '0') then --A rising edge
state <= s3;
else
state <= s2;
end if;
end if;

 

--state s3
when s3 =>
if (DIR_MODE = "01") then --if dir_mode = 01 then uni-dir, inc counter
sig_counter <= sig_counter + 1;
elsif (DIR_MODE = "10" and B_TRIGid4 = '0' and B_TRIGid8 = '0') then --if dir_mode = 10, then bi-dir, check if B is 0 and then inc counter
sig_counter <= sig_counter + 1;
elsif (DIR_MODE = "10" and B_TRIGid4 = '1' and B_TRIGid8 = '1') then ----if dir_mode = 10, then bi-dir, check if B is 1 and then dec counter
sig_counter <= sig_counter - 1;
else
sig_counter <= sig_counter + 1; --default inc
end if;
quad_sig_counter <= sig_counter; --send quad counter to o/p
state <= s1;

 

when others =>
state <= s1;

 

end case;

 

end if;

 

end process;

 

end Behavioral;

0 Kudos
Teacher rcingham
Teacher
14,651 Views
Registered: ‎09-09-2010

Re: quadrature encoder problems

"--rising edge of clk
elsif rising_edge(clk) then"

Comment tautologous, therefore redundant.

Naming the states meaningfully, rather than adding comments is better practice, e.g. s1_waiting.

------------------------------------------
"If it don't work in simulation, it won't work on the board."
0 Kudos
Teacher eteam00
Teacher
14,650 Views
Registered: ‎07-21-2009

Re: quadrature encoder problems

Zumar,

 

You latest post is a huge improvement.

Here are a few review critiques.

 

--since the rise time of A (or B) is 50ns, and FPGA clk is 50MHz,
--ff 1,2, 3, 4 are used to filter out spikes.

 

In your code, ff 1,2,3,4 do not filter spikes, they merely delay them.

Here is an example of filtering spikes, written in Verilog (which you will need to translate)

 

always @(posedge clk) begin // clocked process syntax for verilog

  ff[3:0] <= {ff[2:0], enc_input};  // sample encoder input and delay 3 clock cycles

  if ( (ff[3:0] == 4'b0000) or (ff[3:0] == 4'b1111) // is input stable?

    ff[4] <= ff[0]; // input is stable, copy input value to ff[4]

  ff[8:5] <= ff[7:4];  // additional delay of filtered input

end

 

If you add this filtering, then your IF statements in the state machine are simplified.  For example:

this (A_TRIGid4 = '0' and A_TRIGid8 = '0')

becomes (A_TRIGid4 = '0')

 

Next item --

 

--the max. period of the A pulse (or the B pulse) is 880 us with a 50% duty cycle

 

The more important consideration is the minimum period (max frequency) for the encoder inputs, yes?

 

Next items --

 

Because quad_sig_counter is updated only within state S3, it always represents the previous value of sig_counter.  There will always be a lag between sig_counter and quad_sig_counter.  You might consider moving the assignment of the quad_sig_counter register outside the case statement, so that the register is updated on every clock cycle (and every state).

 

There is a hazard with sampling A input and B input on different clock cycles.  In your current code, A might change state between the time A is sampled in state S2 and the the time B is sampled in state S3.  This can be corrected by changing the following bit of code in state S2:

 

from (A_TRIGid4 = '1' and A_TRIGid8 = '0')

to   (A_TRIGid3 = '1' and A_TRIGid7 = '0')

 

I don't think this particular problem is affecting your design, but it is (in general) a poor coding practice.  The classic example of this poor practice is when different bits of a counter are "sampled" on different clock cycles within a state machine.  The logic falls apart when the counter changes value between one sample point and another.  The correct practice is to sample (or take a 'snapshot' of) the entire counter on one cycle, and use the state machine to act only on that single sampled value until the state machine function is completed.

 

Does this make sense?

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Teacher eteam00
Teacher
14,644 Views
Registered: ‎07-21-2009

coding style suggestions

Naming the states meaningfully, rather than adding comments is better practice, e.g. s1_waiting.

 

Agreed.  If it is helpful to provide meaningful names to variables and registers, it is equally helpful to provide meaningful names to states of a state machine.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Teacher eteam00
Teacher
14,642 Views
Registered: ‎07-21-2009

Re: quadrature encoder problems

when i increase the speed, the counts are missed in the order - 25, 26, 27, 27, 29, 30, 31 .... (28 missed).


the counter value is sent to a host system via GPIO pins to a host system over the USB to a proprietary software which displays the counter values in succession. this software has always worked properly without any issues thus far.

 

There is some information missing.  What logic is used to

  • send a new count value to the host system
  • display a new count value on the host system

This will help to figure out how a new (but unchanged) value might be reported, and how a new (changed) value might not be reported.

 

-- Bob Elkind

SIGNATURE:
README for newbies is here: http://forums.xilinx.com/t5/New-Users-Forum/README-first-Help-for-new-users/td-p/219369

Summary:
1. Read the manual or user guide. Have you read the manual? Can you find the manual?
2. Search the forums (and search the web) for similar topics.
3. Do not post the same question on multiple forums.
4. Do not post a new topic or question on someone else's thread, start a new thread!
5. Students: Copying code is not the same as learning to design.
6 "It does not work" is not a question which can be answered. Provide useful details (with webpage, datasheet links, please).
7. You are not charged extra fees for comments in your code.
8. I am not paid for forum posts. If I write a good post, then I have been good for nothing.
0 Kudos
Newbie cool007mark
Newbie
14,601 Views
Registered: ‎03-15-2012

Re: quadrature encoder problems

Quadrature Encoders are a common type of incremental encoders that use two output channels (A and B) to sense position. Using two code tracks with sectors positioned 90° out of phase (Figure 1), the two output channels of the quadrature encoder indicate both position and direction of rotation.

The major advantage offered by incremental encoders (quadrature encoders are a type of incremental encoders) is their high resolution. Precision quadrature encoders are available that produce over 10,000 pulses per revolution at speeds exceeding 5000 RPM. Their high resolutions, extreme durability and ease of installation make Quadrature Encoders ideal for a wide variety of applications:

  • Motor drive control systems use quadrature encoders to provide closed loop feedback for position and velocity controlled applications.
  • Printers, fax machines and copy machines use quadrature encoders to synchronize various moving parts for trouble free operation.
  • Elevators use quadrature encoders to maintain velocity and acceleration and for correct door alignment.
  • Automated blood analyzers use quadrature encoders to ensure the exact position of vials containing blood samples while performing automated tests.

High speed and precision applications that utilize these quadrature encoders for velocity and acceleration control require hardware that can deterministically process quadrature encoder signals to estimate velocity and acceleration and instantaneously output controls signals at hardware-timed precision.

Velocity and Acceleration Calculations


There can be multiple ways to determine the angular velocity and acceleration of a Quadrature Encoder. In this tutorial we will develop an example that will count the number of Quadrature Encoder pulses in a fixed time interval to estimate the velocity and acceleration of the encoder, Figure 2 below demonstrates this procedure. This method is appropriate for high speed applications.



  Velocity Estimation

 

Once the number of pulses in a fixed time interval is measured the angular velocity of the Quadrature Encoder can be calculated using the following formula:



Where, “Encoder Pulses” is the number of quadrature encoder pulses received in the Fixed Time Interval.

Acceleration is the rate of change of velocity. The following formula can be used to estimate acceleration of the Quadrature Encoder:



Where, the numerator divided by one Fixed Time Interval represents the change in velocity. Dividing the change in velocity by one Fixed Time Interval gives the acceleration.

 

 

 

0 Kudos