URL
https://opencores.org/ocsvn/quad_decoder/quad_decoder/trunk
Subversion Repositories quad_decoder
Compare Revisions
- This comparison shows the changes necessary to convert path
/quad_decoder
- from Rev 2 to Rev 3
- ↔ Reverse comparison
Rev 2 → Rev 3
/trunk/quad_decoder.vhd
1,23 → 1,54
-------------------------------------------------------------------------------- |
-- File: quad_decoder.vhd |
-- Desc: HDL implementation of a quadrature decoder with a Wishbone bus |
-- interface. See the "quad_decoder" datasheet for more information. |
-- Date: Initiated October, 2009 |
-- Auth: Scott Nortman, COPYRIGHT 2009 Bridge Electronic Design LLC |
-- scott.nortman@gmail.com |
-- File: quad_decoder.vhd |
-- Desc: HDL implementation of a quadrature decoder with a Wishbone bus |
-- interface. See the "quad_decoder" datasheet for more information. |
-- Date: Initiated October, 2009 |
-- Auth: Scott Nortman, COPYRIGHT 2009 Bridge Electronic Design LLC |
-- scott.nortman@gmail.com |
-- |
-- NOTE: If you find this file useful / helpful, please let me know :) |
-- |
-------------------------------------------------------------------------------- |
-- |
-- REVISION INFORMATION |
-- REVISION INFORMATION |
-- |
-- Current Version: 0.9.0 |
-- |
-- When Who What |
-- --------------------------------------------------------------------------- |
-- 02NOV09 S. Nortman Initial Release, v0.9.0 |
-- Current Version: 1.0.0 |
-- |
-- Nov. 2009 |
-- 1)Initial beta release, upload to OpenCores.org. |
-- 2)Tested HDL implementation with in a Xilinx Spartan 3 AN FPGA, with |
-- a softcore processor, the Tasking TSK3000. Emulated a quadrature |
-- encoder for initial verification. |
-- |
-- July, 2010 |
-- 1)Release version v1.0.0 |
-- 2)Changes from prior release: |
-- a) Bit 3 of the Quadrature Control Register (offset 0x00) is now changed |
-- functions, to enable / disable of the Index Zero Count function. When |
-- the bit is 0, an index event does not affect the count. When the bit is |
-- 1, and index events are permitted, the internal quadrature count is set |
-- to 0. |
-- b) Added control bit 13, Index Read Count Bit. When set to 0, no count |
-- is latched. When set to 1, and index events are permitted, the internal |
-- quadrature count is automatically latched to the QRW (offset 0x08) |
-- register when an index event is true. This is VERY useful for detection |
-- of missed encoder counts, as you can assume that the delta counts in |
-- between each index event is fixed, so any deviation from the expected |
-- amount indicates that there were missed encoder counts. |
-- 3)Tested the FPGA implementation with a real encoder, verified proper |
-- operation with count frequencies up to 1.3MHz (50MHz system clock) |
-- This test used an instrumented motor driver, with a hardware qudrature |
-- decoder in parallel with this encoder module. This module did not miss |
-- any counts with a 2048 quad counts / rev encoder running at 40e3 rpm. |
-- 4) Fixed a minor bug with the QCR_PLCT bit and the QCR_INZC bit; under |
-- a specific condition that both the PLCT bit and the INZC bit were asserted |
-- at the same clock cycle, the PLCT would have been executed while the INZC |
-- event would have been missed. |
-- 5) Added an additional feature: Quadrature Count Compare Match Event; |
-- when the CCME bit is set in the QCR register, and the quadrature count |
-- matches the QRW register, a signal is asserted and the status bit of the |
-- QSR register is set. This event can also generate an interrupt. |
-- |
|
------------------------------------------------------------------------------- |
|
library ieee; |
34,7 → 65,7
wb_cyc_i : in std_logic; |
wb_ack_o : out std_logic; |
--wb_adr_i : in std_logic_vector(3 downto 0); |
wb_adr_i : in std_logic_vector(1 downto 0); --assumes 32 bit alignment |
wb_adr_i : in std_logic_vector(1 downto 0); --assumes 32 bit alignment |
wb_dat_o : out std_logic_vector(31 downto 0); |
wb_dat_i : in std_logic_vector(31 downto 0); |
wb_we_i : in std_logic; |
53,7 → 84,7
----------------------------------------------------------------------------- |
-- Quadrature Control Register, QCR, offset 0x00 |
-- |
-- Bit 0: Enable Counting, ENCT |
-- Bit 0: Enable Counting, ECNT |
-- 0 -> Quadrature counting disabled |
-- 1 -> Quadrature counting enabled |
-- Bit 1: Set Count Direction, CTDR |
62,9 → 93,9
-- Bit 2: Index Enable Bit, INEN |
-- 0 -> Index input disabled |
-- 1 -> Index input enabled |
-- Bit 3: Index Function Bit, INFC |
-- Bit 3: Index Zero Count Bit, INZC |
-- 0 -> Internal count not affected. |
-- 1 -> Load count from pre load register |
-- 1 -> Zero internal quad_count when quad_index is asserted. |
-- Bit 4: Index Interrupt Enable, INIE |
-- 0 -> Index interrupt request disabled |
-- 1 -> Index interrupt request enabled |
92,24 → 123,37
-- Bit 12: Quadrature Error Interrupt enable, QEIE |
-- 0 -> Quadrature Error Interrupt disabled |
-- 1 -> Quadrature Error Interrupt enabled |
-- Bits 31:13 -> Reserved, must always be written to 0 |
-- Bit 13: Index Read Count Bit, INRC |
-- 0 -> Quadrature Read / Write register not affected. |
-- 1 -> Read the value of the quad. count to the QRW reg, when index event is true. |
-- Bit 14: Count Compare Match Enable, CCME |
-- 0 -> No compare match event may occur. |
-- 1 -> Compare match event asserted when enabled and QRW == quad_count |
-- Bit 15: Compare Match Interrupt Enable, CMIE |
-- 0 -> No interrupt generated when a compare match event is asserted. |
-- 1 -> An external interrupt will be generated when the compare event is asserted. |
-- Bits 31:16 -> Reserved, must always be written to 0 |
-- |
----------------------------------------------------------------------------- |
constant QCR_ECNT : integer := 0; --test ok |
constant QCR_CTDR : integer := 1; --test ok |
constant QCR_INEN : integer := 2; --test ok |
constant QCR_INFC : integer := 3; --test ok |
constant QCR_INIE : integer := 4; --test ok |
constant QCR_PLCT : integer := 5; --test ok |
constant QCR_UNIE : integer := 6; --test ok |
constant QCR_OVIE : integer := 7; --test ok |
constant QCR_QLAT : integer := 8; --test ok |
constant QCR_ICHA : integer := 9; --test ok |
constant QCR_ICHB : integer := 10;--test ok |
constant QCR_IDXL : integer := 11;--test ok |
constant QCR_QEIE : integer := 12;--test ok |
constant QCR_BITS : integer := 13; --Number of bits used in QCR register |
constant QCR_ECNT : integer := 0; |
constant QCR_CTDR : integer := 1; |
constant QCR_INEN : integer := 2; |
constant QCR_INZC : integer := 3; |
constant QCR_INIE : integer := 4; |
constant QCR_PLCT : integer := 5; |
constant QCR_UNIE : integer := 6; |
constant QCR_OVIE : integer := 7; |
constant QCR_QLAT : integer := 8; |
constant QCR_ICHA : integer := 9; |
constant QCR_ICHB : integer := 10; |
constant QCR_IDXL : integer := 11; |
constant QCR_QEIE : integer := 12; |
constant QCR_INRC : integer := 13; |
constant QCR_CCME : integer := 14; |
constant QCR_CMIE : integer := 15; |
constant QCR_BITS : integer := 16; --Number of bits used in QCR register |
signal qcr_reg : std_logic_vector(QCR_BITS-1 downto 0); --QCR register |
constant QCR_ADDR : std_logic_vector(1 downto 0) := "00"; |
|
---------------------------------------------------------------------------- |
-- Quadrature Status Register, QSR, offset 0x04 |
127,14 → 171,19
-- Bit 3: Index event, INEV, auto set, user cleared |
-- 0 -> Index event has not occurred |
-- 1 -> Index event occured, interrupt requested if INIE set |
-- Bits 31:4 -> Reserved, will always read 0 |
-- Bit 4: Count Compare Match Event, CCME, auto set, user cleared |
-- 0 -> Compare match event has not occurred |
-- 1- > Compare match event occurred, interrupt genetated if enabled |
-- Bits 31:5 -> Reserved, will always read 0 |
---------------------------------------------------------------------------- |
constant QSR_QERR : integer := 0; --test ok |
constant QSR_CTOV : integer := 1; --test ok |
constant QSR_CTUN : integer := 2; --test ok |
constant QSR_INEV : integer := 3; --test ok |
constant QSR_BITS : integer := 4; -- Num bits in QSR reg |
signal qsr_reg : std_logic_vector(QSR_BITS-1 downto 0); --QSR register |
constant QSR_QERR : integer := 0; |
constant QSR_CTOV : integer := 1; |
constant QSR_CTUN : integer := 2; |
constant QSR_INEV : integer := 3; |
constant QSR_CCME : integer := 4; |
constant QSR_BITS : integer := 5; -- Num bits in QSR reg |
signal qsr_reg : std_logic_vector(QSR_BITS-1 downto 0); --QSR register |
constant QSR_ADDR : std_logic_vector(1 downto 0) := "01"; |
|
--Signals indicating status information for the QSR process |
signal quad_error : std_logic; |
141,6 → 190,9
signal quad_ovflw : std_logic; |
signal quad_unflw : std_logic; |
signal quad_index : std_logic; |
signal quad_index_d : std_logic; |
signal quad_index_d2: std_logic; |
signal quad_comp : std_logic; |
|
---------------------------------------------------------------------------- |
-- Quadrature Count Read / Write Register, QRW, offset 0x08 |
155,10 → 207,11
-- This register is also used to hold the pre-load count value. |
-- After writing to this register, the pre-load value is |
-- transferred to the quadrature count register by writing a '1' |
-- to bit location 6, quadrature pre-load count (QPLCT) of the |
-- to bit location 5, quadrature pre-load count (PLCT) of the |
-- quadrature control register (QCR) offset 0x00. |
---------------------------------------------------------------------------- |
signal qrw_reg : std_logic_vector(QUAD_COUNT_WIDTH-1 downto 0); |
constant QRW_ADDR : std_logic_vector(1 downto 0) := "10"; |
|
--Actual quadrature counter register, extra bit for over/underflow detect |
signal quad_count : std_logic_vector(QUAD_COUNT_WIDTH downto 0); |
176,11 → 229,10
signal quad_chb_k : std_logic; |
signal quad_idx_j : std_logic; |
signal quad_idx_k : std_logic; |
|
|
signal quad_lat_flt : std_logic; |
signal quad_lat_q : std_logic; |
signal quad_lat_m : std_logic; |
signal quad_lat_flt : std_logic; |
signal quad_lat_q : std_logic; |
signal quad_lat_m : std_logic; |
|
--Quadrature 4X decoding state machine signals |
signal quad_st_new : std_logic_vector(1 downto 0); |
192,42 → 244,45
constant QUAD_STATE_1: std_logic_vector(1 downto 0) := "01"; |
constant QUAD_STATE_2: std_logic_vector(1 downto 0) := "11"; |
constant QUAD_STATE_3: std_logic_vector(1 downto 0) := "10"; |
|
--Wishbone internal signals |
signal wb_request : std_logic; |
signal wb_write : std_logic; |
|
|
--Wishbone internal signals |
signal wb_request : std_logic; |
signal wb_write : std_logic; |
|
--Signal for single clock delay of ack out |
signal ack_dly : std_logic; |
|
signal ack_dly : std_logic; |
|
--Internal irq signal |
signal quad_irq_int: std_logic; |
|
|
|
-- Internal signal to latch quad count on index assertion |
signal qcnt_idx_latch : std_logic; |
|
---------------------------------------------------------------------------- |
--Start of RTL |
---------------------------------------------------------------------------- |
begin |
|
|
--Assign internal signal to external signal |
quad_irq_o <= quad_irq_int; |
|
-- Handle wishbone ack generation / internal write signals |
wb_request <= wb_stb_i and wb_cyc_i; |
wb_write <= wb_request and wb_we_i; |
wb_ack_o <= ack_dly; |
|
----------------------------------------------------------------------- |
-- Process: qck_dly_proc( wb_clk_i ) |
-- Desc: Generates the wishbone ack signal after a single clock |
-- delay. This insures that the internal read / write |
-- operations have completed before acknowledging the |
-- master device. |
-- Signals: wb_clk_i |
-- ack_dly |
-- wb_rst_i |
-- Notes: |
----------------------------------------------------------------------- |
wb_ack_o <= ack_dly; |
|
----------------------------------------------------------------------- |
-- Process: qck_dly_proc( wb_clk_i ) |
-- Desc: Generates the wishbone ack signal after a single clock |
-- delay. This insures that the internal read / write |
-- operations have completed before acknowledging the |
-- master device. |
-- Signals: wb_clk_i |
-- ack_dly |
-- wb_rst_i |
-- Notes: Verified using the Wishbone bus of the TSK3000 from |
-- Altium Designer. |
----------------------------------------------------------------------- |
ack_dly_proc: process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
256,7 → 311,7
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
qcr_reg <= (others => '0'); |
elsif wb_write = '1' and wb_adr_i ="00" then |
elsif wb_write = '1' and wb_adr_i = QCR_ADDR then |
qcr_reg <= wb_dat_i(QCR_BITS-1 downto 0); |
end if; |
--See if PLCT asserted, should be auto-cleared |
272,7 → 327,7
|
----------------------------------------------------------------------- |
-- Process: qsr_reg_wr_proc( wb_clk_i ) |
-- Desc: Handles writing of the Quadrature Status Register, QSR, |
-- Desc: Handles writing of the Quadrature Status Register, QSR, |
-- offset 0x04. |
-- Signals: quad_error, internal error status signal |
-- quad_ovflw, internal counter overflow signal |
293,113 → 348,131
qsr_reg <= (others => '0'); |
else |
--Set qsr_reg bit from signal quad_error |
if quad_error = '1' and qcr_reg( QCR_ECNT) = '1' then |
if quad_error = '1' and qcr_reg(QCR_ECNT) = '1' then |
qsr_reg(QSR_QERR) <= '1'; |
elsif wb_write = '1' and wb_adr_i = "01" and qsr_reg(QSR_QERR) = '1' and wb_dat_i(QSR_QERR) = '1' then |
elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_QERR) = '1' and wb_dat_i(QSR_QERR) = '1' then |
qsr_reg(QSR_QERR) <= '0'; |
end if; |
--Set qsr_reg bit rom signal quad_ovflw |
if quad_ovflw = '1'and qcr_reg( QCR_ECNT) = '1' then |
if quad_ovflw = '1' then |
qsr_reg(QSR_CTOV) <= '1'; |
elsif wb_write = '1' and wb_adr_i = "01" and qsr_reg(QSR_CTOV) = '1' and wb_dat_i(QSR_CTOV) = '1' then |
elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_CTOV) = '1' and wb_dat_i(QSR_CTOV) = '1' then |
qsr_reg(QSR_CTOV) <= '0'; |
end if; |
--Set qsr_reg bit from signal quad_unflw |
if quad_unflw = '1' and qcr_reg( QCR_ECNT) = '1' then |
if quad_unflw = '1' then |
qsr_reg(QSR_CTUN) <= '1'; |
elsif wb_write = '1' and wb_adr_i = "01" and qsr_reg(QSR_CTUN) = '1' and wb_dat_i(QSR_CTUN) = '1' then |
elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_CTUN) = '1' and wb_dat_i(QSR_CTUN) = '1' then |
qsr_reg(QSR_CTUN) <= '0'; |
end if; |
--Set qsr_reg bit from signal quad_index |
if quad_index = '1' and qcr_reg( QCR_ECNT) = '1' then |
if quad_index = '1' then |
qsr_reg(QSR_INEV) <= '1'; |
elsif wb_write = '1' and wb_adr_i = "01" and qsr_reg(QSR_INEV) = '1' and wb_dat_i(QSR_INEV) = '1' then |
elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_INEV) = '1' and wb_dat_i(QSR_INEV) = '1' then |
qsr_reg(QSR_INEV) <= '0'; |
end if; |
--check quadrature compare bit |
if quad_comp = '1' then |
qsr_reg(QSR_CCME) <= '1'; |
elsif wb_write = '1' and wb_adr_i = QSR_ADDR and qsr_reg(QSR_CCME) = '1' and wb_dat_i(QSR_CCME) = '1' then |
qsr_reg(QSR_CCME) <= '0'; |
end if; |
end if; |
end if; |
end process qsr_reg_wr_proc; |
|
|
----------------------------------------------------------------------- |
-- Process: qrw_reg_wr_proc( wb_clk_i ) |
-- Desc: Handles writing to the Quadrature Read / Write Register, |
-- offset 0x08. |
-- Signals: |
-- Signals: wb_rst, reset signal |
-- QLAT bit of QCR reg, Quadrature latch |
-- quad_lat_flt, filtered external quadrature latch signal |
-- Notes: Use of this register is required to access the |
-- quadrature count. |
----------------------------------------------------------------------- |
qrw_reg_wr_proc: process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
qrw_reg <= (others =>'0'); |
elsif wb_write = '1' and wb_adr_i = "10" then |
elsif wb_write = '1' and wb_adr_i = QRW_ADDR then |
qrw_reg <= wb_dat_i; |
elsif qcr_reg(QCR_QLAT) = '1' or quad_lat_flt = '1' then |
elsif qcr_reg(QCR_QLAT) = '1' or quad_lat_flt = '1' or (qcr_reg(QCR_INRC) = '1' and quad_index = '1') then |
qrw_reg <= quad_count(QUAD_COUNT_WIDTH-1 downto 0); |
end if; |
end if; |
end if; |
end process qrw_reg_wr_proc; |
|
|
----------------------------------------------------------------------- |
-- Process: quad_regs_rd_proc( wb_clk_i ) |
-- Desc: Handles reading of all of the registers. |
-- Signals: |
-- Signals: wb_adr_i, Wishbone address input |
-- qcr_reg, Quadrature control register |
-- qsr_reg, Quadrature status register |
-- qrw_reg, Quadrature read/write register |
-- Notes: None. |
----------------------------------------------------------------------- |
quad_regs_rd_proc: process( wb_rst_i, wb_adr_i, qcr_reg, qsr_reg, qrw_reg ) begin |
case wb_adr_i is |
when "00" => |
wb_dat_o(QCR_BITS-1 downto 0) <= qcr_reg; |
wb_dat_o(31 downto QCR_BITS) <= (others => '0'); |
when "01" => |
wb_dat_o(QSR_BITS-1 downto 0) <= qsr_reg; |
wb_dat_o(31 downto QSR_BITS) <= (others => '0'); |
when "10" => |
wb_dat_o(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg; |
when others => |
wb_dat_o <= (others => '0' ); |
end case; |
quad_regs_rd_proc: process( wb_adr_i, qcr_reg, qsr_reg, qrw_reg ) begin |
case wb_adr_i is |
when QCR_ADDR => |
wb_dat_o(QCR_BITS-1 downto 0) <= qcr_reg; |
wb_dat_o(31 downto QCR_BITS) <= (others => '0'); |
when QSR_ADDR => |
wb_dat_o(QSR_BITS-1 downto 0) <= qsr_reg; |
wb_dat_o(31 downto QSR_BITS) <= (others => '0'); |
when QRW_ADDR => |
wb_dat_o(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg; |
when others => |
wb_dat_o <= (others => '0' ); |
end case; |
end process quad_regs_rd_proc; |
|
----------------------------------------------------------------------- |
-- Process: quad_lat_m_proc( wb_clk_i ) |
-- Desc: Rising edge detect for input quad_lat_i |
-- |
----------------------------------------------------------------------- |
quad_lat_m_proc : process( quad_lat_i ) begin |
if rising_edge( quad_lat_i ) then |
if wb_rst_i = '1' then |
quad_lat_m <= '0'; |
else |
quad_lat_m <= '1'; |
end if; |
|
if quad_lat_m = '1' then |
quad_lat_m <= '0'; |
end if; |
end if; |
end process; |
|
----------------------------------------------------------------------- |
-- Process: quad_lat_proc |
-- Desc: Metastable filter for quad_lat_i, sets internal signal |
-- |
----------------------------------------------------------------------- |
|
----------------------------------------------------------------------- |
-- Process: quad_lat_m_proc( wb_clk_i ) |
-- Desc: Rising edge detect for input quad_lat_i |
-- Signals: quad_lat_i, external quadratire latch input |
-- quad_lat_m, metastable quadature latch signal |
-- Note: This is an asynchronous signal; the metastable |
-- output is later latched to a synchronized internal |
-- signal for other module processes. |
----------------------------------------------------------------------- |
quad_lat_m_proc : process( quad_lat_i ) begin |
if rising_edge( quad_lat_i ) then |
if wb_rst_i = '1' then |
quad_lat_m <= '0'; |
else |
quad_lat_m <= '1'; |
end if; |
|
if quad_lat_m = '1' then |
quad_lat_m <= '0'; |
end if; |
end if; |
end process quad_lat_m_proc; |
|
----------------------------------------------------------------------- |
-- Process: quad_lat_proc |
-- Desc: Metastable filter for quad_lat_i, sets internal signal |
-- Signals: quad_lat_m, metastable latch signal |
-- quad_lat_q, stable latched signal |
-- quad_lat_flt, filtered signal used by other processe |
-- Note: Due to the filtering, there is a delay of 4 clk cycles |
-- from assertion of the signal until asserting internal |
-- processes. |
----------------------------------------------------------------------- |
quad_lat_proc: process( wb_clk_i) begin |
|
if rising_edge( wb_clk_i ) then |
|
if wb_rst_i = '1' then |
|
quad_lat_flt <= '0'; |
quad_lat_q <= '0'; |
|
quad_lat_q <= '0'; |
else |
if quad_lat_m = '1' then |
quad_lat_q <= '1'; |
end if; |
if quad_lat_q = '1' then |
quad_lat_q <= '0'; |
quad_lat_flt <= '1'; |
end if; |
|
if quad_lat_m = '1' then |
quad_lat_q <= '1'; |
end if; |
if quad_lat_q = '1' then |
quad_lat_q <= '0'; |
quad_lat_flt <= '1'; |
end if; |
if quad_lat_flt = '1' then |
quad_lat_flt <= '0'; |
end if; |
414,12 → 487,25
quad_chb_k <= not( quad_chb_buf(3) or quad_chb_buf(2) or quad_chb_buf(1) ); |
quad_idx_j <= quad_idx_buf(3) and quad_idx_buf(2) and quad_idx_buf(1); |
quad_idx_k <= not( quad_idx_buf(3) or quad_idx_buf(2) or quad_idx_buf(1) ); |
|
----------------------------------------------------------------------- |
-- Process: quad_filt_proc |
-- Desc: Digital filters for the quadrature inputs |
-- |
----------------------------------------------------------------------- |
|
----------------------------------------------------------------------- |
-- Process: quad_filt_proc |
-- Desc: Digital filters for the quadrature inputs. This is |
-- implemented with serial shift registers on all inputs; |
-- similar to the digital filters of the HCTL-2016. See |
-- that datasheet for more information. |
-- Signals: quad_cha_i, external input |
-- quad_chb_i, external input |
-- quad_idx_i, external input |
-- quad_cha_buf, input buffer for filtering |
-- quad_chb_buf, input buffer for filtering |
-- quad_cha_flt, filtered cha signal |
-- quad_chb_flt, filtered chb signal |
-- quad_cha_j, j signal for jk FF |
-- quad_cha_k, k signal for jk FF |
-- Note: Upon reset, all buffers are filled with the values |
-- present on the input pins. |
----------------------------------------------------------------------- |
quad_filt_proc: process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
453,17 → 539,22
end if; |
if quad_idx_k = '1' then |
quad_idx_flt <= '0'; |
end if; |
end if; |
end if; |
end if; |
end process quad_filt_proc; |
|
----------------------------------------------------------------------- |
-- Process: quad_state_proc |
-- Desc: Reads filtered values quad_cha_flt, quad_chb_flt and |
-- increments / decrements count based on prior state |
-- |
----------------------------------------------------------------------- |
-- Process: quad_state_proc |
-- Desc: Reads filtered values quad_cha_flt, quad_chb_flt and |
-- asserts the quad_trans and quad_dir signals. |
-- Signals: quad_st_old |
-- quad_st_new |
-- quad_trans |
-- quad_dir |
-- quad_error |
-- Notes: See the datasheet for more info. |
----------------------------------------------------------------------- |
quad_state_proc: process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
472,124 → 563,127
quad_trans <= '0'; |
quad_dir <= '0'; |
quad_error <= '0'; |
else |
else |
quad_st_new <= (quad_chb_flt & quad_cha_flt); |
quad_st_old <= quad_st_new; |
--state machine |
case quad_st_new is |
when QUAD_STATE_0 => --"00" |
case quad_st_old is |
when QUAD_STATE_0 => |
quad_trans <= '0'; |
when QUAD_STATE_3 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_1 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
--state machine enabled if counting |
if qcr_reg(QCR_ECNT) = '1' then |
case quad_st_new is |
when QUAD_STATE_0 => --"00" |
case quad_st_old is |
when QUAD_STATE_0 => |
quad_trans <= '0'; |
when QUAD_STATE_3 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_1 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
|
when QUAD_STATE_1 => --"01" |
case quad_st_old is |
when QUAD_STATE_1 => |
quad_trans <= '0'; |
when QUAD_STATE_0 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_2 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
when QUAD_STATE_1 => --"01" |
case quad_st_old is |
when QUAD_STATE_1 => |
quad_trans <= '0'; |
when QUAD_STATE_0 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_2 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
|
when QUAD_STATE_2 => --"11" |
case quad_st_old is |
when QUAD_STATE_2 => |
quad_trans <= '0'; |
when QUAD_STATE_1 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_3 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
when QUAD_STATE_2 => --"11" |
case quad_st_old is |
when QUAD_STATE_2 => |
quad_trans <= '0'; |
when QUAD_STATE_1 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_3 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
|
when QUAD_STATE_3 => --"10" |
case quad_st_old is |
when QUAD_STATE_3 => |
quad_trans <= '0'; |
when QUAD_STATE_2 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_0 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
when QUAD_STATE_3 => --"10" |
case quad_st_old is |
when QUAD_STATE_3 => |
quad_trans <= '0'; |
when QUAD_STATE_2 => --"10" -- dflt positive direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '0'; |
else |
quad_trans <= '1'; |
quad_dir <= '1'; |
end if; |
when QUAD_STATE_0 => --"01" -- dflt negative direction |
if qcr_reg(QCR_CTDR) = '1' then |
quad_trans <= '1'; |
quad_dir <= '1'; |
else |
quad_trans <= '1'; |
quad_dir <= '0'; |
end if; |
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_old |
|
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_new |
|
when others => |
quad_error <= '1'; |
quad_trans <= '0'; |
end case; --quad_st_new |
|
end if; |
|
if quad_trans = '1' then |
quad_trans <= '0'; |
end if; |
|
|
if quad_dir = '1' then |
quad_dir <= '0'; |
end if; |
|
|
if quad_error = '1' then |
quad_error <= '0'; |
end if; |
596,18 → 690,18
end if; |
end if; |
end process quad_state_proc; |
|
|
----------------------------------------------------------------------- |
-- Process: quad_count_proc( wb_clk_i ) |
-- Desc: Handles writing to the quad_count register. |
-- Desc: Handles writing to the quad_count register. |
-- First, pre-load events are handled; this may be triggered |
-- by writing a '1' to the qcr_reg QCR_PLCT bit location, or |
-- by an index_event assertion. Next, count events may be |
-- triggered by an assertion of the 'quad_trans' signal, |
-- triggered by an assertion of the 'quad_trans' signal, |
-- which causes the quad_count value to increment or |
-- decrement by one, based on the quad_dir signal. |
-- With each change on the count value, the counter is |
-- checked for over/underflow. If either is detected, the |
-- With each change on the count value, the counter is |
-- checked for over/underflow. If either is detected, the |
-- corresponding signal is asserted for one clock cycle. |
-- Signals: quad_count, QUAD_COUNT_WIDTH+1 bit length, holds the actual |
-- 4x quadrature counts. The extra bit (i.e., as compared |
627,12 → 721,16
quad_count <= (others =>'0'); |
quad_ovflw <= '0'; |
quad_unflw <= '0'; |
else |
--Pre-load count event; either from qcr_reg or index event |
elsif qcr_reg(QCR_PLCT) = '1' or (quad_index = '1' and qcr_reg(QCR_INFC) = '1') then |
quad_count(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg; |
quad_count(QUAD_COUNT_WIDTH) <= '0'; |
else |
if quad_trans = '1' and qcr_reg(QCR_ECNT) = '1' then |
if qcr_reg(QCR_PLCT) = '1' then |
quad_count(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg; |
quad_count(QUAD_COUNT_WIDTH) <= '0'; |
end if; |
if (quad_index = '1' and qcr_reg(QCR_INZC) = '1') then |
quad_count <= (others =>'0'); |
end if; |
if quad_trans = '1' then |
if quad_dir = '1' then |
quad_count <= quad_count + 1; |
else |
650,61 → 748,110
quad_ovflw <= '1'; |
end if; |
end if; |
--reset signals |
if quad_ovflw = '1' then |
quad_ovflw <= '0'; |
end if; |
if quad_unflw = '1' then |
quad_unflw <= '0'; |
end if; |
end if; |
--reset signals |
if quad_ovflw = '1' then |
quad_ovflw <= '0'; |
end if; |
if quad_unflw = '1' then |
quad_unflw <= '0'; |
end if; |
end if; |
end process quad_count_proc; |
|
----------------------------------------------------------------------- |
-- Preocess: quad_comp_proc( wb_clk_i ) |
-- Desc: Monitors the quad_count and the qwr_reg to assert the |
-- the quad_comp signal. |
-- Signals: wb_clk_i |
-- wb_rst_i |
-- quad_comp |
-- Note: When enabled, the quad_comp signal will get asserted |
-- every time the quad_count is latched into the qrw reg. |
----------------------------------------------------------------------- |
quad_comp_proc : process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
quad_comp <= '0'; |
elsif (quad_count(QUAD_COUNT_WIDTH-1 downto 0) = qrw_reg) and qcr_reg(QCR_CCME) = '1' and qsr_reg(QSR_CCME) = '0' then |
quad_comp <= '1'; |
end if; |
if quad_comp = '1' then |
quad_comp <= '0'; |
end if; |
end if; |
end process quad_comp_proc; |
|
----------------------------------------------------------------------- |
-- Process: quad_index_proc( wb_clk_i ) |
-- Desc: Controled the internal quad_index signal. This signal is |
-- Desc: Controls the internal quad_index signal. This signal is |
-- asserted to indicated the occurance of an index event. |
-- |
-- Signals: quad_index |
-- quad_cha_flt |
-- quad_chb_flt |
-- quad_index |
-- Note: None. |
----------------------------------------------------------------------- |
quad_index_proc : process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
quad_index <= '0'; |
elsif qcr_reg(QCR_INEN) = '1' and qcr_reg(QCR_ICHA) = quad_cha_flt |
and qcr_reg(QCR_ICHB) = quad_chb_flt and qcr_reg(QCR_IDXL) = quad_idx_flt then |
quad_index <= '1'; |
elsif qcr_reg(QCR_INEN) = '1' |
and qcr_reg(QCR_ECNT) = '1' |
and qcr_reg(QCR_ICHA) = quad_cha_flt |
and qcr_reg(QCR_ICHB) = quad_chb_flt |
and qcr_reg(QCR_IDXL) = quad_idx_flt then |
quad_index_d <= '1'; |
end if; |
--If quad_index is asserted, clear signal |
if quad_index_d = '1' then |
quad_index_d <= '0'; |
quad_index_d2<= '1'; |
end if; |
if quad_index_d2 ='1' then |
quad_index_d2 <= '0'; |
quad_index <= '1'; |
end if; |
if quad_index = '1' then |
quad_index <= '0'; |
end if; |
end if; |
end process quad_index_proc; |
|
----------------------------------------------------------------------- |
-- Process: quad_irq_proc |
-- Desc: |
-- |
----------------------------------------------------------------------- |
|
----------------------------------------------------------------------- |
-- Process: quad_irq_proc |
-- Desc: Handles writing to the internal signal quad_irq_int. |
-- This process checks to see if a valid interrupt signal |
-- is asserted along with the corresponding enable bit; if |
-- so, the external interrupt is asserted. |
-- Signals: quad_irq_int |
-- quad_error |
-- quad_ovflw |
-- quad_unflw |
-- quad_index |
-- quad_comp |
-- Note: The external interrupt is cleared after assertion when |
-- all status bits are cleared in the QSR register. |
-- |
----------------------------------------------------------------------- |
quad_irq_proc: process( wb_clk_i ) begin |
if rising_edge( wb_clk_i ) then |
if wb_rst_i = '1' then |
quad_irq_int <= '0'; |
elsif ( quad_error = '1' and qcr_reg(QCR_QEIE) = '1' ) |
or ( quad_ovflw = '1' and qcr_reg(QCR_OVIE) = '1' ) |
or ( quad_unflw = '1' and qcr_reg(QCR_UNIE) = '1' ) |
or ( quad_index = '1' and qcr_reg(QCR_INIE) = '1' ) then |
or ( quad_ovflw = '1' and qcr_reg(QCR_OVIE) = '1' ) |
or ( quad_unflw = '1' and qcr_reg(QCR_UNIE) = '1' ) |
or ( quad_index = '1' and qcr_reg(QCR_INIE) = '1' ) |
or ( quad_comp = '1' and qcr_reg(QCR_CMIE) = '1' ) then |
quad_irq_int <= '1'; |
elsif quad_irq_int = '1' and |
elsif quad_irq_int = '1' and |
not( ( qsr_reg(QSR_QERR) = '1' and qcr_reg(QCR_QEIE) = '1' ) |
or ( qsr_reg(QSR_CTOV) = '1' and qcr_reg(QCR_OVIE) = '1' ) |
or ( qsr_reg(QSR_CTUN) = '1' and qcr_reg(QCR_UNIE) = '1' ) |
or ( qsr_reg(QSR_INEV) = '1' and qcr_reg(QCR_INIE) = '1' ) ) then |
or ( qsr_reg(QSR_CTOV) = '1' and qcr_reg(QCR_OVIE) = '1' ) |
or ( qsr_reg(QSR_CTUN) = '1' and qcr_reg(QCR_UNIE) = '1' ) |
or ( qsr_reg(QSR_INEV) = '1' and qcr_reg(QCR_INIE) = '1' ) |
or ( qsr_reg(QSR_CCME) = '1' and qcr_reg(QCR_CMIE) = '1' ) ) then |
quad_irq_int <= '0'; |
end if; |
end if; |
end process quad_irq_proc; |
|
|
end architecture quad_decoder_rtl; |