问题
I have got a small problem with my finite state machine which I have written in VHDL recently. I tried to create "intelligent" counter triggered by clock with frequency 2 Hz. This counter is built in one state of FSM and is started by pushing a button on DE2 board.
Firstly, whole system is in IDLE state and if I push this button, state is changed to COUNTING and counter begin to be incremented and his current value is shown on LED display. After it reach value of modulo, the state COUNTING is left back to IDLE and the counter is set up to zero.
My problem is that the counter doesn´t work correctly - the counting value was too great. So I tried to solve it with this construction: if (clk_tick´event and clk_tick = 1) then.... , there are some errors by synthesis: Error (10822): HDL error at Citac_FSM.vhd(57): couldn't implement registers for assignments on this clock edge
Error (10821): HDL error at Citac_FSM.vhd(62): can't infer register for "AUTOMAT:flg" because its behavior does not match any supported register model
Please, does somebody have an idea to solve it? And what is it correct way to write clock triggered FSM with two (or more) clock sources?
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_unsigned.all;
ENTITY Counter_FSM IS
GENERIC (
REGSIZE : integer := 8; -- range of counter
MODULO : natural := 50 -- modulo value
);
PORT (
CLK : IN STD_LOGIC; -- puls 50 MHz
CLK_tick : IN STD_LOGIC; -- puls 2 Hz
RESET : IN STD_LOGIC; -- reset
READY : OUT STD_LOGIC; -- counter is ready to start
START_C : IN STD_LOGIC; -- start of counting
DOUT : OUT STD_LOGIC_VECTOR(REGSIZE - 1 downto 0) --out
);
END Counter_FSM;
ARCHITECTURE Behavior OF Counter_FSM is
type counterState is (IDLE, COUNTING); -- states of FSM
signal currCounterState : counterState; -- current state
signal nextCounterState : counterState; -- next state
signal cnt : std_logic_vector(REGSIZE - 1 downto 0); -- counter
begin
UPDATE: process(RESET, CLK)
begin
if (RESET = '0') then
currCounterState <= IDLE;
elsif (CLK'event and CLK = '1') then
currCounterState <= nextCounterState;
end if;
end process;
COMBI: process (clk_tick, start_c, currCounterState)
variable flg : std_logic := '0';
begin
if (clk_tick'event and clk_tick = '1') then
flg := '1';
end if;
case currCounterState is
when IDLE =>
cnt <= (others => '0'); -- counter value = zero
READY <= '1'; -- we can start
if (start_c = '1') then -- if button is pushed
nextCounterState <= COUNTING; -- go to COUNTING
end if;
when COUNTING =>
READY <= '0';
if (flg = '1') then -- Was there impuls of 2 Hz?
cnt <= cnt + 1; -- yes -> incrementing
flg := '0';
if (cnt = MODULO) then -- if cnt = MODULO
cnt <= (others => '0'); -- then cnt = zero
nextCounterState <= IDLE;
end if;
end if;
when others =>
nextCounterState <= IDLE;
end case;
-- OUTPUT
douT <= cnt;
end process;
end Behavior;
Thank you very much.
Mirek
P.S.: I am sorry my English is not so good.
回答1:
First of all you should not use clk_tick as a second clock signal. What you should do is to save the previous value of clk_tick, then compare the current value of clk_tick to the previous value to detect a rinsing edge. Depending on how clk_tick is generated you might need to synchronize clk_tick to the clock domain of CLK.
You could write something like this:
when COUNTING =>
nextCounterState <= COUNTING;
READY <= '0';
if (prev_clk_tick = '0' and clk_tick = '1') then
next_cnt <= cnt + 1; -- yes -> incrementing
if (cnt = MODULO) then
next_cnt <= (others => '0');
nextCounterState <= IDLE;
end if;
end if;
I will leave it to you to add the extra registers.
回答2:
I have already solved my problem :-). I have moved the counter into separate process and then attached witch signals to FSM. So, it works very well.
By reading of button I am using two D flip-flops to synchronize it at the moment.
I have to make an observation on style of VHDL programming - it is too different to "normal" programming like C language :-D
Nice day!
来源:https://stackoverflow.com/questions/30302117/counter-inside-fsm-in-vhdl