Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Asynchronous pulse counter on fpga

Status
Not open for further replies.

shahulakthar

Member level 2
Joined
Oct 13, 2009
Messages
45
Helped
12
Reputation
24
Reaction score
10
Trophy points
1,288
Location
Chennai, India
Activity points
1,515
I need to count the external pulse coming on to FPGA.
Total time i take to count pulse is 5 sec.

internal clock is 50mhz.

external pulse duration is around 0.5 sec to 1.5 sec. so i am calculating number of pulses for 5 sec.

last 5sec pulses needs to be updated on 8 bit LED's.

not working as expected. output always shows "11110100" or "00000001"

Here is the VHDL code

Code:
library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;

entity fcnt is
    port (
	C : in std_logic;
	S : in std_logic;
	Q : out unsigned(7 downto 0));
end entity;

architecture RTL of fcnt is

    constant MAX_CLK : integer := 250000000;
    constant MAX_CNT : integer := 500;

    signal count : unsigned(Q'range) := (others => '0');
    signal toggle : std_logic := '0';

begin

    clk_proc : process (C)
	variable cnt_v : natural range 0 to MAX_CLK := 0;
    begin
	if rising_edge(C) then
	    if cnt_v = MAX_CLK then
		Q <= count;
		toggle <= not toggle;
		cnt_v := 0;
	    else
		cnt_v := cnt_v + 1;
	    end if;
	end if;
    end process;

    cnt_proc : process (S, toggle)
	variable cnt_v : natural range 0 to MAX_CNT := 0;
	variable last_v : std_logic := '0';
    begin
	if toggle /= last_v then 
	    last_v := toggle;
	    cnt_v := 0;

	elsif rising_edge(S) then
	    if cnt_v < MAX_CNT then
		cnt_v := cnt_v + 1;
	    end if;
	    count <= to_unsigned(cnt_v, count'length);
	end if;
    end process;

end RTL;

Regards,
shahul
 

So many questions:
Which signal is your external pulse?
Which one is your internal clock?
Why do you have those variables in the second process outside the clock ?
It's really not clear what you're trying to do here.
 

Which signal is your external pulse?
S is the external pulse

Which one is your internal clock?
C is the internal 50 Mhz clock

Why do you have those variables in the second process outside the clock ?
second process is based on toggle and external pulse. not based on the internal clock.

It's really not clear what you're trying to do here.
I want to count the number of asynchronous pulse (S) for 5 seconds.
 

Hi,

From hardware view...

I'd simply synchronize the async input signal to the internal clock with a DFF.
And to detect the rising edge I'd add a second DFF in series...an AND with one inverting input detects the edge
And this signal may directely act as ENA signal for a counter.

Klaus
 

not working as expected. output always shows "11110100" or "00000001"
Observed how? What's the test bench?

In any case, there's no proper synchronization in domain crossing. We would normally synchronize the asynchronous signal into the 50 MHz clock domain.

The really bad asynchronous code is here

Code VHDL - [expand]
1
2
3
if toggle /= last_v then 
        last_v := toggle;
        cnt_v := 0;

 

Hi,

From hardware view...

I'd simply synchronize the async input signal to the internal clock with a DFF.
And to detect the rising edge I'd add a second DFF in series...an AND with one inverting input detects the edge
And this signal may directely act as ENA signal for a counter.

Klaus

I updated the code with synchronize process. Please let me know is it the right way of synchronize.

Code:
library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;

entity fcnt is
    port (
	C : in std_logic;                         --- clock 50mhz
	S : in std_logic;                         --- external pulse
	Q : out unsigned(7 downto 0));  ---  pulse count in 5 sec 
end entity;

architecture RTL of fcnt is

    constant MAX_CLK : integer := 250000000;   --- 5 sec duration for pulse count
    constant MAX_CNT : integer := 256;              

    signal count : unsigned(Q'range) := (others => '0');
    signal toggle : std_logic := '0';
	 
	 signal reg1 :std_logic;
	 signal reg2 :std_logic;
	 signal edge :std_logic;

begin

    clk_proc : process (C)
	variable cnt_v : natural range 0 to MAX_CLK := 0;
    begin
	if rising_edge(C) then
	    if cnt_v = MAX_CLK then
		Q <= count;
		toggle <= not toggle;
		cnt_v := 0;
	    else
		cnt_v := cnt_v + 1;
	    end if;
	end if;
    end process;
	 
	reg: process(C)
	begin
		if rising_edge(C) then
			reg1  <= S;
			reg2  <= reg1;
	  end if;
	end process;

	edge <= reg1 and (not reg2);


    cnt_proc : process (edge, toggle)
	variable cnt_v : natural range 0 to MAX_CNT := 0;
	variable last_v : std_logic := '0';
    begin
	if toggle /= last_v then 
	    last_v := toggle;
	    cnt_v := 0;

	elsif rising_edge(edge) then
	    if cnt_v < MAX_CNT then
		cnt_v := cnt_v + 1;
	    end if;
	    count <= to_unsigned(cnt_v, count'length);
	end if;
    end process;
	 
end RTL;

Above code is not working as expected.
 

Execute everything under rising_edge(C).

I am not sure how to execute this process with rising_edge(C)

Code:
cnt_proc : process (edge, toggle)
	variable cnt_v : natural range 0 to MAX_CNT := 0;
	variable last_v : std_logic := '0';
    begin
	if toggle /= last_v then 
	    last_v := toggle;
	    cnt_v := 0;

	elsif rising_edge(edge) then
	    if cnt_v < MAX_CNT then
		cnt_v := cnt_v + 1;
	    end if;
	    count <= to_unsigned(cnt_v, count'length);
	end if;
    end process;
 

Hi,

With the "AND" ...EDGE indeed us the rising edge,
Therefore you don't need an extra "RISING" statement.

Pseudo code:
On every rising edge of C:
... reg1 = S
... reg2 = reg1
... if (reg1 and not reg2) then increment counter
...

For sure the timing is delayed by a clock...
So maybe it's more clear if the order is this way:
On every rising edge of C:
... if (reg1 and not reg2) then increment counter
... reg2 = reg1
... reg1 = S

But the result will be exactly the same

Klaus
 



Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
reg: process(C)
    begin
        if rising_edge(C) then
            reg1  <= S; -- synchronizer FF
            reg2  <= reg1; -- edge detection FF
      end if;
    end process;
 
    edge <= reg1 and (not reg2);


This is a 1 register synchronizer.
You need two FFs and then a third to do the edge detection to have a proper 2 stage synchronizer.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top