Forum: FPGA, VHDL & Co. FIFO läuft über


von GS (chromosoma)


Lesenswert?

Abend.
Ich habe "dual port dual clock" RAM  als FIFO zwischen den SDRAM(133MHZ) 
und VGA-Anzeige(49.5 MHZ).

---process 1, getaktet mit 133Mhz
Solange der  FIFO nicht voll und bereit  ist, werden die Daten von SDRAM 
abgerufen. Dabei  erhöhe ich FULL_Pointer um 1. Der Full_Pointer ist 
immer um 1 höher als die ADDR1.

Solange die Daten verfügbar sind werden die Daten in FIFO geschrieben, 
und die Schreibadresse (ADDR1)  wird erhöht.
Der SDRAM liefert so viel Daten wie ich abfrage(bestätigt in SignalTap), 
also darf  hier ADDR1 nicht überlaufen.
----process 2, getaktet mit 49.5 Mhz

Solange der FIFO nicht Leer ist, werden die Daten ausgegeben, sonst wird 
ein roter Pixel angezeigt

Nun hat das Bild ziemlich viele rote Pixel, die sich periodisch 
wiederholen.
Das Bild ist ziemlich stark verzerrt. Also tippe ich auf FIFO Überlauf.
Mögliche Ursachen  wären: Die Voll-Bedienung(FULL_pointer=ADDR2) wird 
nicht richtig erkannt, und  es werden mehr Daten  abgefragt, als es in 
den FIFO rein passen, so läuft die adresse1 über,die voll-Bedienung wird 
ignoriert,kurz erscheint die Empty-Bedienung (wegen ADDR1=ADDR2) und 
der FIFO wird neu überschrieben.
Leider funktioniert die Simulation an dieser Stelle  ohne Probleme.
Kann es sein dass das Problem wegen zwei Clock-Domänen erscheint?
Die ADDR1 wird  in 133Mhz-Process  gesteuert, ADDR2 in 49,5Mhz-Process.
Die Empty/Voll Bedienung wird  außerhalb des Prozesses abgefragt.

Mache  ic was falsch hier?
Hier ist der Code:
Lesen @133Mhz
1
  SDRAM_WE_N<='1'; 
2
  RAM2WE2<='0';
3
  IF(RAM2FULL='0')THEN---------fill output buffer  
4
    SDRAM_RE_N<='0';
5
    IF(SDRAM_WAIT='0' AND SDRAM_RE_N='0')THEN
6
       IF(RAM2FULL_POINTER<511)then-----move full pointer
7
       RAM2FULL_POINTER<=RAM2FULL_POINTER+1;
8
       else
9
      RAM2FULL_POINTER<=0;
10
        end if;
11
      SDRAM_ADDR<=std_logic_vector(unsigned(SDRAM_ADDR)+1);    
12
     END IF;      
13
  ELSE
14
      SDRAM_RE_N<='1';
15
   END IF;
16
17
      ---RAM2WE1<=SDRAM_RDVAL;  
18
  IF(SDRAM_RDVAL='1')then------------while data is avalable, write to buffer RAM    
19
          RAM2IN1<=SDRAM_READDATA(7 downto 0);
20
21
        IF(RAM2ADDR1<511)then
22
        RAM2ADDR1<=RAM2ADDR1+1;
23
        else
24
        RAM2ADDR1<=0;
25
        end if;
26
27
   END IF;
VGA @49.5 Mhz
1
IF( RAM2EMPTY='0')then
2
      IF(RAM2ADDR2<511)then
3
      RAM2ADDR2<=RAM2ADDR2+1;
4
      else
5
      RAM2ADDR2<=0;
6
      end if;
7
       RED<=RAM2OUT2;
8
        GREEN<=RAM2OUT2;
9
       BLUE<=RAM2OUT2;
10
    ELSIF( RAM2EMPTY='1')THEN
11
  
12
       RED<=(others=>'1');
13
      BLUE<=(others=>'0');
14
      GREEN<=(OTHERS=>'0');
15
    END IF;

Und außerhalb des Prozesses steht einfach:
RAM2FULL<='1' WHEN RAM2ADDR2=RAM2FULL_POINTER ELSE '0';
RAM2EMPTY<='1' WHEN RAM2ADDR1=RAM2ADDR2 ELSE '0';

von GS (chromosoma)


Angehängte Dateien:

Lesenswert?

Sooo
Ich habe eine ähnliche situation in SIgnalTap nachgemacht.

Zwei counter: addr1 und addr2.

Addr1 befindet sich in 133Mhz Domain,
Addr2 in 50 MHZ Domain.

Addr1 zähl nur, wenn die Werte addr1 und addr2 nicht gleich sind.
Außer dem gibt es EQ Singal, der außerhalb des Prozesses steht, und  die 
beide Werte vergleicht.
Wie man aus der Diagramm sieht, funktioniert EQ nicht immer so wie es 
sein soll, manchmal sind die Werte ungleich, aber EQ ist immer noch 1.
Manchmal zeigt  addr2 den falschen Wert an, zB: 10,11,13,12,13,14...

von Matthias (Gast)


Lesenswert?

Die Signale müssen zwischen den ClockDomains synchronisiert werden. ZB 
der Addressvergleich in ram2empty führt zu Problemen.

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Hallo,

warum machst du das Full/Empty-Handling selber? Man kann bei FIFOs ein 
programmierbares Full/Empty einstellen. Wenn deine Burstlänge beim Lesen 
vom SDRAM z.B. 16 Byte ist, denn setzt du das ProgEmpty auf FIFO-Länge - 
16 Byte. Nun kannst du solange Daten in den FIFO eintragen, wie das 
ProgEmpty aktiv ist, weil ein ganzer Burst immer rein passt. Nebenbei 
behandelt der Dual-Clock FIFO auch noch das Clock-Domain-Crossing von 
ProgEmpty.

Tom

: Bearbeitet durch User
von P. K. (pek)


Lesenswert?

=> Falls Du nicht generisch sein must:

Nimm ein entsprechendes FIFO aus der MegaWizard-Bibliothek (e.g. dcfifo) 
und alle Probleme sind gelöst...

=> Falls Du generisch bleiben must / das FIFO inferiert werden soll:

Natürlich must Du die Counter in die jeweilige andere Clockdomain 
einsynchronisieren. Das allein genügt aber nicht: Damit nicht irgend ein 
"Zwischenstand" registriert wird, solltest Du Gray-Counter einsetzen, 
(es wechselt nur jeweils ein Bit den Zustand). Ansonsten würde ein 
zeitraubendes Handshake nötig.
Da das Einsynchronisieren Latenz zur Folge hat solltest Du schauen, dass 
das Empty-Flag in der Read-Domain, das Full-Flag aber in der 
Write-Domain lokalisiert ist.

: Bearbeitet durch User
von GS (chromosoma)


Lesenswert?

Hm...wie genau muss ich Gray-Code benutzen?
Muss ich den Counter in Domain 1 in GrayCode umwandeln und so nach 
Domain 2 senden.
Soll der Vergleich  zwischen den Counter1 und Counter 2 besser auch 
getaktet sein?

von bko (Gast)


Lesenswert?


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.