Forum: FPGA, VHDL & Co. Event Counter funktioniert nur in der Simulation


von Markus (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich möchte einen Impulszähler konstruieren. Die Rahmenbedingungen sind:

- systemtakt 20MHz
- Impulse (>= 1us) sollen gezählt werden
- periodisch (z.Zt. 100ms) soll das Ergebnis gepuffert, der Zähler 
zurückgesetzt,neu gestartet werden und weiterlaufen während dann das 
gepufferte Ergebnis seriell übertragen wird

Die serielle Übertragung kommt später, wenn der Zähler mal läuft. 
Aktuell funktioniert die Zählung in der Pre-Synth Simulation.
Der Synthesizer meint allerdings die Signale "Count" und "timebase" 
wären ungenutzt (Toplevel.srr Zeile 141ff). Ausserdem werden noch 
diverse Register rausoptimiert, was ich noch nicht einordnen kann.
Ich denke mal da habe ich was nicht synthetisierbares konstruiert.

der Counter:
1
entity Counter is
2
port (
3
    --<port_name> : <direction> <type>;
4
  clk : IN  std_logic;
5
    reset : IN std_logic;
6
  Count : IN  std_logic; 
7
    timebase : IN std_logic;
8
    
9
    rd : IN std_logic;
10
    busif : OUT std_logic_vector(15 downto 0) 
11
);
12
end Counter;
13
14
architecture architecture_Counter of Counter is
15
  signal cnt : integer range 0 to 65535 ; --16 bit
16
    signal count_processed : std_logic ;
17
    signal outputbuffer : std_logic_vector(15 downto 0); 
18
    signal buffer_filled : std_logic ;
19
20
begin
21
   -- architecture body
22
  event_counter : process (clk, reset, Count, count_processed, outputbuffer, timebase, buffer_filled)
23
  begin
24
    if reset='0' then 
25
      cnt <= 0;
26
      count_processed <= '0';
27
      buffer_filled <= '0';
28
      outputbuffer <= (others => '0');
29
    else
30
      if clk = '1' and clk'event then
31
          --increment counter
32
          if timebase = '1' then
33
            if Count='1' then
34
              if count_processed='0' then
35
                cnt <= cnt +1;
36
                count_processed <= '1';
37
              end if;
38
            else
39
              count_processed <= '0';
40
            end if; -- Count=1
41
            buffer_filled <='0' ;
42
          else    -- timebase=0
43
            if buffer_filled='0' then
44
              outputbuffer <= std_logic_vector(to_unsigned(cnt, 16));
45
              buffer_filled <='1' ;
46
            end if;
47
          end if; -- timebase=0
48
      end if; --clk
49
      
50
      if clk = '0' and clk'event then
51
        if buffer_filled='1' then
52
          cnt <= 0;
53
        end if; 
54
      end if;
55
    end if; --reset
56
  end process;
57
58
59
  readout : process (clk, rd, busif, outputbuffer, reset)
60
  begin
61
    if reset='0' then 
62
      busif <= (others => 'Z');
63
    else
64
      if clk = '1' and clk'event then
65
        if rd='1' then
66
          busif <= outputbuffer ;
67
        else
68
          busif <= (others => 'Z'); 
69
        end if;      
70
      end if;
71
    end if;
72
  end process;
73
74
end architecture_Counter;

Timebase:
1
entity Timebase is
2
generic ( TEILFAKTOR : natural := 2000000); -- Berechnung: gewuenschte Zeitbasis furch Periodendauer der Haupttaktes
3
                                             -- also z.B.: 100ms bei 20MHz -->  0.1/0.00000005 bzw. 100/0.00005 ->  2000000
4
5
port (
6
    --<port_name> : <direction> <type>;
7
  clk : IN  std_logic; 
8
  timebase : OUT  std_logic
9
);
10
end Timebase;
11
12
architecture architecture_Timebase of Timebase is
13
  signal timer :integer range 0 to 20000000; -- bis 20 MHz
14
begin
15
   -- architecture body
16
   tb : process (clk)
17
   begin
18
     if clk='1' and clk'event then
19
        if timer < TEILFAKTOR then
20
          timer <= timer +1;
21
          timebase <= '1';
22
        else
23
          timebase <= '0';
24
--          if timer < (TEILFAKTOR+1) then
25
--            timer <= timer +1;
26
--          else  
27
            timer <= 0;
28
--          end if;
29
        end if;
30
     end if;
31
   end process;
32
33
end architecture_Timebase;

Wer kann mir den entscheidenen Tipp geben?

Vielen Dank,
Markus

: Bearbeitet durch Moderator
von Blick mit Krausen (Gast)


Lesenswert?

Vermischte Taktflanken.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

1
use IEEE.std_logic_unsigned.all;
2
use IEEE.NUMERIC_STD.all;
Never ever!

Die numeric_std kann alles, was du brauchst.
1
process (clk, rd, busif, outputbuffer, reset)
Da gehören nur clk und reset rein. Und reset ist im Grunde nicht nötig.

1
      if clk = '1' and clk'event then
2
        ..... 
3
                cnt <= cnt +1;
4
5
      
6
      if clk = '0' and clk'event then
7
       ..... 
8
          cnt <= 0;
cnt sind 16 Flipflops. Und du möchtest da getne Flipflops haben, die mit 
beiden Flanken getriggert werden können. Hat dein FPGA sowas?

Mein Tipp: im gesamten Design nur 1 Takt und nur überall die selbe 
Flanke.

Markus schrieb:
> Impulse (>= 1us) sollen gezählt werden
Das heißt, wenn das Eingangssignal mindestens für 1us high ist? 
Vermutlich also zur Unterdrückung von Störungen...

Was soll aber passieren, wenn das Eingangssignal 10us high, dann 500ns 
liw, dann wieder 10us high ist? Ist das dann 1 gestörter Impuls, oder 
sind es 2 Impulse?

BTW: irgendwie habe ich den Eindruck, du machst das unnötig kompliziert 
mit den ganzen Enable Signalen...

Ich würde das entkoppeln und erst mal sicher stellen, dass ich nur 
gültige Impulse erkenne und verarbeite. Und das hat was mit "Entprellen" 
zu tun: erst, wenn das Signal 1us stabil ist, ist es ein valides Signal.

Wo ich das schreibe sehe ich gerade, dass du das vermutlich asynchrone 
Eingangssignal es ohne jegliche Einsynchronisierung verwendest. Das geht 
sicher schief.

: Bearbeitet durch Moderator
von Markus (Gast)


Lesenswert?

Lothar M. schrieb:
> Das heißt, wenn das Eingangssignal mindestens für 1us high ist?

Nicht zwingend. In der Praxis reicht es aber aus, nur diese Impulse zu 
berücksichtigen.

> Was soll aber passieren, wenn das Eingangssignal 10us high, dann 500ns
> liw, dann wieder 10us high ist? Ist das dann 1 gestörter Impuls, oder
> sind es 2 Impulse?

Das sind dann 2 Impulse. Eine Ausfilterung von Störungen ist (erstmal) 
nicht notwendig.
Bisher wird der Eventcounter eines Mikrocontrollers genutzt. Es gibt 
überlegungen auch weiterhin uC zu nutzen, allerdings wird das bei ~20 
Kanälen eher unsauber.

>
> BTW: irgendwie habe ich den Eindruck, du machst das unnötig kompliziert
> mit den ganzen Enable Signalen...

Kann sein. Es soll letztendlich festgestellt werden, wiviele Impulse in 
einer definierten Zeit angekommen sind.

Ich werde mal anfangen, die asynchronen Signale einzutakten und dann den 
Zähler neu konstruieren.

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe den Counter jetzt in einer Statemachine realisiert. In der 
Pre-Synth Simulation funktioniert das wie gewünscht. In der Post-Synth 
Simulation habe ich bei der funften clk-Flanke einen undefinierten 
Zustand.

Wo kann der Mist wieder herkommen?
1
entity Counter is
2
port (
3
    --<port_name> : <direction> <type>;
4
  clk : IN  std_logic;
5
    reset : IN std_logic;
6
  Count : IN  std_logic; 
7
    timebase : IN std_logic;
8
    
9
    rd : IN std_logic;
10
    busif : OUT std_logic_vector(15 downto 0) 
11
);
12
end Counter;
13
14
architecture architecture_Counter of Counter is
15
16
--    signal count_processed : std_logic ;
17
--    signal buffer_filled : std_logic ;
18
19
20
    signal count_0_int : std_logic ;
21
    signal count_int : std_logic ;
22
23
  signal cnt : integer range 0 to 65535 ; --16 bit
24
    signal outputbuffer : std_logic_vector(15 downto 0); 
25
26
    type states is(wait_for_count, count_recognized, door_closed, buffer_uptodate);
27
    signal state : states ;
28
29
begin
30
31
  sync : process (clk)
32
  begin
33
    if clk = '1' and clk'event then
34
      count_0_int <= Count;
35
      count_int <= count_0_int;  
36
    end if;
37
  end process;  
38
39
40
   -- architecture body
41
  event_counter : process (clk, reset)
42
  begin
43
    if reset='0' then 
44
      cnt <= 0;
45
      outputbuffer <= (others => '0');
46
      state <= wait_for_count ;
47
    else
48
      if clk = '1' and clk'event then
49
50
        case state is
51
          when wait_for_count => if timebase ='0' then
52
                                   state <= door_closed ;
53
                                 else
54
                                   if count_int = '1' then
55
                                     state <= count_recognized ;
56
                                     cnt <= cnt +1; 
57
                                   end if;    
58
                                 end if;
59
          when count_recognized => if timebase ='0' then
60
                                     state <= door_closed ;
61
                                   else
62
                                     if count_int = '0' then
63
                                       state <= wait_for_count ;
64
                                     end if;
65
                                   end if;
66
          when door_closed =>   outputbuffer <= std_logic_vector(to_unsigned(cnt, 16));
67
                                state <= buffer_uptodate ;
68
          when buffer_uptodate => cnt <= 0;
69
                                  if timebase ='1' then
70
                                    if count_int = '1' then
71
                                      state <= count_recognized ; -- Impulse beim uebergang ignorieren
72
                                    else
73
                                      state <= wait_for_count ;
74
                                    end if;
75
                                  end if;
76
                                                      
77
--          when others => state <= wait_for_count ;
78
        end case;
79
80
      end if; -- rising edge
81
    end if; --reset
82
  end process;
83
84
85
  readout : process (clk, rd, busif, outputbuffer, reset)
86
  begin
87
    if reset='0' then 
88
      busif <= (others => 'Z');
89
    else
90
      if clk = '1' and clk'event then
91
        if rd='1' then
92
          busif <= outputbuffer ;
93
        else
94
          busif <= (others => 'Z'); 
95
        end if;      
96
      end if;
97
    end if;
98
  end process;
99
100
end architecture_Counter;

Markus

: Bearbeitet durch Moderator
von Markus (Gast)


Lesenswert?

Habs gefunden. Das Problem war, daß "timebase" bei reset nicht 
initialisiert wurde:
1
architecture architecture_Timebase of Timebase is
2
  signal timer :integer range 0 to 20000000; -- bis 20 MHz
3
begin
4
   -- architecture body
5
   tb : process (clk, reset)
6
   begin
7
     if reset = '0' then
8
       timer <= 0;
9
       timebase <= '0' ; --  <- das hier fehlte
10
     else
11
       if clk='1' and clk'event then
12
          if timer < TEILFAKTOR then
13
            timer <= timer +1;
14
            timebase <= '1';
15
          else
16
            timebase <= '0';
17
--            if timer < (TEILFAKTOR+1) then
18
--              timer <= timer +1;
19
--            else  
20
              timer <= 0;
21
--            end if;
22
          end if;
23
       end if;
24
     end if;
25
   end process;
26
27
end architecture_Timebase;

Das Problem ist damit gelöst.

BTW: warum funktioniert die vhdl Formatierung nicht? Mache ich was 
falsch?

Markus

: Bearbeitet durch Moderator
von Achim S. (Gast)


Lesenswert?

Markus schrieb:
> BTW: warum funktioniert die vhdl Formatierung nicht? Mache ich was
> falsch?

[\vhdl]  statt [/vhdl]

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Markus schrieb:
> BTW: warum funktioniert die vhdl Formatierung nicht? Mache ich was
> falsch?
Nimm den / statt des \

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Das nächste Mal bitte gleich die Testbench mitliefern, damit sich ein 
Problem leichter nachvollziehen lässt.

Duke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Markus schrieb:
> Das Problem war, daß "timebase" bei reset nicht initialisiert wurde
1. Du kannst einen Initialwert bei der Deklaration des Signals angeben, 
dann ist
2. im ganzen Design kein Reset nötig. Denn was ist dieser "Reset"? Ein 
Knopf, wo jemand draufdrückt?

von Markus (Gast)


Lesenswert?

Lothar M. schrieb:
> 1. Du kannst einen Initialwert bei der Deklaration des Signals angeben,
> dann ist

Nein, das ist nicht möglich. Hast du selbst mal festgestellt:
Beitrag "Re: Modelsim: Zählerausgang funktioniert nicht"


> 2. im ganzen Design kein Reset nötig. Denn was ist dieser "Reset"? Ein
> Knopf, wo jemand draufdrückt?

Das wird ein Reset-Baustein.

Markus

von Blick mit Krausen (Gast)


Lesenswert?

Markus schrieb:
> Lothar M. schrieb:
>> 1. Du kannst einen Initialwert bei der Deklaration des Signals angeben,
>> dann ist
>
> Nein, das ist nicht möglich.

Klar ist das möglich, weil das LRM das so fordert (für die Simulation). 
Für manche FPGA-Architekturen kann das auch die Synthese: 
https://docs.xilinx.com/v/u/en-US/wp272

von Markus (Gast)


Lesenswert?

Blick mit Krausen schrieb:
> Klar ist das möglich, weil das LRM das so fordert (für die Simulation).

Da ich aber die Simulation möglichst nahe an der Realität haben möchte 
und meine FPGA-Architekturen das nicht hergibt bleibe ich beim Reset.

Markus

von Blick mit Krausen (Gast)


Lesenswert?

Markus schrieb:
> Blick mit Krausen schrieb:
>> Klar ist das möglich, weil das LRM das so fordert (für die Simulation).
>
> Da ich aber die Simulation möglichst nahe an der Realität haben möchte

Naja, man kann unterschiedliche Nähe zur Realität simulieren, jenachdem 
wielange man auf das Ergebniss warten will. Nah an der Realität ist man 
mit einer post-P&R aka timing simu - da wartet man aber ewig ....
Und eine Simulation bleibt eine Simulation, der Realität ist das 
wurscht, die macht ohnehin was real ist.

> und meine FPGA-Architekturen das nicht hergibt bleibe ich beim Reset.
Statt (klassisch, externen) PowerUp-Reset, könnte man auch eine (µC 
gesteuerte) Initphase vorsehen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Markus schrieb:
> Nein, das ist nicht möglich. Hast du selbst mal festgestellt Flash-FPGAs von 
Microsemi... Pech...

Markus schrieb:
> Da ich aber die Simulation möglichst nahe an der Realität haben möchte
Warum hat dann nicht jeder getaktete Prozess einen Reset-Pfad?

Die Sensitivliste dort ist noch zu lang:

readout : process (clk, rd, busif, outputbuffer, reset)

Das würde reichen:

readout : process (clk, reset)

Aber prinzipiell ist dieser Prozess eh seltsam, denn wenn das rd ein 
Steuersignal von außen ist, dann muss der externe Datenbus sofort 
reagieren und nicht erst beim nächsten Takt. Der ganze Prozess kann also 
auf diese Kombinatorik abgebildet werden:

busif <= outputbuffer when rd *'1' else (others => 'Z');

Wenn das aber ein Bus innerhalb des FPGAs ist, dann muss er sowieso in 
einen Multiplexer aufgelöst werden, denn im FPGA gibt es kein 'Z'.

von Markus (Gast)


Lesenswert?

Wie bekommt man das hin, dass in Modelsim die states im Klartext 
angezeigt werden?

Markus

von Pat A. (patamat)


Lesenswert?

Indem man für das Signal als Datentyp eine Enumeration aller States 
nimmt:
1
type  states (init, wait_for_count, count, done);
2
signal state: states;
Dann zeigt der Simulator die States im 'Klartext' an.

von Duke Scarring (Gast)


Lesenswert?

Markus schrieb:
> Wie bekommt man das hin, dass in Modelsim die states im Klartext
> angezeigt werden?
Das geht bei 'enumeration types' automatisch.
Bei einer 'post-synthesis' oder 'post-implementation' wird natürlich 
alles std_logic bzw. std_logic_vector gemappt und die Zuordnung geht 
verloren.
Aber in 99,5% der Fälle ist eine 'post-$$$'-Simulation nicht nötig.

Duke

von Kai K. (Gast)


Lesenswert?

Ohne das jetzt genau gelesen zu haben: Ich würde das Signal auf dem die 
Pulse passieren können per Schieberegister einsynchronisieren und dann 
aus dem seriellen Stream die Pulse rauslesen (evtl. per state machine: 
puls beginnt, puls endet). Und dann zählst Du halt wie oft die state 
machine durchgelaufen ist.

von Carsten S. (Gast)


Lesenswert?

Immer einsynchronisieren, auch wenn dir dabei Takte verloren gehen. Das 
kann sonst ganz komische Effekte geben wie: Funktioniert mal und nach 5 
Minuten wieder nicht. Das hat mir zum Beispiel bei den Xilinx Spartans 
schon Tage an Fehlersuche gekostet.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.