Successfully reported this slideshow.

Microprocessor-Compatible Quadrature Decoder/Counter Design

829 views

Published on

A microprocessor-compatible quadrature decoder/counter is used to interface an optical shaft encoder (OSE) to a microprocessor's system bus. Quadrature decoder/counter find application in digital data input subsystems and digital closed loop motion control systems.

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

Microprocessor-Compatible Quadrature Decoder/Counter Design

  1. 1. 1 INTRODUCTION TO VLSI A PROJECT REPORT ON MICROPROCESSOR-COMPATIBLE QUADRATURE DECODER/COUNTER DESIGN ROHIT SINGH M.TECH VLSI SYSTEMS AND TECHNOLOGY DEPARTMENT OF ELECTRICAL ENGINEERING SHIV NADAR UNIVERSITY
  2. 2. 2 Contents 1. Introduction 03 2. Quadrature decoder/counter 03 3. Optical shaft encoder (OSE) 03 3.1 Introduction 03 3.2 Signals having a quadrature phase relationship 04 4. Optical shaft encoder interface approach 05 4.1 Approach 1 05 4.2 Approach 2 05 5. Features of quadrature decoder/counter 05 5.1 Input signal noise filter 05 5.2 Four times decode 06 5.3 12-bit counter 07 5.4 Registered outputs that are readable “on the fly” 07 5.4.1 Reading the count “On the fly” 07 5.4.2 Double buffer register 08 5.5 8-bit microprocessor bus interfaces 08 6. Quadrature decoder/counter partition 08 7. VHDL Code 09 7.1 VHDL Code No. 1 (filter) 09 7.2 VHDL Code No. 2 (fx_decode) 10 7.3 VHDL Code No.3 (binary_cntr) 14 7.4 VHDL Code No.4 (inhibit_fsm) 15 7.5 VHDL Code No.5 (double_buff) 18 7.6 VHDL Code No.6 (mux) 19 7.7 VHDL Code No.7 (quad_decode) 19
  3. 3. 3 1. Introduction A microprocessor-compatible quadrature decoder/counter is used to interface an optical shaft encoder (OSE) to a microprocessor‟s system bus. Quadrature decoder/counter find application in digital data input subsystems and digital closed loop motion control systems. 2. Quadrature decoder/counter Quadrature decoder/counter is used to decode the two input signal which are 90 degrees out of phase. These signals are decoded to produce a count up pulse or a count down pulse. For decoding in software, the A & B outputs are read by software, either via an interrupt on any edge or polling, and the below table is used to decode the direction. For example, if the last value was 00 and the current value is 01, the device has moved one half step in the clockwise direction. Coding for clockwise rotation Phase A B 1 0 0 2 0 1 3 1 1 4 1 0 Coding for counter-clockwise rotation Phase A B 1 1 0 2 1 1 3 0 1 4 0 0 3. Optical shaft encoder (OSE) 3.1 Introduction An optical shaft encoder (OSE) converts rotary mechanical motion into a digital output. It does this by first converting the rotary of its shaft into interruptions of a light beam. It then converts these light beam interruptions into electrical pulses. One common use of OSE is on the front panel of an electronics instrument where it allows an operator to increment or decrement a displayed parameter. For example, clockwise (CW) rotation might cause the parameter to be incremented and counter clockwise (CCW) rotation cause it to be decremented.
  4. 4. 4 3.2 Signals having a quadrature phase relationship When its shaft is rotated, the OSE produces two digital output waveforms, designated channel A and channel B. These waveforms have a quadrature phase relationship.
  5. 5. 5 4. Optical shaft encoder interface approach There are two common approaches to interface an OSE to a microprocessor system‟s bus. 4.1 Approach 1 In a software-intensive approach, the microprocessor repeatedly inputs signals A and B from OSE through input port. A software subroutine compares the newly read values of A and B with a copy of the previously read values saved in memory. Based on this comparison, the subroutine determines whether to increment or decrement a count variable in the microprocessor‟s memory. This simple software approach requires that the microprocessor constantly monitor the OSE‟s outputs to detect each change in their values. 4.2 Approach 2 To improve the performance of a system incorporating an OSE, the time-intensive quadrature/decoder functions can be implemented in hardware. In this approach hardware converts changes in A and B to a count that is stored in a register. A microprocessor-compatible quadrature decoder/counter includes a bus interface that allows its count register to be read by a microprocessor at any time. 5. Features of quadrature decoder/counter Some features that quadrature decoder/counter IC might provide is: 1. Input signal noise filter 2. 4X decoder 3. 12-bit counter 4. Registered outputs that are readable “on the fly “ 5. 8-bit microprocessor bus interface 5.1 Input signal noise filter In an application environment, inputs A and B to the quadrature decoder/counter may be subject to electrical noise. The quadrature decoder/counter must include features to minimize the effect of both metastability from the asynchronous nature of inputs A and B and noise spikes of short duration that might appear on these inputs. Each input channel (A and B) is filtered by a separate copy of the digital noise filter (Shift Register Digital Noise Filter).
  6. 6. 6 Figure below shows a logic representation of a digital noise filter. The purpose of this filter is to reject short duration noise spikes at its input cx. The filter‟s output y can change only after its input has had the same value at three consecutive triggering clock edges. Input changes that have duration of two or fewer clock cycles are rejected. Examination of the logic diagram indicates that a valid input changes is delayed by five clock periods, one for each flip-flop, before it is seen at the output. A description of a functionally equivalent system is given in VHDL Code No. 1. This code describes the functionality of the 4-bit shift register and J-K flip flop with gated inputs. The first flip-flop of the shift register is used to reduce the chances of a metastable event if the input data is asynchronous. The filtered output is computed from the rightmost 3 bits of the shift register. If all three bits are zeros “000”, then output Y is assigned a „0‟. If all three of these bits are ones “111”, then Y is assigned a „1‟. For any other combination of these 3 bits, Y remains unchanged. 5.2 Four times decode Since output signals A and B from the OSE have a quadrature relationship, if the counter in the quadrature decoder/counter is enabled to count once for each quadrature of period of A, as defined by its relationship with B, the effective resolution of the OSE is increased by a factor of four. The four times decode subsystem is a state machine that uses the system clock to detect each time the combination of output values A and B changes. When this state machine detects such a change, it asserts its count enable output (cnten) until the next triggering clock edge. A counter enabled by cnten counts at the next triggering clock edge. The count enable output is unasserted on this same clock edge. This finite state machine is described below.
  7. 7. 7 5.3 12-bit counter A counter enable input can also be added to a counter, so the counter only counts at a triggering clock edge when it is enabled. If the counter is not enabled, its count remains the same at the triggering clock edge. A 12-bit binary up/down counter with a count enable input and a synchronous reset is described in VHDL code No. 3. This counter‟s count direction can be reversed at any point in its count sequence.. If an event on clk is positive edge, the inner if statement determines if the counter should be reset. If not, the count enable signal cnten is checked to determine whether the counter is enabled to count. If so, a case statement determines whether to count up or down. If the counter is not enabled to count, its value remains unchanged. 5.4 Registered outputs that are readable “on the fly” 5.4.1 Reading the count “On the fly” A problem can arise if a microprocessor directly reads the contents of a counter at the same time the counter is being incremented (reads “on the fly”). The value read can be incorrect, containing some bits from the old cont values that have not yet changed and some bits from the new count value. This problem is exacerbated in this application because the counter being read is wider than the microprocessor‟s data bus. The counter is 12 bits and the microprocessor‟s data bus is only 8 bit wide. This requires that the 12-bit data value be read as two different bytes, one containing the most significant 4 bits of the count and the other containing the least significant 8 bits. Reading 2 bytes requires that the microprocessor execute two read bus cycles. The increased time period
  8. 8. 8 over which the count is read increases the probability that the count might change while being read. 5.4.2 Double buffer register A double buffer register provides the solution to the problem of reading a counter “on the fly.” The double buffer register is connected to the counter‟s output. While its inhibit input is „0‟, the double buffer register stores a copy of the counter‟s output on each triggering clock edge. However, when its inhibit input is a „1‟, the double buffer register leaves its stored value unchanged. A FSM is required to generate the inhibit signal. The FSM makes inhibit a „1‟ as soon as the microprocessor starts to read the contents of the double buffer register, and returns inhibit to a „0‟ after both bytes have been read. 5.5 8-bit microprocessor bus interfaces Finally, a multiplexer is required to multiplex the 12-bit output of the double buffer register to the 8-bit data bus output. The sel signal determines whether the high byte or low byte appears on the multiplexer‟s outputs when oe_bar is asserted. 6. Quadrature decoder/counter partition A block diagram of the first level partition of the quadrature decoder/counter‟s functions is represented in figure below. There are seven components. U0: shift register digital noise filter U1: shift register digital noise filter U2: four times decoder U3: 12-bit counter U4: double buffer U5: inhibit FSM U6: MUX
  9. 9. 9 7. VHDL Code 7.1 VHDL Code No. 1 (filter) library ieee; use ieee.std_logic_1164.all; entity filter is port (cx, clk, rst_bar : in std_logic; y : out std_logic) ; end; architecture behavior of filter is begin synch: process (clk) variable q : std_logic_vector (3 downto 0) ; begin
  10. 10. 10 if rising_edge (clk) then if rst_bar = '0' then q := "0000"; y <= '0' ; else if q(2 downto 0 ) = "111" then --- filter y <= '1' ; elsif q(2 downto 0) = "000" then y <= '0'; else null ; end if ; q := cx & q (3 downto 1) ; -- right shift end if ; end if ; end process ; end behavior ; 7.2 VHDL Code No. 2 (fx_decode) library ieee ; use ieee.std_logic_1164.all ; entity fx_decode is port ( a, b, clk, rst_bar : in std_logic ; cnten, up : out std_logic ) ; end fx_decode ;
  11. 11. 11 architecture behavior of fx_decode is subtype state is std_logic_vector ( 1 downto 0) ; signal present_state, next_state : state ; constant state_p : state := "00" ; constant state_q : state := "01" ; constant state_r : state := "11" ; constant state_s : state := "10" ; begin state_reg: process (clk) begin if rising_edge (clk ) then if (rst_bar = '0' ) then present_state <= (b, a); else present_state <= next_state ; end if ; end if ; end process state_reg ; outputs : process (a, b, present_state ) variable input : std_logic_vector (1 downto 0); begin input := (b, a) ; case present_state is
  12. 12. 12 when state_p => if input = "01" then up <= '1' ; cnten <= '1' ; elsif input = "10" then up <= '0' ; cnten <= '1' ; else up <= '-' ; cnten <= '0' ; end if ; when state_q => if input = "11" then up <= '1' ; cnten <= '1' ; elsif input = "00" then up <= '0' ; cnten <= '1' ; else up <= '-' ; cnten <= '0' ; end if ; when state_r => if input = "10" then up <= '1' ; cnten <= '1' ; elsif input = "01" then up <= '0' ; cnten <= '1' ; else up <= '-' ; cnten <= '0' ; end if ; when state_s => if input = "00" then up <= '1' ; cnten <= '1' ; elsif input = "11" then up <= '0' ; cnten <= '1' ; else up <= '-' ; cnten <= '0' ; end if ;
  13. 13. 13 when others => null ; end case ; end process ; nxt_state: process (a, b, present_state) variable input : std_logic_vector (1 downto 0); begin input := (b, a) ; case present_state is when state_p => if input = "01" then next_state <= state_q ; elsif input = "10" then next_state <= state_s ; else next_state <= state_p ; end if ; when state_q => if input = "11" then next_state <= state_r ; elsif input = "00" then next_state <= state_p ; else next_state <= state_q ; end if ; when state_r => if input = "10" then next_state <= state_s ;
  14. 14. 14 elsif input = "01" then next_state <= state_q ; else next_state <= state_r ; end if ; when state_s => if input = "00" then next_state <= state_p ; elsif input = "11" then next_state <= state_r ; else next_state <= state_s ; end if ; when others => null ; end case ; end process ; end behavior ; 7.3 VHDL Code No.3 (binary_cntr) library ieee ; use ieee.std_logic_1164.all ; use ieee.numeric_std.all ; entity binary_cntr is port (clk, cnten, up, rst_bar : in std_logic; q : out std_logic_vector (11 downto 0)) ; end binary_cntr ; architecture behavioral of binary_cntr is begin
  15. 15. 15 cntr: process (clk) variable count_v : unsigned (11 downto 0) ; begin if rising_edge (clk) then if rst_bar = '0' then count_v := (others => '0' ) ; elsif cnten = '1' then case up is when '1' => count_v := count_v + 1 ; when others => count_v := count_v - 1 ; end case ; end if ; end if ; q <= std_logic_vector (count_v) ; end process ; end behavioral ; 7.4 VHDL Code No.4 (inhibit_fsm) library ieee ; use ieee.std_logic_1164.all ; entity inhibit_fsm is port ( rst_bar : in std_logic ; clk, sel, oe_bar : in std_logic ; inhibit : out std_logic ); end inhibit_fsm ;
  16. 16. 16 architecture behav of inhibit_fsm is type inhib_state is ( idle, byte1, byte2) ; signal present_state, next_state : inhib_state; begin inhib_sreg: process (clk) begin if rising_edge (clk) then if rst_bar = '0' then present_state <= idle; else present_state <= next_state ; end if ; end if ; end process ; inhib_output: process (present_state) begin case present_state is when byte1 | byte2 => inhibit <= '1' ; when others => inhibit <= '0' ; end case ; end process ; inhib_nxt_state: process (present_state, sel, oe_bar) begin
  17. 17. 17 case present_state is when idle => if sel = '0' and oe_bar = '0' then next_state <= byte1 ; else next_state <= idle ; end if ; when byte1 => if sel = '1' and oe_bar = '0' then next_state <= byte2 ; else next_state <= byte1 ; end if ; when byte2 => if oe_bar ='1' then next_state <= idle ; elsif sel = '0' and oe_bar = '0' then next_state <= byte1 ; else next_state <= byte2 ; end if ; end case ; end process ; end behav ;
  18. 18. 18 7.5 VHDL Code No.5 (double_buff) library ieee ; use ieee.std_logic_1164.all ; entity double_buff is port (din : in std_logic_vector (11 downto 0) ; rst_bar : in std_logic ; clk : in std_logic ; inhibit : in std_logic ; dout : out std_logic_vector (11 downto 0)) ; end double_buff ; architecture behav of double_buff is begin freeze : process (clk) begin if rising_edge (clk) then if rst_bar = '0' then dout <= x"000" ; elsif inhibit = '0' then dout <= din ; end if ; end if ; end process ; end behav ;
  19. 19. 19 7.6 VHDL Code No.6 (mux) ibrary ieee ; use ieee.std_logic_1164.all ; entity mux is port ( din : in std_logic_vector (11 downto 0); sel : in std_logic ; oe_bar : in std_logic ; dout : out std_logic_vector (7 downto 0)); end mux ; architecture behav of mux is begin dout <= "0000" & din (11 downto 8) when oe_bar = '0' and sel = '0' else din (7 downto 0) when oe_bar = '0' and sel = '1' else (others => 'Z' ); end behav ; 7.7 VHDL Code No.7 (quad_decode) Top-level structural description of quadrature decoder/counter library ieee ; use ieee.std_logic_1164.all ; entity quad_decode is port ( ch_a, ch_b, rst_bar : in std_logic ; clk, sel, oe_bar : in std_logic ; d : out std_logic_vector (7 downto 0 )) ; end quad_decode ;
  20. 20. 20 architecture structure of quad_decode is component filter port ( cx, clk, rst_bar : std_logic ; y : out std_logic ); end component ; component fx_decode port (a, b, clk, rst_bar : in std_logic ; cnten, up : out std_logic ); end component ; component binary_cntr port ( clk, cnten, up, rst_bar : in std_logic ; q : out std_logic_vector (11 downto 0 ) ); end component ; component double_buff port (din : in std_logic_vector (11 downto 0) ; rst_bar : in std_logic ; clk : in std_logic ; inhibit : in std_logic ; dout : out std_logic_vector (11 downto 0) ); end component ; component inhibit_fsm
  21. 21. 21 port ( rst_bar : in std_logic ; clk : in std_logic ; sel : in std_logic ; inhibit : out std_logic ; oe_bar : in std_logic ); end component ; component mux port (din : in std_logic_vector (11 downto 0); sel : in std_logic ; oe_bar : in std_logic ; dout : out std_logic_vector (7 downto 0)); end component ; signal ch_a_sig, ch_b_sig, cnten_sig, up_sig : std_logic; signal count_sig : std_logic_vector (11 downto 0); signal dbl_buff_sig : std_logic_vector (11 downto 0) ; signal inhibit_sig : std_logic ; begin u0 : filter port map ( cx => ch_a , clk => clk, rst_bar => rst_bar, y => ch_a_sig ); u1 : filter port map ( cx => ch_b, clk =>clk, rst_bar => rst_bar, y => ch_b_sig );
  22. 22. 22 u2 : fx_decode port map ( a => ch_a_sig, b => ch_b_sig, clk => clk, rst_bar => rst_bar, cnten => cnten_sig, up => up_sig ); u3 : binary_cntr port map ( clk => clk, cnten => cnten_sig, up => up_sig, rst_bar => rst_bar, q => count_sig ); u4 : double_buff port map ( din => count_sig, rst_bar => rst_bar, clk => clk, inhibit => inhibit_sig, dout => dbl_buff_sig ); u5 : inhibit_fsm port map ( rst_bar => rst_bar, clk => clk, sel => sel, inhibit => inhibit_sig, oe_bar => oe_bar ); u6 : mux port map ( din => dbl_buff_sig, sel => sel, oe_bar => oe_bar , dout => d ); end structure ;

×