0
\$\begingroup\$

I'm supposed to write code for simple frequency meter. What it is supposed to do is: when you press button it should measure frequency of input signal based on 1Hz clock signal so the outcome won't need any dividing to get frequency. Basically measuring input signal "peaks" in 1s period. The result must be shown in kHz on 2 7digt displays (30-40kHz measurement).

I thought I'm gonna use state machine diagram but even if it is compileable in Active HDL, I get a "Error (10822): HDL error at Termometr_F.vhd(69): couldn't implement registers for assignments on this clock edge" in Quartus...

Here is my state diagram:

enter image description here

Is there a way to implement this diagram in Quartus software? I've tried another method: dividing input signal by 2 to get a gate signal and then counting pulses but dividing is also not compilable without using floating point operations for which I don't have liblaries for...

Here is the code:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;

entity Termometr_F is 
    port (
        Clock: in STD_LOGIC;
        input: in STD_LOGIC;
        measure: in STD_LOGIC;
        reset: in STD_LOGIC;
        ok: out STD_LOGIC;
        output: out INTEGER);
end Termometr_F;

architecture Termometr_F_arch of Termometr_F is


signal Count: INTEGER;


type Termometr_F_type is (
    S1, S2, S3, S4);

signal Termometr_F: Termometr_F_type;


begin


Termometr_F_machine: process (Clock)
begin
if Clock'event and Clock = '1' then

    case Termometr_F is
        when S1 =>
            output <= 0;
            Count <= 0;
            ok <= '0';
            if measure='1' then 
                Termometr_F <= S2;
            end if;
        when S2 =>
            if rising_edge(Clock) then  
                Termometr_F <= S3;
            end if;
        when S3 =>
            Count <= Count+1;
            if rising_edge(input) then  
                Termometr_F <= S3;
            elsif rising_edge(Clock) then   
                Termometr_F <= S4;
            end if;
        when S4 =>
            output <= count-1;
            Count <= 0;
            ok <= '1';
            if reset='1' then   
                Termometr_F <= S1;
            end if;
        when others =>
            null;
    end case;
end if;
end process;

end Termometr_F_arch;

Thanks in advance

EDIT: I gave up edge detecion and modified the code:

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity Termometr is 
    port (
        divider: inout STD_LOGIC;
        ----
        C : in std_logic;
        state: inout INTEGER;
        ---
        input: inout STD_LOGIC;
        pomiar: in STD_LOGIC;
        reset: in STD_LOGIC;
        ok: out STD_LOGIC;
        output: inout INTEGER;
        Y0,Y1,Y2,Y3: inout std_logic_vector(0 to 6));
end Termometr;

architecture Termometr_F_arch of Termometr is


signal Count: INTEGER;
signal gate: STD_LOGIC;
----
signal KLOK  : integer:=0;
signal O,O1,O2,O3: integer;
signal counter: integer:=0;
----


type Termometr_F_type is (
    S1, S2, S3, S4
);
signal Termometr_F: Termometr_F_type;


begin

----------------------------------------------------------------------
-- Machine: Termometr_F
----------------------------------------------------------------------
Termometr_F_machine: process (input)
begin
if input'event and input = '1' then
    if reset='0' then   
        Termometr_F <= S1;
        output <= 0;
        Count <= 0;
        ok <= '0';
    else
        case Termometr_F is
            when S1 =>
                output <= 0;
                Count <= 0;
                ok <= '0';
                state<=1;
                if pomiar='0' then  
                    Termometr_F <= S2;
                end if;
            when S2 =>
            state<=2;
                gate <= input and divider;
                if gate='1' then    
                    Termometr_F <= S3;
                end if;
            when S3 =>
            state<=3;
                Count <= Count+1;
                gate <= input and divider;
                if gate='1' then    
                    Termometr_F <= S3;
                elsif gate='0' then
                    Termometr_F <= S4;
                end if;
            when S4 =>
            state<=4;
                output <= Count;
                ok <= '1';
                gate <= '0';
                if reset='0' then   
                    Termometr_F <= S1;
                end if;
            when others =>
                null;
        end case;
    end if;
end if;
end process;
*-------------------
---TEST INPUT SIGNAL----
--------------------*
 process (C,input) 
    begin 
        if(reset='0') then
        KLOK<=0;
        input<='0';
            elsif(C'event and C='1') then
                KLOK <=KLOK+1;
                    if (KLOK = 5000) then   
                        input <= NOT input;
                        KLOK <= 0;
                    end if;
        end if;
    end process;
--------------------------
--GENERATING 0.5Hz SIGNAL---
--------------------------  
 process (C,divider)
    begin  
        if(reset='0') then
        counter<=0;
        divider<='0';
            elsif(C'event and C='1') then
                counter <=counter+1;
                    if (counter = 50000000) then     
                        divider <= NOT divider;
                        counter <= 0;
                    end if;
        end if;
    end process;
----------------------------
---- 7 digit conv---
---------------------------
    O<=output;
    O1<=((O mod 1000) - (O mod 100))/100;   
    O2<=((O mod 10000) - (O mod 1000))/1000;
    O3<=state;



with O1 select 
    Y1 <= "0000001" when 0,
    "1001111" when 1,
    "0010010" when 2,
    "0000110" when 3,
    "1001100" when 4,
    "0100100" when 5,
    "0100000" when 6,
    "0001111" when 7,
    "0000000" when 8,
    "0000100" when 9,
    "1111111" when others; 

    with O2 select 
    Y2 <= "0000001" when 0,
    "1001111" when 1,
    "0010010" when 2,
    "0000110" when 3,
    "1001100" when 4,
    "0100100" when 5,
    "0100000" when 6,
    "0001111" when 7,
    "0000000" when 8,
    "0000100" when 9,
    "1111111" when others;

    with O3 select 
    Y3 <= "0000001" when 0,
    "1001111" when 1,
    "0010010" when 2,
    "0000110" when 3,
    "1001100" when 4,
    "0100100" when 5,
    "0100000" when 6,
    "0001111" when 7,
    "0000000" when 8,
    "0000100" when 9,
    "1111111" when others;

end Termometr_F_arch;
\$\endgroup\$
  • 2
    \$\begingroup\$ You have a big problem here, because the error message refers to line 69 of a 49 line piece of code. See stackoverflow.com/help/mcve for the next step. \$\endgroup\$ – Brian Drummond Dec 29 '16 at 23:05
2
\$\begingroup\$

The fundamental problem is that you have conditional statements like

if rising_edge(...) then

buried inside a process that is already conditional on a clock edge. You can't have multiple edge sensitivities affecting the same signal, even if those sensitivities are actually on the same Clock in one case, but definitely NOT on a separate asynchronous signal (input).

Any inputs used in a state machine must already be synchronized to the same clock that the state machine is using. This may require adjusting the state machine definition a bit to accommodate this requirement while still implementing the desired functionality.

\$\endgroup\$
  • \$\begingroup\$ I've edited the code but still it's getting stuck in State 2 while in active HDL everything works properly... Without edge detection the outcome is incorrect but as for measuring 30-40kHz frequencies the error is only 4 counts so it seems acceptable. Is there any solution? \$\endgroup\$ – Rafael Dec 30 '16 at 13:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.