In this post I will outline a couple of solutions for a quadrature encoder generator in VHDL. I wanted a Quadrature Encoder signal for test purposes without the need to hook-up a real encoder and decided that an FPGA is perfect for this, especially considering that generating two signals with a 90-degree phase shift is not easy using analog means.
The basic specification for this task can be summarized as follows:
Inputs:
- System clock: I will use the 50MHz clock iCLK_50 on the DE2-70
- Reset.
- Divisor: Divides the system clock to achieve a desired quadrature encoder output frequency.
- Direction: Defines the rotational direction of the quadrature encoder
- PPR: Pulses Per Revolution. A quadrature encoder characteristic. Encoders can be purchased with different PPR settings. A Z pulse is generated every this many A or B pulses.
Outputs:
- A: Quadrature Encoder Output. 50% duty cycle.
- B: Quadrature Encoder Output. 50% duty cycle. 90-degree phase shifted off A. Phase shift plus or minus depends on direction of travel.
- Z: Reference pulse generated every time the encoder completes 1 revolution (as given by PPR). The pulse width is equal to half the width of an A/B pulse.
Quadrature Encoder in VHDL Solution 1
This basic solution consists of 2 processes. The first process generates the A/B pulses while the second process generates the Z pulse.
The First Process
This process is divided into two parts (although this may not be obvious in the implementation). The first part simply generates a temporary 50% duty cycle base signal (representing the signal A or B) using the Divisor input to generate the given output frequency based off the system clock. The 90-degree phase shifted second temporary signal is based off this first base signal and is generated by counting half the number of Divisor system clock cycles every time the base signal transitions. Once this count is reached the output (second signal) takes on the value of the base signal. Finally, the Direction parameter decides how these temporary signals are assigned to the outputs A and B. The following diagram illustrates this.

Quadrature Encoder Solution 1
Notes:
- The divisor input parameter above is used to toggle the output every time that many system clock pulses are counted. In other words, the output pulse width of the A/B quadrature encoder pulse is 2 times the Divisor number of system clock pulses. This means that we can only generate the output frequency in multiples of 2. In summary, the output quadrature encoder frequency is given by

The Second Process
This process is very simple. It clocks off the A pulses generated by the first process and counts PPR number of transitions. A Z pulse is then generated when the count is reached. It then resets and repeats.
The Solution
-- Quadrature Encoder -- Author : Hitesh Patel, November 2008 -- blog.nirosoftware.com -- LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; ENTITY QuadratureEnc IS GENERIC (NumBits : INTEGER := 26; PPR : INTEGER := 4);-- Pulses Per Revolution. Z generated every PPR count PORT( clk, rst : IN STD_LOGIC; divisor : IN STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); -- 26 bits, must be multiple of 2 direction : IN STD_LOGIC; -- '1' => CLOCKWISE; '0' => ANTI-CLOCKWISE A : BUFFER STD_LOGIC; B : OUT STD_LOGIC; Z : BUFFER STD_LOGIC); END QuadratureEnc; ARCHITECTURE QuadratureEnc OF QuadratureEnc IS SIGNAL clkCountB : STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); SIGNAL div : STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); BEGIN -- Make divisor a multiple of 2 otherwise incorrect signal patterns -- are generated div(0) <= '0'; div(NumBits-1 DOWNTO 1) <= divisor(NumBits-1 DOWNTO 1); PROCESS(clk, rst) VARIABLE clkCountA : STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); VARIABLE startCount : BOOLEAN; VARIABLE signalA, signalB : STD_LOGIC; BEGIN IF(rst = '1') THEN clkCountA := (OTHERS => '0'); clkCountB <= (OTHERS => '0'); signalA := '0'; startCount := False; ELSIF (clk'EVENT AND clk='1') THEN clkCountA := clkCountA + 1; IF(clkCountA = div) THEN clkCountA := (OTHERS => '0'); signalA := NOT signalA; startCount := True; END IF; IF(startCount) THEN clkCountB <= clkCountB + 1; IF(clkCountB = To_StdLogicVector(To_bitvector(div) SRL 1)) THEN clkCountB <= (OTHERS => '0'); signalB := signalA; startCount := False; END IF; END IF; END IF; IF(direction = '1') THEN -- CLOCKWISE A <= signalB; B <= signalA; ELSE -- ANTI-CLOCKWISE A <= signalA; B <= signalB; END IF; END PROCESS; -- Process that generates the Z reference pulse PROCESS(A, clk) VARIABLE countA : STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); BEGIN IF (A'EVENT AND A='1') THEN Z <= '0'; countA := countA + 1; IF(countA = PPR) THEN Z <= '1'; END IF; END IF; END PROCESS; END QuadratureEnc;
Quadrature Encoder in VHDL Solution 2
This design came to me in a moment of inspiration while I was perusing some quadrature encoder data sheets! Anyway, this design uses a state machine to generate the output. Note how A and B change in the diagram below as the encoder rotates in a given direction.

Quadrature Encoder Signals A/B
The repeating pattern can be captured in a state machine which transitions every N (or Divisor) system clock cycles, as shown below.

Quadrature Encoder State Machine, Clockwise Rotation

Quadrature Encoder State Machine, Counter Clockwise Rotation
This implementation uses a classic state machine design pattern consisting of 2 processes. The first process consists of sequential logic and is responsible for state transitions. In this case the state transitions are predicated by a counter. This is the same counting logic as in design 1 above to generate a given Quadrature Encoder frequency. The second process is responsible for signal assignments and assigning the next state. I have left out the logic that generates the Z pulse to keep the implementation uncluttered for purposes of illustrating the simplicity of the design.
The Solution
-- State Machine based Quadrature Encoder -- Author : Hitesh Patel, December 2008 -- blog.nirosoftware.com -- LIBRARY ieee; USE ieee.std_logic_1164.all; USE ieee.std_logic_arith.all; USE ieee.std_logic_unsigned.all; ENTITY QuadratureEncSM IS GENERIC (NumBits : INTEGER := 26; PPR : INTEGER := 4);-- Pulses Per Revolution. Z generated every PPR count PORT( clk, rst : IN STD_LOGIC; divisor : IN STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); -- 26 bits, must be multiple of 2 direction : IN STD_LOGIC; -- '1' => CLOCKWISE; '0' => ANTI-CLOCKWISE A : OUT STD_LOGIC; B : OUT STD_LOGIC; Z : OUT STD_LOGIC); END QuadratureEncSM; ARCHITECTURE QuadratureEncSM OF QuadratureEncSM IS TYPE state IS (s00, s01, s11, s10); SIGNAL pState, nState : state; SIGNAL aa, bb, zz : STD_LOGIC; BEGIN -- State machine control PROCESS(clk, rst) VARIABLE clkCountA : STD_LOGIC_VECTOR(NumBits-1 DOWNTO 0); BEGIN IF(rst = '1') THEN pState <= s00; clkCountA := (OTHERS => '0'); ELSIF (clk'EVENT AND clk='1') THEN clkCountA := clkCountA + 1; IF(clkCountA = divisor) THEN clkCountA := (OTHERS => '0'); pState <= nState; END IF; -- Output signals A <= aa; B <= bb; Z <= zz; END IF; END PROCESS; -- Quadrature Encoder state machine PROCESS(pState, rst) BEGIN IF(direction = '1') THEN -- clockwise CASE pState IS WHEN s00 => nState <= s01; aa <= '0'; bb <= '1'; WHEN s01 => nState <= s11; aa <= '1'; bb <= '1'; WHEN s11 => nState <= s10; aa <= '1'; bb <= '0'; WHEN s10 => nState <= s00; aa <= '0'; bb <= '0'; END CASE; ELSE -- Counter clockwise CASE pState IS WHEN s00 => nState <= s10; aa <= '1'; bb <= '0'; WHEN s10 => nState <= s11; aa <= '1'; bb <= '1'; WHEN s11 => nState <= s01; aa <= '0'; bb <= '1'; WHEN s01 => nState <= s00; aa <= '0'; bb <= '0'; END CASE; END IF; zz <= '0'; END PROCESS; END QuadratureEncSM;
In conclusion this design methodology lends itself very well to generating interesting repeating output patterns. One simply maps out the desired pattern for the output signals and captures this in a state machine.
Download the project archive below

Popularity: 49% [?]















Be The First To Comment
Related Post
Please Leave Your Comments Below