Line 3... |
Line 3... |
-- Desc: HDL implementation of a quadrature decoder with a Wishbone bus
|
-- Desc: HDL implementation of a quadrature decoder with a Wishbone bus
|
-- interface. See the "quad_decoder" datasheet for more information.
|
-- interface. See the "quad_decoder" datasheet for more information.
|
-- Date: Initiated October, 2009
|
-- Date: Initiated October, 2009
|
-- Auth: Scott Nortman, COPYRIGHT 2009 Bridge Electronic Design LLC
|
-- Auth: Scott Nortman, COPYRIGHT 2009 Bridge Electronic Design LLC
|
-- scott.nortman@gmail.com
|
-- scott.nortman@gmail.com
|
--------------------------------------------------------------------------------
|
|
--
|
--
|
-- REVISION INFORMATION
|
-- NOTE: If you find this file useful / helpful, please let me know :)
|
--
|
--
|
-- Current Version: 0.9.0
|
--------------------------------------------------------------------------------
|
--
|
--
|
-- When Who What
|
-- REVISION INFORMATION
|
-- ---------------------------------------------------------------------------
|
|
-- 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;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
Line 51... |
Line 82... |
|
|
--Register and bit definitions
|
--Register and bit definitions
|
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
-- Quadrature Control Register, QCR, offset 0x00
|
-- Quadrature Control Register, QCR, offset 0x00
|
--
|
--
|
-- Bit 0: Enable Counting, ENCT
|
-- Bit 0: Enable Counting, ECNT
|
-- 0 -> Quadrature counting disabled
|
-- 0 -> Quadrature counting disabled
|
-- 1 -> Quadrature counting enabled
|
-- 1 -> Quadrature counting enabled
|
-- Bit 1: Set Count Direction, CTDR
|
-- Bit 1: Set Count Direction, CTDR
|
-- 0 -> Counts positive when A leads B
|
-- 0 -> Counts positive when A leads B
|
-- 1 -> Counts negative when A leads B
|
-- 1 -> Counts negative when A leads B
|
-- Bit 2: Index Enable Bit, INEN
|
-- Bit 2: Index Enable Bit, INEN
|
-- 0 -> Index input disabled
|
-- 0 -> Index input disabled
|
-- 1 -> Index input enabled
|
-- 1 -> Index input enabled
|
-- Bit 3: Index Function Bit, INFC
|
-- Bit 3: Index Zero Count Bit, INZC
|
-- 0 -> Internal count not affected.
|
-- 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
|
-- Bit 4: Index Interrupt Enable, INIE
|
-- 0 -> Index interrupt request disabled
|
-- 0 -> Index interrupt request disabled
|
-- 1 -> Index interrupt request enabled
|
-- 1 -> Index interrupt request enabled
|
-- Bit 5: Pre Load Count register, PLCT
|
-- Bit 5: Pre Load Count register, PLCT
|
-- 0 -> No action.
|
-- 0 -> No action.
|
Line 90... |
Line 121... |
-- 0 -> Index asserted when quadature index is logic low
|
-- 0 -> Index asserted when quadature index is logic low
|
-- 1 -> Index asserted when quadrature index is logic high
|
-- 1 -> Index asserted when quadrature index is logic high
|
-- Bit 12: Quadrature Error Interrupt enable, QEIE
|
-- Bit 12: Quadrature Error Interrupt enable, QEIE
|
-- 0 -> Quadrature Error Interrupt disabled
|
-- 0 -> Quadrature Error Interrupt disabled
|
-- 1 -> Quadrature Error Interrupt enabled
|
-- 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_ECNT : integer := 0;
|
constant QCR_CTDR : integer := 1; --test ok
|
constant QCR_CTDR : integer := 1;
|
constant QCR_INEN : integer := 2; --test ok
|
constant QCR_INEN : integer := 2;
|
constant QCR_INFC : integer := 3; --test ok
|
constant QCR_INZC : integer := 3;
|
constant QCR_INIE : integer := 4; --test ok
|
constant QCR_INIE : integer := 4;
|
constant QCR_PLCT : integer := 5; --test ok
|
constant QCR_PLCT : integer := 5;
|
constant QCR_UNIE : integer := 6; --test ok
|
constant QCR_UNIE : integer := 6;
|
constant QCR_OVIE : integer := 7; --test ok
|
constant QCR_OVIE : integer := 7;
|
constant QCR_QLAT : integer := 8; --test ok
|
constant QCR_QLAT : integer := 8;
|
constant QCR_ICHA : integer := 9; --test ok
|
constant QCR_ICHA : integer := 9;
|
constant QCR_ICHB : integer := 10;--test ok
|
constant QCR_ICHB : integer := 10;
|
constant QCR_IDXL : integer := 11;--test ok
|
constant QCR_IDXL : integer := 11;
|
constant QCR_QEIE : integer := 12;--test ok
|
constant QCR_QEIE : integer := 12;
|
constant QCR_BITS : integer := 13; --Number of bits used in QCR register
|
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
|
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
|
-- Quadrature Status Register, QSR, offset 0x04
|
-- Note: User clears set bits by writing a 1 to the correspoding register
|
-- Note: User clears set bits by writing a 1 to the correspoding register
|
-- bit.
|
-- bit.
|
Line 125... |
Line 169... |
-- 0 -> No underflow detected
|
-- 0 -> No underflow detected
|
-- 1 -> Counter underflow from 0x0000 to 0xFFFF
|
-- 1 -> Counter underflow from 0x0000 to 0xFFFF
|
-- Bit 3: Index event, INEV, auto set, user cleared
|
-- Bit 3: Index event, INEV, auto set, user cleared
|
-- 0 -> Index event has not occurred
|
-- 0 -> Index event has not occurred
|
-- 1 -> Index event occured, interrupt requested if INIE set
|
-- 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_QERR : integer := 0;
|
constant QSR_CTOV : integer := 1; --test ok
|
constant QSR_CTOV : integer := 1;
|
constant QSR_CTUN : integer := 2; --test ok
|
constant QSR_CTUN : integer := 2;
|
constant QSR_INEV : integer := 3; --test ok
|
constant QSR_INEV : integer := 3;
|
constant QSR_BITS : integer := 4; -- Num bits in QSR reg
|
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
|
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
|
--Signals indicating status information for the QSR process
|
signal quad_error : std_logic;
|
signal quad_error : std_logic;
|
signal quad_ovflw : std_logic;
|
signal quad_ovflw : std_logic;
|
signal quad_unflw : std_logic;
|
signal quad_unflw : std_logic;
|
signal quad_index : 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
|
-- Quadrature Count Read / Write Register, QRW, offset 0x08
|
-- Note: The actual quadrature count value must be latched prior to
|
-- Note: The actual quadrature count value must be latched prior to
|
-- reading from this register. This may be triggered two ways:
|
-- reading from this register. This may be triggered two ways:
|
Line 153... |
Line 205... |
-- copied to the QCT register.
|
-- copied to the QCT register.
|
--
|
--
|
-- This register is also used to hold the pre-load count value.
|
-- This register is also used to hold the pre-load count value.
|
-- After writing to this register, the pre-load value is
|
-- After writing to this register, the pre-load value is
|
-- transferred to the quadrature count register by writing a '1'
|
-- 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.
|
-- quadrature control register (QCR) offset 0x00.
|
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
signal qrw_reg : std_logic_vector(QUAD_COUNT_WIDTH-1 downto 0);
|
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
|
--Actual quadrature counter register, extra bit for over/underflow detect
|
signal quad_count : std_logic_vector(QUAD_COUNT_WIDTH downto 0);
|
signal quad_count : std_logic_vector(QUAD_COUNT_WIDTH downto 0);
|
|
|
--Input buffers / filters for quadrature signals
|
--Input buffers / filters for quadrature signals
|
Line 175... |
Line 228... |
signal quad_chb_j : std_logic;
|
signal quad_chb_j : std_logic;
|
signal quad_chb_k : std_logic;
|
signal quad_chb_k : std_logic;
|
signal quad_idx_j : std_logic;
|
signal quad_idx_j : std_logic;
|
signal quad_idx_k : std_logic;
|
signal quad_idx_k : std_logic;
|
|
|
|
|
signal quad_lat_flt : std_logic;
|
signal quad_lat_flt : std_logic;
|
signal quad_lat_q : std_logic;
|
signal quad_lat_q : std_logic;
|
signal quad_lat_m : std_logic;
|
signal quad_lat_m : std_logic;
|
|
|
--Quadrature 4X decoding state machine signals
|
--Quadrature 4X decoding state machine signals
|
Line 201... |
Line 253... |
signal ack_dly : std_logic;
|
signal ack_dly : std_logic;
|
|
|
--Internal irq signal
|
--Internal irq signal
|
signal quad_irq_int: std_logic;
|
signal quad_irq_int: std_logic;
|
|
|
|
-- Internal signal to latch quad count on index assertion
|
|
signal qcnt_idx_latch : std_logic;
|
|
|
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
--Start of RTL
|
--Start of RTL
|
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
begin
|
begin
|
|
|
|
--Assign internal signal to external signal
|
quad_irq_o <= quad_irq_int;
|
quad_irq_o <= quad_irq_int;
|
|
|
-- Handle wishbone ack generation / internal write signals
|
-- Handle wishbone ack generation / internal write signals
|
wb_request <= wb_stb_i and wb_cyc_i;
|
wb_request <= wb_stb_i and wb_cyc_i;
|
wb_write <= wb_request and wb_we_i;
|
wb_write <= wb_request and wb_we_i;
|
Line 224... |
Line 278... |
-- operations have completed before acknowledging the
|
-- operations have completed before acknowledging the
|
-- master device.
|
-- master device.
|
-- Signals: wb_clk_i
|
-- Signals: wb_clk_i
|
-- ack_dly
|
-- ack_dly
|
-- wb_rst_i
|
-- wb_rst_i
|
-- Notes:
|
-- Notes: Verified using the Wishbone bus of the TSK3000 from
|
|
-- Altium Designer.
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
ack_dly_proc: process( wb_clk_i ) begin
|
ack_dly_proc: process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
ack_dly <= '0';
|
ack_dly <= '0';
|
Line 254... |
Line 309... |
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
qcr_reg_wr_proc: process( wb_clk_i ) begin
|
qcr_reg_wr_proc: process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
qcr_reg <= (others => '0');
|
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);
|
qcr_reg <= wb_dat_i(QCR_BITS-1 downto 0);
|
end if;
|
end if;
|
--See if PLCT asserted, should be auto-cleared
|
--See if PLCT asserted, should be auto-cleared
|
if qcr_reg(QCR_PLCT) = '1' then
|
if qcr_reg(QCR_PLCT) = '1' then
|
qcr_reg(QCR_PLCT) <= '0';
|
qcr_reg(QCR_PLCT) <= '0';
|
Line 293... |
Line 348... |
qsr_reg <= (others => '0');
|
qsr_reg <= (others => '0');
|
else
|
else
|
--Set qsr_reg bit from signal quad_error
|
--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';
|
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';
|
qsr_reg(QSR_QERR) <= '0';
|
end if;
|
end if;
|
--Set qsr_reg bit rom signal quad_ovflw
|
--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';
|
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';
|
qsr_reg(QSR_CTOV) <= '0';
|
end if;
|
end if;
|
--Set qsr_reg bit from signal quad_unflw
|
--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';
|
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';
|
qsr_reg(QSR_CTUN) <= '0';
|
end if;
|
end if;
|
--Set qsr_reg bit from signal quad_index
|
--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';
|
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';
|
qsr_reg(QSR_INEV) <= '0';
|
end if;
|
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 if;
|
end if;
|
end process qsr_reg_wr_proc;
|
end process qsr_reg_wr_proc;
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: qrw_reg_wr_proc( wb_clk_i )
|
-- Process: qrw_reg_wr_proc( wb_clk_i )
|
-- Desc: Handles writing to the Quadrature Read / Write Register,
|
-- Desc: Handles writing to the Quadrature Read / Write Register,
|
-- offset 0x08.
|
-- 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
|
qrw_reg_wr_proc: process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
qrw_reg <= (others =>'0');
|
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;
|
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);
|
qrw_reg <= quad_count(QUAD_COUNT_WIDTH-1 downto 0);
|
end if;
|
end if;
|
end if;
|
end if;
|
end process qrw_reg_wr_proc;
|
end process qrw_reg_wr_proc;
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: quad_regs_rd_proc( wb_clk_i )
|
-- Process: quad_regs_rd_proc( wb_clk_i )
|
-- Desc: Handles reading of all of the registers.
|
-- 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
|
quad_regs_rd_proc: process( wb_adr_i, qcr_reg, qsr_reg, qrw_reg ) begin
|
case wb_adr_i is
|
case wb_adr_i is
|
when "00" =>
|
when QCR_ADDR =>
|
wb_dat_o(QCR_BITS-1 downto 0) <= qcr_reg;
|
wb_dat_o(QCR_BITS-1 downto 0) <= qcr_reg;
|
wb_dat_o(31 downto QCR_BITS) <= (others => '0');
|
wb_dat_o(31 downto QCR_BITS) <= (others => '0');
|
when "01" =>
|
when QSR_ADDR =>
|
wb_dat_o(QSR_BITS-1 downto 0) <= qsr_reg;
|
wb_dat_o(QSR_BITS-1 downto 0) <= qsr_reg;
|
wb_dat_o(31 downto QSR_BITS) <= (others => '0');
|
wb_dat_o(31 downto QSR_BITS) <= (others => '0');
|
when "10" =>
|
when QRW_ADDR =>
|
wb_dat_o(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg;
|
wb_dat_o(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg;
|
when others =>
|
when others =>
|
wb_dat_o <= (others => '0' );
|
wb_dat_o <= (others => '0' );
|
end case;
|
end case;
|
end process quad_regs_rd_proc;
|
end process quad_regs_rd_proc;
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: quad_lat_m_proc( wb_clk_i )
|
-- Process: quad_lat_m_proc( wb_clk_i )
|
-- Desc: Rising edge detect for input quad_lat_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
|
quad_lat_m_proc : process( quad_lat_i ) begin
|
if rising_edge( quad_lat_i ) then
|
if rising_edge( quad_lat_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
quad_lat_m <= '0';
|
quad_lat_m <= '0';
|
Line 373... |
Line 446... |
|
|
if quad_lat_m = '1' then
|
if quad_lat_m = '1' then
|
quad_lat_m <= '0';
|
quad_lat_m <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process quad_lat_m_proc;
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: quad_lat_proc
|
-- Process: quad_lat_proc
|
-- Desc: Metastable filter for quad_lat_i, sets internal signal
|
-- 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
|
quad_lat_proc: process( wb_clk_i) begin
|
|
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
|
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
|
|
quad_lat_flt <= '0';
|
quad_lat_flt <= '0';
|
quad_lat_q <= '0';
|
quad_lat_q <= '0';
|
|
|
else
|
else
|
if quad_lat_m = '1' then
|
if quad_lat_m = '1' then
|
quad_lat_q <= '1';
|
quad_lat_q <= '1';
|
end if;
|
end if;
|
if quad_lat_q = '1' then
|
if quad_lat_q = '1' then
|
quad_lat_q <= '0';
|
quad_lat_q <= '0';
|
quad_lat_flt <= '1';
|
quad_lat_flt <= '1';
|
end if;
|
end if;
|
|
|
if quad_lat_flt = '1' then
|
if quad_lat_flt = '1' then
|
quad_lat_flt <= '0';
|
quad_lat_flt <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
Line 415... |
Line 488... |
quad_idx_j <= quad_idx_buf(3) and quad_idx_buf(2) and quad_idx_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) );
|
quad_idx_k <= not( quad_idx_buf(3) or quad_idx_buf(2) or quad_idx_buf(1) );
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: quad_filt_proc
|
-- Process: quad_filt_proc
|
-- Desc: Digital filters for the quadrature inputs
|
-- 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
|
quad_filt_proc: process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
quad_cha_buf <= ( quad_cha_i & quad_cha_i & quad_cha_i & quad_cha_i );
|
quad_cha_buf <= ( quad_cha_i & quad_cha_i & quad_cha_i & quad_cha_i );
|
Line 459... |
Line 545... |
end process quad_filt_proc;
|
end process quad_filt_proc;
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: quad_state_proc
|
-- Process: quad_state_proc
|
-- Desc: Reads filtered values quad_cha_flt, quad_chb_flt and
|
-- Desc: Reads filtered values quad_cha_flt, quad_chb_flt and
|
-- increments / decrements count based on prior state
|
-- 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
|
quad_state_proc: process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
quad_st_old <= (quad_chb_i & quad_cha_i);
|
quad_st_old <= (quad_chb_i & quad_cha_i);
|
Line 473... |
Line 564... |
quad_dir <= '0';
|
quad_dir <= '0';
|
quad_error <= '0';
|
quad_error <= '0';
|
else
|
else
|
quad_st_new <= (quad_chb_flt & quad_cha_flt);
|
quad_st_new <= (quad_chb_flt & quad_cha_flt);
|
quad_st_old <= quad_st_new;
|
quad_st_old <= quad_st_new;
|
--state machine
|
--state machine enabled if counting
|
|
if qcr_reg(QCR_ECNT) = '1' then
|
case quad_st_new is
|
case quad_st_new is
|
when QUAD_STATE_0 => --"00"
|
when QUAD_STATE_0 => --"00"
|
case quad_st_old is
|
case quad_st_old is
|
when QUAD_STATE_0 =>
|
when QUAD_STATE_0 =>
|
quad_trans <= '0';
|
quad_trans <= '0';
|
Line 580... |
Line 672... |
when others =>
|
when others =>
|
quad_error <= '1';
|
quad_error <= '1';
|
quad_trans <= '0';
|
quad_trans <= '0';
|
end case; --quad_st_new
|
end case; --quad_st_new
|
|
|
|
end if;
|
|
|
if quad_trans = '1' then
|
if quad_trans = '1' then
|
quad_trans <= '0';
|
quad_trans <= '0';
|
end if;
|
end if;
|
|
|
if quad_dir = '1' then
|
if quad_dir = '1' then
|
Line 625... |
Line 719... |
--Reset event
|
--Reset event
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
quad_count <= (others =>'0');
|
quad_count <= (others =>'0');
|
quad_ovflw <= '0';
|
quad_ovflw <= '0';
|
quad_unflw <= '0';
|
quad_unflw <= '0';
|
|
else
|
--Pre-load count event; either from qcr_reg or index event
|
--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
|
if qcr_reg(QCR_PLCT) = '1' then
|
quad_count(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg;
|
quad_count(QUAD_COUNT_WIDTH-1 downto 0) <= qrw_reg;
|
quad_count(QUAD_COUNT_WIDTH) <= '0';
|
quad_count(QUAD_COUNT_WIDTH) <= '0';
|
else
|
end if;
|
if quad_trans = '1' and qcr_reg(QCR_ECNT) = '1' then
|
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
|
if quad_dir = '1' then
|
quad_count <= quad_count + 1;
|
quad_count <= quad_count + 1;
|
else
|
else
|
quad_count <= quad_count - 1;
|
quad_count <= quad_count - 1;
|
end if;
|
end if;
|
Line 648... |
Line 746... |
quad_unflw <= '1';
|
quad_unflw <= '1';
|
else
|
else
|
quad_ovflw <= '1';
|
quad_ovflw <= '1';
|
end if;
|
end if;
|
end if;
|
end if;
|
|
end if;
|
--reset signals
|
--reset signals
|
if quad_ovflw = '1' then
|
if quad_ovflw = '1' then
|
quad_ovflw <= '0';
|
quad_ovflw <= '0';
|
end if;
|
end if;
|
if quad_unflw = '1' then
|
if quad_unflw = '1' then
|
quad_unflw <= '0';
|
quad_unflw <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
|
end process quad_count_proc;
|
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 )
|
-- 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.
|
-- 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
|
quad_index_proc : process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
quad_index <= '0';
|
quad_index <= '0';
|
elsif qcr_reg(QCR_INEN) = '1' and qcr_reg(QCR_ICHA) = quad_cha_flt
|
elsif qcr_reg(QCR_INEN) = '1'
|
and qcr_reg(QCR_ICHB) = quad_chb_flt and qcr_reg(QCR_IDXL) = quad_idx_flt then
|
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_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';
|
quad_index <= '1';
|
end if;
|
end if;
|
--If quad_index is asserted, clear signal
|
|
if quad_index = '1' then
|
if quad_index = '1' then
|
quad_index <= '0';
|
quad_index <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process quad_index_proc;
|
end process quad_index_proc;
|
|
|
-----------------------------------------------------------------------
|
-----------------------------------------------------------------------
|
-- Process: quad_irq_proc
|
-- Process: quad_irq_proc
|
-- Desc:
|
-- 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
|
quad_irq_proc: process( wb_clk_i ) begin
|
if rising_edge( wb_clk_i ) then
|
if rising_edge( wb_clk_i ) then
|
if wb_rst_i = '1' then
|
if wb_rst_i = '1' then
|
quad_irq_int <= '0';
|
quad_irq_int <= '0';
|
elsif ( quad_error = '1' and qcr_reg(QCR_QEIE) = '1' )
|
elsif ( quad_error = '1' and qcr_reg(QCR_QEIE) = '1' )
|
or ( quad_ovflw = '1' and qcr_reg(QCR_OVIE) = '1' )
|
or ( quad_ovflw = '1' and qcr_reg(QCR_OVIE) = '1' )
|
or ( quad_unflw = '1' and qcr_reg(QCR_UNIE) = '1' )
|
or ( quad_unflw = '1' and qcr_reg(QCR_UNIE) = '1' )
|
or ( quad_index = '1' and qcr_reg(QCR_INIE) = '1' ) then
|
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';
|
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' )
|
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_CTOV) = '1' and qcr_reg(QCR_OVIE) = '1' )
|
or ( qsr_reg(QSR_CTUN) = '1' and qcr_reg(QCR_UNIE) = '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_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';
|
quad_irq_int <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
end process quad_irq_proc;
|
end process quad_irq_proc;
|
|
|
|
|
end architecture quad_decoder_rtl;
|
end architecture quad_decoder_rtl;
|
|
|
No newline at end of file
|
No newline at end of file
|