Forum: FPGA, VHDL & Co. Steigende Flanke als eine Art Trigger


von Andreas B. (loopy83)


Lesenswert?

Hallo,

ich habe hier ein Problem und weiß nicht so recht, wie ich es umsetzen 
kann.

Ich habe ein asynchrones FIFO, also unterschiedlicher Schreib- und 
Lesetakt.

Es werden kontinuierlich Daten in den Fifo geschrieben. Da der Lesetakt 
aber schneller ist als der Schreibtakt, muss ich eine "Leseverzögerung" 
einbauen. Gelesen wird von einem externen Device.

Ich habe nun vereinbart, dass das externe Device immer 1024 DoubleByte 
aus dem FIFO lesen soll (FIFO ist 16bit breit x 2048 Zeilen) und dann 
auf einen Interrupt wartet. Es kann natürlich nur 1024 DByte lesen, wenn 
diese auch da sind. Das bedeutet, dass der Interrupt erst auslösen darf, 
wenn die ersten 1024 DByte im Fifo sind.

Dazu habe ich mir eine Zählschleife ausgedacht, die immer, wenn 1024 
Schreibzyklen vorbei sind, ein Interrupt ausgelöst wird. Nach diesem 
Interrupt sollen die Daten aus dem FIFO ausgelesen werden, uns zwar 
synchron zum externen Lesetakt.

Wie kann ich die steigende Flanke des IRQ Signals nutzen um dem 
Read-Device zu sagen, jetzt kannste deine 1024 Datenpakete abholen?

Wäre eine Lösung über das Read-enable denkbar?
Ich hatte mir gedacht, wieder einen Zähler zu bauen, der bis 1024 zählt 
und danach den rd_en auf Low letzt und dann erst wieder aktiviert, wenn 
der Trigger kommt, dass weitere 1024 Datensätze geschrieben wurden.

Nur leider muss ich dann den process von dem Triggersignal und dem 
Readclock abhängig machen, Trigger setzt den counter auf Null und der 
Readclock zählt ihn nach oben... da bekomme ich aber sicher Probleme bei 
der Synthese.

Hat jemand eine Idee, wie ich diese Sache elegant lösen kann?

VIELEN DANK!

von Jan M. (mueschel)


Lesenswert?

Ich gehe mal davon aus, du generierst dir den Fifo mit dem 
entsprechenden Tool des Herstellers deines FPGAs? Diese bieten meist 
auch die Option eines "almost empty" oder "almost full" Signals mit 
einstellbaren Schwellen. Du setzt also die Schwelle fuer das "almost 
empty" auf 1024.

Dann wartest du bis almost empty 0 ist, liest deine 1024 Daten aus und 
wartest wieder.

von Christian R. (supachris)


Lesenswert?

Kannst du denn das Lesen nicht stoppen? Normal macht man das so, dass 
man das Empty Flag des FIFOs natürlich beachtet und nur ausliest, wenn 
auch was drin ist. Ob du dann 1024 Byte oder sonstwas ausliest ist egal, 
wichtig ist, den Zähler und die gesamte weitere Verarbeitung anzuhalten, 
bis wieder was im FIFO ist.

von Andreas B. (loopy83)


Lesenswert?

Danke für die Antworten!

Ja das Fifo erstelle ich mit dem CoreGen, auch das AlmostEmty Flag ist 
dabei. Wußte bisher nicht, dass ich dabei eine Schwelle einstellen kann. 
Das wäre natürlich recht komfortabel. Sobald 1024 DByte drin sind, 
können sie ausgelesen werden. Das schaue ich mir mal an! Wobei ich hier 
aber sicher das AlmostFull Bit nehmen muss, denn der FIFO wird ja 
unterhalb von 1024 aufgefüllt.

@ Christian:
Ich hatte mir durch diese Methode eigentlich etwas geschaffen, dass es 
in keinem Fall zu einem empty kommen kann. Dadurch, dass immer 1024 DB 
ausgelesen werden, aber parallel dazu wieder neue Daten reinkommen, kann 
es nie leer werden. Denn sobald wieder 1024 da sind, wird wieder 
ausgelesen.

Die Übertragung zum externen Device soll burstartig verlaufen. Also 
Übertragen (1024x16bit) und dann wieder warten, bis weitere 1024 Pakete 
anliegen und wieder auslesen...

DANKE!!!

EDIT:
Dabei fällt mir eigentlich auf, dass das Almost_full Flag ja auch nur 
ein Trigger wäre, den ich mir ja schon künstlich durch die Schleife 
geschaffen habe. Die kann ich damit abschaffen, aber mein eigentliches 
Problem, dass der Read-process dann vom externen Readtakt und (!) vom 
almost_full Flag abhängt, hab ich damit immer noch nicht erschlagen. Ich 
schau mal, vielleicht fällt mir dazu noch etwas ein... vielleicht 
funktioniert es ja schon mit einer einfachen if Abfrage und ich komme 
nur noch nicht drauf :)

von Klaus F. (kfalser)


Lesenswert?

Du brauchst eigentlich auch keine getrennten Zähler, das Fifo kann Dir 
einen Zähler ausgeben, der sagt, wieviel Daten im Fifo sind.

Ich würde eine State-Machine bauen, die diesen Zähler beobachtet.
Sobald 1024 Daten drinnen sind, fängt dies an, 1024 x auszulesen. Nach 
dem Auslesen springt man wieder in den Beobachtung-State, wenn wieder 
1024 drinnen sind, geht's weiter, sonst wird eben in diesem State 
gewartet, bis es soweit ist.

von Andreas B. (loopy83)


Lesenswert?

Ich bin leider noch nicht so lange im Geschäft :)
Wie implementiere ich eine State-machine und wie weise ich ihr eine 
Funktion zu? Ist das auch nur eine Art automatisch generierter Core, 
oder muss ich die Funktion selber erzeugen bzw. generieren?

Deine Variante klingt recht logisch bzw. sehr anschaulich.

Leider habe ich gerade noch das problem, dass mein Fifo auch bei 
Grenzwert 8 (so viel schreibe ich erstmal testeweise in den Fifo, statt 
der 1024, damit ich es besser simulieren kann und nicht 1024 Flanken 
abzählen muss) kein almoist_full Flag setzt, das bleibt leider 
behaarlich auf 0.

DANKE!

von Iulius (Gast)


Lesenswert?

Hast du es auch richtig konfiguriert ?

Die almost/programmable full/empty Signale funktionieren eigentlich gut.

Dann musst du nurnoch dieses Signal auswerten und fertig.


- warten bis almost full=1
- 1024 mal auslesen (alternativ : auslesen bis empty = 1 wenn es nicht 
zwingend maximal 1024er Blöcke sein müssen)
- warten bis almost full=1
...

das sind genau 2 Zustände im Automaten(read_enable=0 und read_enable=1)


Sowas kannst du noch ganz simpel in 2-3 If-Then erledigen.

von Christian R. (supachris)


Lesenswert?

Achso, für Burst-Übertragung ist das natürlich dann sehr günstig mit den 
Flags. Ich glaub, die Almost-Full sind fest, aber Prog-Full kannst du 
einstellen auf eine beliebige Anzahl. Übrigens werden die Flags synchron 
zum Takt der jeweiligen Seite ausgegeben. Also Empty synchron zur 
Lese-Seite und Full synchron zur Schreibseite. Somit kannst du am besten 
mit dem Prog-Empty Flag arbeiten, das ist dann schon synchron zum 
Lesetakt.

von Andreas B. (loopy83)


Lesenswert?

DANKE für die Antworten und die Hilfe.

Kann mir jemand sagen wieso die markierte if-Anweisung in der SImulation 
ignoriert wird und die Daten sofort an den Ausgang geschaltet werden?
1
DATA_READ: process (PClk, FIFO_prog_emty, PADD(10), PCS1, POEn, PRnW, PER_RSTn)
2
begin
3
  if rising_edge(PClk) then
4
    if (FIFO_prog_emty = '0') then --=> wird in der Simulation ignoriert!!!
5
      if (PCS1 = '0' and POEn = '0' and PRnW = '1' and PER_RSTn = '1') then    
6
          if (PADD(10) = '1') then
7
            DATA_OUT <= DATA_OUT_FIFO;
8
          else 
9
            DATA_OUT <= (others => 'Z');
10
          end if;
11
      else 
12
        DATA_OUT <= (others => 'Z');
13
      end if;
14
    else 
15
      DATA_OUT <= (others => 'Z');
16
    end if;
17
  end if;
18
end process;

Das Z verwende ich nur, um in der Simulation einen besseren Überblick zu 
haben. Eine blaue Linie ist besser zu unterscheiden als eine weitere 
Grüne Linie. Mir ist bewußt, dass es diesen Zustand in der Hardware 
nicht gibt. Entweder er wird noch durch weitere Anweisungen ersetzt, 
oder es wird dann 0 gesetzt :)

VIELEN DANK!

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


Lesenswert?

Warum dann nicht mit einer Defaultzuweisung?
Dann wird das Ganze wesentlich übersichlicher, weil alle else 
herausfallen:
1
DATA_READ: process (PClk, FIFO_prog_emty, PADD(10), PCS1, POEn, PRnW, PER_RSTn)
2
begin
3
  if rising_edge(PClk) then
4
    DATA_OUT <= (others => 'Z');
5
    if (FIFO_prog_emty = '0') then --=> wird in der Simulation ignoriert!!!
6
      if (PCS1 = '0' and POEn = '0' and PRnW = '1' and PER_RSTn = '1') then    
7
          if (PADD(10) = '1') then
8
            DATA_OUT <= DATA_OUT_FIFO;
9
          end if;
10
      end if;
11
    end if;
12
  end if;
13
end process;
Und das ist letzlich:
1
DATA_READ: process (PClk)
2
begin
3
  if rising_edge(PClk) then
4
    DATA_OUT <= (others => 'Z');
5
    if (FIFO_prog_emty = '0' and PCS1 = '0' and POEn = '0' and PRnW = '1' and PER_RSTn = '1' and PADD(10) = '1') then
6
            DATA_OUT <= DATA_OUT_FIFO;
7
    end if;
8
  end if;
9
end process;

BTW: der Prozess ist nur auf PClk sensitiv.

von Andreas B. (loopy83)


Lesenswert?

Für solche Vereinfachungen, denke ich, fehlt mir einfach noch der Blick. 
Ich denke das wird sich dann mit der Zeit ergeben. Freilich kann ich 
deinen Ausdruck genauso verstehen und nachvollziehen, aber selber darauf 
gekommen wäre ich nicht :)

DANKE...

Ich werde mal schauen, ob diese Umformulierung das Problem behebt!

von Andreas B. (loopy83)


Lesenswert?

1
FIFO_prog_emty = '0'
Diese Abfrage in der if-Anweisung wird einfach ignoriert und der 
Data_Out Zweig wird rein über das rd_en gesteuert, was aber nun noch 
testweise per constant auf '1' liegt.

Dann wird direkt nach dem Schreiben des FIFOs der Wert wieder ausgelesen 
und dadurch kann natürlich der prog_emty Wert auch nie 0 werden. Würde 
die oben genannte Abfrage aber gehen, würden erst eine definierte Anzahl 
von DByte in das Fifo geschrieben, bevor ausgelesen werden kann. Eine 
direkte Verknüpfung von rd_en und dem prog_emty ist mir auch noch nicht 
geglückt, da das Signal dann häufiger toggelt, als die Daten zu Ende 
ausgelesen werden.

Ich denke es ist noch irgendein logischer Fehler, ich muss ihn nur noch 
finden.

Ich versteh die Welt nicht mehr...

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.