Forum Discussion
Altera_Forum
Honored Contributor
12 years agoThis code has 4x counter decoding. Extra IF statements were added in the counter and it also had modified pulse output section.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
ENTITY EncoderDecoder IS
GENERIC
(
CNTR_SZ : INTEGER := 32;
COEFF_SZ : INTEGER := 8
);
PORT
(
clk : IN STD_LOGIC;
rstn : IN STD_LOGIC;
clrcnt : IN STD_LOGIC;
encA : IN STD_LOGIC;
encB : IN STD_LOGIC;
rd : IN STD_LOGIC;
coeff : IN STD_LOGIC_VECTOR(COEFF_SZ-1 DOWNTO 0);
ch_coeff : IN STD_LOGIC;
pls : OUT STD_LOGIC;
counter : OUT STD_LOGIC_VECTOR(CNTR_SZ-1 DOWNTO 0);
dbg_cnt : OUT STD_LOGIC_VECTOR(CNTR_SZ-1 DOWNTO 0)
);
END ENTITY;
ARCHITECTURE behv OF EncoderDecoder IS
signal temp_encA : STD_LOGIC_VECTOR(2 DOWNTO 0);
signal temp_encB : STD_LOGIC_VECTOR(2 DOWNTO 0);
signal temp_counter : SIGNED(CNTR_SZ-1 DOWNTO 0);
signal counter_reg : SIGNED(CNTR_SZ-1 DOWNTO 0);
signal sync_encA : STD_LOGIC;
signal sync_encB : STD_LOGIC;
signal rising_encA : STD_LOGIC;
signal falling_encA : STD_LOGIC;
signal rising_encB : STD_LOGIC;
signal falling_encB : STD_LOGIC;
signal coeff_val : UNSIGNED(COEFF_SZ-1 DOWNTO 0);
signal pulse : STD_LOGIC;
signal out_pls : STD_LOGIC;
BEGIN
PROCESS(clk, rstn)
BEGIN
IF(rstn = '0') THEN
coeff_val <= (others => '0');
ELSIF(rising_edge(clk)) THEN
IF(ch_coeff = '1') THEN
coeff_val <= unsigned(coeff);
END IF;
END IF;
END PROCESS;
dbg_cnt <= std_logic_vector(temp_counter);
-- Synchronize encoder A and B inputs and also detect falling and rising edges
-- (1) used as 2-DFF synchronizer output for each signal
-- (2) used to detect rising/falling edges
PROCESS(clk, rstn)
BEGIN
IF(rstn = '0') THEN
temp_encA <= (others=>'0');
temp_encB <= (others=>'0');
ELSIF(rising_edge(clk)) THEN
temp_encA <= temp_encA(1 DOWNTO 0) & encA;
temp_encB <= temp_encB(1 DOWNTO 0) & encB;
END IF;
END PROCESS;
sync_encA <= temp_encA(1);
sync_encB <= temp_encB(1);
rising_encA <= '1' WHEN temp_encA(2) = '0' AND temp_encA(1) = '1' ELSE '0';
rising_encB <= '1' WHEN temp_encB(2) = '0' AND temp_encB(1) = '1' ELSE '0';
falling_encA <= '1' WHEN temp_encA(2) = '1' AND temp_encA(1) = '0' ELSE '0';
falling_encB <= '1' WHEN temp_encB(2) = '1' AND temp_encB(1) = '0' ELSE '0';
-- 4x decoding and detecting pulse rising edge
pulse <= rising_encA XOR rising_encB XOR falling_encA XOR falling_encB;
-- updating counter
-- clrcnt is used to clear the counter back to 0
-- for that we need to use clk and not pulse in the process
-- if clrn is not needed - pulse can be used as clock to update the counter
PROCESS(clk, rstn, clrcnt)
BEGIN
IF(rstn = '0') THEN
temp_counter <= (others=>'0');
ELSIF(rising_edge(clk)) THEN
IF(clrcnt = '1') THEN
temp_counter <= (others => '0');
ELSIF(rising_encB = '1' AND sync_encA = '1') THEN
temp_counter <= temp_counter + 1;
ELSIF(rising_encB = '1' AND sync_encA = '0') THEN
temp_counter <= temp_counter - 1;
ELSIF(falling_encB = '1' AND sync_encA = '0') THEN
temp_counter <= temp_counter + 1;
ELSIF(falling_encB = '1' AND sync_encA = '1') THEN
temp_counter <= temp_counter - 1;
ELSIF(rising_encA = '1' AND sync_encB = '0') THEN
temp_counter <= temp_counter + 1;
ELSIF(rising_encA = '1' AND sync_encB = '1') THEN
temp_counter <= temp_counter - 1;
ELSIF(falling_encA = '1' AND sync_encB = '1') THEN
temp_counter <= temp_counter + 1;
ELSIF(falling_encA = '1' AND sync_encB = '0') THEN
temp_counter <= temp_counter - 1;
ELSE
temp_counter <= temp_counter + 0;
END IF;
END IF;
END PROCESS;
-- Outputs
-- RD pulse latches the counter value to the output
-- so it can be processed as needed elsewhere while counter is still being updated.
PROCESS(clk, rstn, rd)
BEGIN
IF(rstn = '0') THEN
counter <= (others => '0');
counter_reg <= (others => '0');
ELSIF(rising_edge(clk)) THEN
IF(rd = '1') THEN
counter_reg <= temp_counter;
counter <= std_logic_vector(temp_counter);
ELSE
counter <= std_logic_vector(counter_reg);
END IF;
END IF;
END PROCESS;
-- Will output a single pulse when a number of pulses from encoder is reached
-- it can be used for counts to mm conversion when a number of pulses is known (= value should be put into coeff)
-- pulse will be single clk long
PROCESS(clk, pulse, rstn)
VARIABLE cnt : INTEGER := 0;
BEGIN
IF(rstn = '0') THEN
cnt := 0;
out_pls <= '0';
ELSIF(rising_edge(clk)) THEN
IF(pulse = '1') THEN
IF(cnt = coeff_val) THEN
out_pls <= '1';
cnt := 0;
ELSE
out_pls <= '0';
cnt := cnt + 1;
END IF;
ELSE
out_pls <= '0';
END IF;
END IF;
END PROCESS;
pls <= pulse WHEN (coeff_val = 0 OR coeff_val = 1) ELSE out_pls;
END behv;