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.

Troubles with latched counter

Status
Not open for further replies.

lbdcdrc

Newbie level 5
Joined
Feb 18, 2019
Messages
9
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
95
Hi all !

It's my first post here, so many thanks in advancy for any kind of help that you'll give =)

I working on a project based on an FPGA. One of the goals is to check a frequency (wich is different and lower than the main clock).

By surfing on this forum, I've decided to use 3 different entity the first, called "HundredusCounter" is written to get a a high level each 100us during one main clock period. Here is the code :

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity HundredusCounter is
  Port( clk : in STD_LOGIC;
        nCEN : out STD_LOGIC);
end HundredusCounter;

architecture Behavioral of HundredusCounter is
	signal timer : STD_LOGIC_VECTOR(11 downto 0) := "000000000000"; 
	signal reset: STD_LOGIC;

	begin 

	process (clk, reset) 
		begin
			if clk='1' and clk'event then
				if reset = '1' then 
					timer <= timer + 1;
					reset <= '0';
				elsif timer = "111110100000" then  --111110100000 means 4000
					timer <= "000000000000";
					reset <= '1';
				else
					timer <= timer + 1;
				end if;
			end if;

	end process;
	nCEN <= reset;
end Behavioral;

The second one is there to count the number of clock rising edge between two reset made by the previous bloc. Here is the code :

Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity FreqCounter is
  Port( rf_in : in STD_LOGIC;
        rst : in STD_LOGIC;
		  freqOut : out STD_LOGIC_VECTOR(10 downto 0):= "00000000000");
end FreqCounter;

architecture Behavioral of FreqCounter is
	signal counter : STD_LOGIC_VECTOR(10 downto 0) := "00000000000"; 	
	begin 

	process (rf_in, rst) 
		begin
			if rst='1' then
				counter <= "00000000000";
			elsif rf_in='1' and rf_in'event then
				counter <= counter + '1';
			end if;
		freqOut <= counter;
	end process;
end Behavioral;


I then have putted a 12-bits D latch to keep the value between the 100 us. Here is the code :
Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity d_latch_12_top is
    Port ( EN : in  STD_LOGIC;
           D  : in  STD_LOGIC_VECTOR(10 downto 0);
           Q  : out STD_LOGIC_vector(10 downto 0));
end d_latch_12_top;

architecture Behavioral of d_latch_12_top is
begin

process (EN, D)
begin
    if (EN = '1') then
        Q <= D;
    end if;
end process;

end Behavioral;

At the end, I 've connected the blocks alltogether like this :

final.png

I really don't know why, but it doesn't work =/

I always have a 0 on Q...

I would be soooooo thanks-full if one of you could help me !

Cedric
 

Both the components freqcounter rst pin and the en pin of the d_latch12_top are driven by the same signal ncen from the hundredscounter component.

As the freqcounter is in reset when the enable is high then all you ever get is a 0 in the latch.

I would avoid making a design with logic generated clocks (especially in an FPGA), and in this design you have 2 of them.
 
The short answer is that you get zero result because the frequency counter is reset before you latch the value, as already explained by ads-ee.

But you have two asynchronous clocks, and transferring the counter value from one to the other clock domain reliably involves some effort. Consider that the readout event can coincide with a rf_in edge. Latching a binary counter value can produce arbitrary wrong results in this case. You either need to use a gray coded counter or synchronize the readout signal to the rf_in clock domain.
 
Thanks for your answer ! I now understand the problem with the last D-latch.
Please, excuse me for theses newbie questions, but i'm quite new on FPGA...
I would like to make this design in the state of art, and it seems that you know the subject =)

I understand that creating severals logicals clocks isn't a good practice, but I face an unsolved answer : how to get the 100us timer AND the RF_count without using "homemade" clocks ? The RF signal can be between 2 and 10 Mhz, and the goal is to drive a DAC according to the value counted.

I don't know and to count both the main clock and the RF signal ...

Have you some tips ?

Thanks =)

Cédric
 

My FPGA works with a 40 MHz oscillator, so I use the main clock wich is normaly 40,000 (10 ppm).

So, if I understand well, I have to use a PLL based on my system clock (40 Mhz) and the unknow RF system (between 2 and 10 Mhz). Then I'll will have the two clocks synchronized ? Is this ok ?

Many thanks,

Cédric
 

I'll assume you somehow found a clock osc that has a frequency of 40.01 MHz as you are dividing down by 4001. If not then you have a 100.025 us clock period.

Most of us would synchronize the signals to the system clock first then do everything on that clock domain. Of course this introduces jitter to the count values captured in your latch. The jitter will be based on the 25 ns system clock period and the jitter introduced by the synchronization of the RF input.

If you continue with the asynchronous clocks you'll run into problems with synchronizing the capture of the frequency count, which will require a synchronizer to the rf_in (clock) signal, which will once again introduce jitter.

As both methods introduce jitter you might as well use the easiest solution, which is synchronize the rf_in first and then generate an enable to capture the current frequency count (which is done on the system clock). Doing this will make the entire design run off the system clock (clk) with no clock domain crossings.

- - - Updated - - -

FYI, In hundreduscounter you use reset as an enable, not a good way to name the signal as reset and preset are normally reserved by digital logic designers as the signal that sets the system to a known condition to start.

Anyone else looking at your code will have to take extra time to determine that the reset isn't resetting anything, but is actually an enable signal, so don't misname it.

- - - Updated - - -

Actually your hundreduscounter code is rather convoluted and isn't written better than the standard method of writing a counter.
e.g.

Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
-- sticking with your syncrhonous reset, though I'm not entirely sure what your original intention for reset was...
proces (clk)
begin
  if rising_edge(clk) then
    if (reset) then
      timer_1us <= (others => '0');
    elsif (timer_1us < 3999) then -- use vhdl type conversion to make this integer of 3999 into a slv.
      timer_1us <= timer_1us +1;
    else
      timer_1us <= (others => '0');
    end if;
  end if;
end process;

 
Oh, beginner mistake ! I didn't notice the 4001 divider ...

Thanks for this code, it's going to be helpfull !
The reset name was choosen because this signal will reset the RF counter (the next stage)...

Is PLL a good way to work on my troubles ? If yes, how to implement it ?

You're very helpfull, thanks for taking time for beginners like me.

Cedric
 

Using a PLL is overly complicated in my opinion and I never suggested using one.

If a ADPLL is used then it will still suffer from the same jitter you get using a synchronous design with a higher frequency clock.
 

Using a PLL is overly complicated in my opinion and I never suggested using one.

Hey,

I kmow that you nerver suggested that, but you were talking about synchronizing the two signals, RF_in and clock... The only way that comes to me is using a PLL.

I used your code, I now have a clean 100us second timer (on this example the timer was set on 5 for the simulation):

timer100us.png

But I still don't understand how to count the number of rising edges on RF_in without using RF_in as a clock.

I understand that I've to use the system clock (40Mhz) as the main clock for the freq_meter entity, but if I trigger the rising edges on the system clock, how can I see a rising edge on the RF signal ?
I don't know if I talk about this, but I cannot use the up time, because the duty cycle is not 0,5, and it's not constant.

I feel so idiot with my questions...
 

The most simple solution is to use synchronizer logic that generates a clock enable pulse in the 40 MHz domain for each rising edge of rf_in and perform all operations with 40 MHz clock. No PLLs involved.

Synchronizer example below. The edge synchronizer requires the pulse width of the ce input signal to be > one period of the clock. Otherwise a toggle synchronizer can be used.


Code VHDL - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ENTITY edge_sync IS
   PORT
   (
      clk   : IN STD_LOGIC;
      ce    : IN STD_LOGIC;
      ce_s  : OUT STD_LOGIC
    );
END ENTITY;
       
ARCHITECTURE rtl OF edge_sync IS
   SIGNAL ce_t      : STD_LOGIC_VECTOR(2 downto 0);
 
attribute altera_attribute : string;
attribute altera_attribute of rtl : architecture is 
    "-name SDC_STATEMENT ""set_false_path -to [get_registers *edge_sync:*|ce_t[0]]""";
BEGIN
   PROCESS (clk)
   BEGIN
      IF rising_edge(clk) THEN
         ce_t <= ce_t(1 downto 0) & ce;
         ce_s <= ce_t(1) and not ce_t(2);
      END IF;
   END PROCESS;
end rtl;

 
Hey !

Many thanks for this code !

I simulate it, and, I think I'm now going to understand !

Here is the result of the simulation :

synthe.png

So, the goal of this function is to synchronize the rising edge of RF_in with the rising edge of the main clock ?

Is it true to say that I now have to create an entity with as a main clock the ce_s from edge_sync and as an enable the output from my timer ?

You're really helpfull, but, also really good teachers =)

Cedric
 

I didn't find how to edit my previous post, sorry for the double post !

Finally, it works, hope that the state of art are we me ! I also corrected a mistake that I made before. I don't use the RF profided by the synthetiseur as a clock, but as a clock enable.

Here is the final diagram :

Diagram.png

And the final simulation withe the D-Latches :

timeline.png

It works pretty fine !

Here are my final entity :

HundedusCounter, wich created the timer : (thanks to ads-ee =) )
Code:
[syntax=vhdl]library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity HundredusCounter is
  Port( clk : in STD_LOGIC;
		  reset : in boolean;
		  out_100us : out STD_LOGIC);
end HundredusCounter;

architecture Behavioral of HundredusCounter is
	signal  timer_1us : STD_LOGIC_VECTOR(11 downto 0):= "000000000000";
	begin 
	process (clk)
	begin
	  if rising_edge(clk) then
		 if (reset) then
			timer_1us <= (others => '0');
			out_100us <= '0';
		 elsif (timer_1us < 100) then -- use vhdl type conversion to make this integer of 3999 into a slv.
			timer_1us <= timer_1us +1;
			out_100us <= '1';
		 else
			timer_1us <= (others => '0');
			out_100us <= '0';
		 end if;
	  end if;
	end process;
end Behavioral;[/syntax]

Edge_synth, wich synchronize the RF input to the system clock (thanks to FvM) :

Code:
[syntax=vhdl]library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

ENTITY edge_sync IS
   PORT
   (
      clk   : IN STD_LOGIC;
      ce    : IN STD_LOGIC;
      ce_s  : OUT STD_LOGIC
    );
END ENTITY;
       
ARCHITECTURE rtl OF edge_sync IS
   SIGNAL ce_t      : STD_LOGIC_VECTOR(2 downto 0);
 
attribute altera_attribute : string;
attribute altera_attribute of rtl : architecture is 
    "-name SDC_STATEMENT ""set_false_path -to [get_registers *edge_sync:*|ce_t[0]]""";
BEGIN
   PROCESS (clk)
   BEGIN
      IF rising_edge(clk) THEN
         ce_t <= ce_t(1 downto 0) & ce;
         ce_s <= ce_t(1) and not ce_t(2);
      END IF;
   END PROCESS;
end rtl;[/syntax]


The counter, wich work wich the system clock as the main clock, and the RF_in_synth as the clock enable :

Code:
[syntax=vhdl]library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Counter2_VHDL is
   port( Clock_enable_B: in std_logic;
 	 Clock: in std_logic;
 	 Reset: in std_logic;
	 endVal : out std_logic;
 	 Output: out std_logic_vector(11 downto 0));
end Counter2_VHDL;
 
architecture Behavioral of Counter2_VHDL is
   signal temp: std_logic_vector(11 downto 0);
	signal endofcount : std_logic;
begin   process(Clock,Reset)
   begin
      if Reset='0' then
			endofcount <= '1';
		elsif endofcount = '1' then
			temp<=(others => '0');
			endofcount <= '0';
      elsif(rising_edge(Clock)) then
         if Clock_enable_B='1' then
            if temp= 4095 then
               temp<=(others => '0');
            else
               temp <= temp + 1;
            end if;
         end if;
      end if;
   end process;
   Output <= temp;
	endVal <= endofcount;
end Behavioral;[/syntax]

And then, the final 12Bit D-Latch :

Code:
[syntax=vhdl]library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity d_latch_12_top is
    Port ( EN : in  STD_LOGIC;
			  clk : in STD_LOGIC;
           D  : in  STD_LOGIC_VECTOR(11 downto 0);
           Q  : out STD_LOGIC_vector(11 downto 0));
end d_latch_12_top;

architecture Behavioral of d_latch_12_top is
begin

process (EN, D, clk)
begin
	IF rising_edge(clk) THEN
		 if (EN = '1') then
			  Q <= D;
		 end if;
	end if;
end process;

end Behavioral;[/syntax]

What do you think about this ? It's working, but is it correct ?

I also have a last question, I now need to multiply the final result by 1.023, how can i do this ?

I was thinking about making a multiplier by 1023 and then divide by 1000, but it seems hard to do, is there an easier way ?

One more time, thanks for your help !

Cedric
 

This conversation uses the word latch a lot... but I wonder if it really is the correct word. The FPGA fabric typically has DFFs, and the logic described above will become a flop with a gated clock or a muxed input. I don't see how you can latches from it.
 

Hi,

I also have a last question, I now need to multiply the final result by 1.023, how can i do this ?
I didn´t go through the complete thread.

But it seems you are doing some frequency measurement.
For this you use a "gate" time of 100us.

If so.... you could simply multiply the result by 1.023 when you use a gate time of "102.3us"

Klaus
 

The counter design is likely to cause irregular behavior by using asynchronous reset. Now, as you have moved everything to a single clock domain, all actions can and should should be performed in synchronous logic.
 

This conversation uses the word latch a lot... but I wonder if it really is the correct word. The FPGA fabric typically has DFFs, and the logic described above will become a flop with a gated clock or a muxed input. I don't see how you can latches from it.

ThisIsNotSam, I don't understand what the problem is ? My knowledge on FPGA is too short...


If so.... you could simply multiply the result by 1.023 when you use a gate time of "102.3us"

Klaus, this solution is sooooo smart, because it's so easy ! Thanks a lot !!!

all actions can and should should be performed in synchronous logic

FvM, I now understand ! I'll move all the signals to the clock edges !


I'm going to try all the modifications tomorrow, and let you know the results.
Many thanks for all the advices, you're really nice ! I just wonder what does the message from Sam means. It would change the content of my dreams =)

Cedric
 

Simply put, we don't design with latches unless there is a very good reason for doing so.

The preferred sequential element is, by far, a D-type flip-flop. I know you coded something that looks like a latch... but what I am saying is that the tool will map that to a flop instead. Your enable signal will become a clock gate or a mux.
 

Sam,

Are you only talking about the last entity (Which is called d_latch_12) or the whole design ?
If it's only the last one, what's the proper way to implement the same function ? If not, how can I do ? I have the feeling that this design is working pretty fine...

Thanks,

Cédric
 

It is your poorly named file d_latch_12. What you have coded in #12 is no longer a level sensitive latch, but is a D Flip-flop with an active high enable. IMO you shouldn't even have a separate file for this trivial bit of code.

If you had named the file dffe or d_register_12 it would have not even merited a comment. Even about it being a trivial amount of code in it's own file.

There isn't really anything inherently wrong with a latch, but the tools used for ASIC/FPGA design have problems with analyzing designs with latches due to all the time borrowing that goes on. Because it is both difficult to analyze and to write constraints for latches, it's become the norm to never allow them in a design. Besides that in modern FPGAs the basic single bit storage element is a DFF (back in the early days of FPGAs they used to be programmable as either a true level sensitive latch or a D-FF).

- - - Updated - - -

BTW, remove the EN and D from the process sensitivity list in d_latch_12 they are not needed as the code has if rising_edge(clk) ....

All they effectively do is slow a simulator down. Only simulators use the sensitivity list, synthesis tools ignore it, and if you get a simulation to work with a incorrect sensitivity list you are more likely to end up with a design that either won't synthesize or doesn't work after synthesis.

e.g.

Code VHDL - [expand]
1
2
3
4
5
6
7
8
process (clkr, clkf)
begin
  if rising_edge(clkr) then
    ...
  elsif falling_edge(clkf) then
    ...
  end if;
end process;


This will run in a simulator but won't synthesize.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top