Ok here is this code in 3 separate files firs 2 files I didn't change because they are main building blocks.
firs file is Edge decoder witch senses both rising,falling edges and generate impulse caled STP (step) and this block decodes just one encoder channel input, maby by combining them together it could be possible to save additional cells ! this edge decoder consumes 4 cells.
Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
-- Entity Declaration
ENTITY EDge_decoder IS
-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
PORT
(
clock : IN STD_LOGIC;
ENC : IN STD_LOGIC;
STP : OUT STD_LOGIC
);
-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
END EDge_decoder;
ARCHITECTURE EDge_decoder_architecture OF EDge_decoder IS
signal E1_A :std_logic;
signal E1_IRQ :std_Logic;
signal BR :std_logic;
signal BF :std_logic;
Signal IRQ1_R : std_logic;
Signal IRQ1_F : std_logic;
BEGIN
E1_A <= ENC;
process(clock)
begin
if rising_edge(clock) then
IF BF ='0' then BR <='1'; end if;
if BR ='0' then BF <= '1'; end if;
if BF ='1' then
if E1_A ='1' then
BF <='0';
BR <='1';
IRQ1_R <= '1';
end if;
else irQ1_R <= '0';
end if;
IF BR ='1' then
if E1_A ='0' then
BR <='0';
BF <='1';
IRQ1_F <= '1';
end if;
else IRQ1_F <='0';
end if;
end if;
end process;
STP <= IRQ1_F xor IRQ1_R;
END EDge_decoder_architecture;
second is direction decoder it takes 6 cells:
Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
-- Entity Declaration
ENTITY ENC_DIR2 IS
-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
PORT
(
CX : IN STD_LOGIC;
clock : IN STD_LOGIC;
D_A : IN STD_LOGIC;
D_B : IN STD_LOGIC;
DIR : OUT STD_LOGIC;
AOUT : OUT STD_LOGIC;
BOUT : OUT STD_LOGIC;
COUT : OUT STD_LOGIC
);
-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
END ENC_DIR2;
-- Architecture Body
ARCHITECTURE ENC_DIR2_architecture OF ENC_DIR2 IS
signal A,AA1,B,BB1,izeja,izeja1,izeja2 : std_logic;
BEGIN
process(clock)
begin
if rising_edge(clock) then
A <= D_A;
end if;
end process;
process(clock,CX)
begin
IF CX ='1' then
if rising_edge(clock) then
B <= D_B;
end if;
end if;
end process;
BB1 <= NOT B;
COUT <= izeja1;
BOUT <= izeja2;
AOUT <= izeja;
Virz:process(A,clock)
variable index1 : std_logic;
begin
if rising_edge(clock) then
if A='1' then
if index1 ='1' then
izeja1 <= BB1;
index1 := '0';
end if;
else
index1 := '1';
end if;
end if;
end process;
Virz2 :process(A,clock)
variable index1 : std_logic;
begin
if rising_edge(clock) then
if A='0' then
if index1 = '1' then
izeja2 <= BB1;
index1 := '0';
end if;
else index1 :='1';
end if;
end if;
end process;
process(clock)
begin
if A ='1' then
izeja <= izeja1;
else izeja <= izeja2;
end if;
end process;
process(clock)
begin
if rising_edge(clock) then
if CX ='1' then
DIR <= A xor izeja;
end if;
end if;
end process;
END ENC_DIR2_architecture;
and then we have top-level file which combine all together and creates 32bit up down counter.
Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-- Entity Declaration
ENTITY Encoder_step_counter IS
-- {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
PORT
(
clock : IN STD_LOGIC;
A,B : IN STD_LOGIC;
count : OUT std_logic_vector( 31 downto 0)
);
-- {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
END Encoder_step_counter;
ARCHITECTURE Encoder_step_counter_architecture OF Encoder_step_counter IS
signal A1,B1,AB,DIR : std_logic;
signal counter : std_logic_vector(31 downto 0);
Component EDge_decoder IS
PORT
(
clock : IN STD_LOGIC;
ENC : IN STD_LOGIC;
STP : OUT STD_LOGIC
);
end component;
component ENC_DIR2 IS
PORT
(
CX : IN STD_LOGIC;
clock : IN STD_LOGIC;
D_A : IN STD_LOGIC;
D_B : IN STD_LOGIC;
DIR : OUT STD_LOGIC
);
end component;
BEGIN
A_chanel : EDge_decoder
PORT MAP( clock=>clock, ENC =>A, STP => A1);
B_chanel : EDge_decoder
PORT MAP( clock =>clock, ENC => B, STP => B1);
AB <= A1 xor B1;
Direction : ENC_DIR2
Port map( CX => AB, clock => clock, D_A=> A, D_B=> B, DIR=> DIR);
-- the main code starts here
process(clock)
begin
if rising_edge(clock) then
if AB ='1' then
if DIR ='1' then counter <= counter +1;
else Counter <= counter -1;
end if; end if; end if; end process;
count <= counter;
END Encoder_step_counter_architecture;
and here is little modified Jahonen code. I commented out all code that I didn't used leaving just pure Quad decoder + up down counter for comparison
Code:
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.numeric_std.all;
entity CNCzone_kods is
port (
clk : in std_logic;
dout : out unsigned(31 downto 0);
-- din : in unsigned(31 downto 0) := (others => '0');
cha_in : in std_logic;
chb_in : in std_logic;
cha_filtered_T,cha_T : out std_logic
);
-- load : in std_logic);
end CNCzone_kods;
architecture JTA_design of CNCzone_kods is
-- Input synchronizer
component isync is port (
sin : in std_logic;
sout : out std_logic;
clk : in std_logic);
end component isync;
-- Digital filter
component dfilter is port (
clk : in std_logic;
sin : in std_logic;
sout : out std_logic;
sample : in std_logic
);
end component dfilter;
signal qeposcnt : unsigned(31 downto 0);
signal cha : std_logic;
signal chb : std_logic;
signal cha_filtered : std_logic;
signal chb_filtered : std_logic;
signal cha_rise : std_logic;
signal cha_fall : std_logic;
signal chb_rise : std_logic;
signal chb_fall : std_logic;
signal inc_trig : std_logic;
signal dec_trig : std_logic;
signal currstate : std_logic_vector(1 downto 0);
signal samplecounter : integer range 0 to 255;
signal do_sample : std_logic;
--signal SAMPLING_INTERVAL : integer range 0 to 255:= 4;
begin
CHASYNC: isync port map(sin=>cha_in, sout=>cha, clk=>clk);
CHBSYNC: isync port map(sin=>chb_in, sout=>chb, clk=>clk);
CHAFILT: dfilter port map(sin=>cha, sout=>cha_filtered, clk=>clk, sample=>do_sample);
CHBFILT: dfilter port map(sin=>chb, sout=>chb_filtered, clk=>clk, sample=>do_sample);
cha_T <=cha;
cha_filtered_T<=cha_filtered;
--
-- Quadrature pulse decoder
--
-- The definition of direction is as follows:
--
-- "When the codewheel rotates in the counterclockwise direction (as viewed from the
-- encoder end of the motor), channel A will lead channel B. If the codewheel rotates
-- in the clockwise direction, channel B will lead channel A."
--
-- Clockwise direction increments counter and counterclockwise decrements, respectively.
--
-- 32 bit position counter state machine
--
process(clk,cha_filtered, chb_filtered)
variable newstate : std_logic_vector(1 downto 0);
begin
newstate := cha_filtered & chb_filtered;
if rising_edge(clk) then
if do_sample = '1' then
case currstate is
when "00" =>
if newstate = b"01" then
qeposcnt <= qeposcnt + 1;
elsif newstate = b"10" then
qeposcnt <= qeposcnt - 1;
end if;
when "01" =>
if newstate = b"11" then
qeposcnt <= qeposcnt + 1;
elsif newstate = b"00" then
qeposcnt <= qeposcnt - 1;
end if;
when "11" =>
if newstate = b"10" then
qeposcnt <= qeposcnt + 1;
elsif newstate = b"01" then
qeposcnt <= qeposcnt - 1;
end if;
when "10" =>
if newstate = b"00" then
qeposcnt <= qeposcnt + 1;
elsif newstate = b"11" then
qeposcnt <= qeposcnt - 1;
end if;
end case;
currstate <= (cha_filtered & chb_filtered);
end if;
-- if load='1' then
-- qeposcnt <= din;
-- end if;
dout <= qeposcnt;
end if;
end process;
do_sample <= '1'; -- add by me
--
--process(clk)
--begin
--
-- if rising_edge(clk) then
-- do_sample <= '0';
-- if samplecounter = SAMPLING_INTERVAL then
-- do_sample <= '1';
-- samplecounter <= 0;
-- else
-- samplecounter <= samplecounter + 1;
-- end if;
-- end if;
--end process;
end;
ass you can see all this Quad decoder+ counter is coded in one big Case statement called "currstate" and placed in one process statement thats why it executes in one clock cycle (compared to 2 clocks in my design) but consumes twice as much as my code (I mean quad_decoder+ direction not 32bit up down counter)