Forum: FPGA, VHDL & Co. Zwei Clockdomains, ein Signal.


von GS (chromosoma)


Angehängte Dateien:

Lesenswert?

Abend.

Gegeben zwei clockdomains.
Einer läuft mit 27MHZ und liefert  Pixeldaten eines Bildes.
Zweiter läuft mit 166MHZ und schreibt die Daten in SDRAM.


Jetzt habe fogendes Problem.
 Jedes mal, wenn auf Domain1 eine gültige Datei vorliegt, wird diese 
Datei in den SDRAM geschrieben (Domain2).
Wenn ich die SDRAM Adresse im Domain1 steuere, habe ich kein Problem 
damit. (Siehe Bild1)
  Will ich aber die ganze Steuerung im Domain2 realisieren, sieht das 
Bild stark verzerrt und instabil aus(Bild. 2).

Ich verstehe nicht ganz, warum das passiert, denn im Simulator  sehen 
die beide Fälle gut aus.
Danke im voraus für die Hilfe;)
Anbei  mein Code für den  Ok-Fall:
1
------------DOMAIN1-------------------
2
PROCESS  (TD_CLK27)
3
VARIABLE RED,BLUE,GREEN: STD_LOGIC_VECTOR(7 downto 0);
4
VARIABLE MUL_VAL:STD_LOGIC;
5
BEGIN
6
IF(IMGRDY='1')THEN-----RESET
7
  BT656_CAP<='0';
8
  STATE<=GETCB;
9
  ENABLE<='0';
10
        SDRAM_ADDR2<=0;
11
   ELSIF rising_edge(TD_CLK27)THEN
12
   BT656_CAP<='1';
13
   YCRCB_to_RGB(CR,CB,Y,MUL_EN,RED,GREEN,BLUE,MUL_VAL);
14
   ENABLE<=MUL_VAL;
15
16
   IF(BT656_VIDEN='1')THEN
17
     CASE STATE IS
18
    WHEN GETCB=>
19
           MUL_EN<='0';
20
           CB<=BT656_DATA;
21
           STATE<=GETY;
22
         STATE_FLAG<='1';
23
    WHEN GETCR=>
24
           MUL_EN<='0';
25
           STATE<=GETY;
26
         CR<=BT656_DATA;
27
         STATE_FLAG<='0';
28
     WHEN GETY=>
29
           MUL_EN<='1';
30
           Y<=BT656_DATA;
31
           IF(STATE_FLAG='1')THEN
32
         STATE<=GETCR;
33
         ELSE
34
         STATE<=GETCB;
35
         END IF;
36
    END CASE;
37
         IF (MUL_VAL='1')THEN----DATA VALID, Write it to SDRAM
38
                  SDRAM_ADDR2<=SDRAM_ADDR2+1;
39
      REDD<=RED;------actual Data
40
41
     END IF;
42
END IF; 
43
END IF;
44
45
END PROCESS; 
46
-----------------DOMAIN 2----------------------
47
PROCESS  (SDRAM_CLK_SHIFT)
48
BEGIN  
49
IF rising_edge(SDRAM_CLK_SHIFT) THEN
50
51
-----------------------wirte to SDRAM-------------------
52
IF (IMGRDY='0')THEN
53
      AV_RD_N<='1';
54
      AV_WR_N<='0';
55
          IF(ENABLE ='1' AND ACK='0')THEN
56
57
58
            ACK<='1';
59
60
             IF (AV_WRQ='0') THEN -----------IF SDRAM is not busy
61
               SDRAM_ADDR<=STD_LOGIC_VECTOR(to_unsigned(SDRAM_ADDR2,25));  
62
63
            AV_WRDATA(7 downto 0)<=REDD;
64
           END IF;
65
      END IF;
66
       IF(ENABLE ='0')THEN
67
        ACK<='0';
68
       END IF;
69
         IF(BT656_DONE='1')THEN-------END OF IMAGE, Image is ready
70
71
72
73
          IMGRDY<='1';
74
          SDRAM_ADDR<=(OTHERS=>'0');
75
        
76
77
        END IF;
78
END IF;
Und jetzt  für den  verzerrten Fall, Nur die SDRAM_ADDR2 Steuerung wird 
geändert
1
------------DOMAIN1-------------------
2
PROCESS  (TD_CLK27)
3
VARIABLE RED,BLUE,GREEN: STD_LOGIC_VECTOR(7 downto 0);
4
VARIABLE MUL_VAL:STD_LOGIC;
5
BEGIN
6
IF(IMGRDY='1')THEN-----RESET
7
  BT656_CAP<='0';
8
  STATE<=GETCB;
9
  ENABLE<='0';
10
11
   ELSIF rising_edge(TD_CLK27)THEN
12
   BT656_CAP<='1';
13
   YCRCB_to_RGB(CR,CB,Y,MUL_EN,RED,GREEN,BLUE,MUL_VAL);
14
   ENABLE<=MUL_VAL;
15
16
   IF(BT656_VIDEN='1')THEN
17
     CASE STATE IS
18
    WHEN GETCB=>
19
           MUL_EN<='0';
20
           CB<=BT656_DATA;
21
           STATE<=GETY;
22
         STATE_FLAG<='1';
23
    WHEN GETCR=>
24
           MUL_EN<='0';
25
           STATE<=GETY;
26
         CR<=BT656_DATA;
27
         STATE_FLAG<='0';
28
     WHEN GETY=>
29
           MUL_EN<='1';
30
           Y<=BT656_DATA;
31
           IF(STATE_FLAG='1')THEN
32
         STATE<=GETCR;
33
         ELSE
34
         STATE<=GETCB;
35
         END IF;
36
    END CASE;
37
         IF (MUL_VAL='1')THEN----DATA VALID, Write it to SDRAM
38
39
      REDD<=RED;------actual Data
40
41
     END IF;
42
END IF; 
43
END IF;
44
45
END PROCESS; 
46
-----------------DOMAIN 2----------------------
47
PROCESS  (SDRAM_CLK_SHIFT)
48
BEGIN  
49
IF rising_edge(SDRAM_CLK_SHIFT) THEN
50
51
-----------------------wirte to SDRAM-------------------
52
IF (IMGRDY='0')THEN
53
      AV_RD_N<='1';
54
      AV_WR_N<='0';
55
          IF(ENABLE ='1' AND ACK='0')THEN
56
57
                            SDRAM_ADDR2<=SDRAM_ADDR2+1;
58
            ACK<='1';
59
60
             IF (AV_WRQ='0') THEN -----------IF SDRAM is not busy
61
               SDRAM_ADDR<=STD_LOGIC_VECTOR(to_unsigned(SDRAM_ADDR2,25));  
62
63
            AV_WRDATA(7 downto 0)<=REDD;
64
           END IF;
65
      END IF;
66
       IF(ENABLE ='0')THEN
67
        ACK<='0';
68
       END IF;
69
         IF(BT656_DONE='1')THEN-------END OF IMAGE, Image is ready
70
71
72
73
          IMGRDY<='1';
74
          SDRAM_ADDR<=(OTHERS=>'0');
75
                SDRAM_ADDR2<=0;
76
77
        END IF;
78
END IF;



PS

Das Video wird als PAL übertragen, deswegen doppeltes Bild, das wird 
später deinterlaced.

: Bearbeitet durch User
von Schlumpf (Gast)


Lesenswert?

Ohne jetzt sicher sagen zu können, dass genau darin der Fehler liegt, 
aber vielleicht erklärt es das prinzipielle Problem, welches bei solchen 
Domainünbergängen passiert.

z.B. wird das Signal ENABLE in der Domain 1 erzeugt. Also synchron zu 
TD_CLK27

Mit diesem ENABLE-Signal steuerst du irgendwas in Domain 2

Im Gut-Fall übernimmst du nur Daten von einem Register in ein anderes.
Im Schlecht-Fall steuerst du mit dem ENABLE-Signal einen Zähler. Gibst 
das hochzählen also frei.

Problem 1:
Ist sichergestellt, dass das ENABLE-Signal immer nur genau für einen 
Takt der Domain2 aktiv ist? Wenn ja, ist gut, aber wenn nein.. dann kann 
sein, dein Zähler zählt auch mehrfach hintereinander, oder?

Problem 2:
Wenn die Phasenlage zwischen Domain 1 und 2 nicht starr ist, hat die 
Synthese ein Problem.
Es kann nicht ausgeschlossen werden, dass es zu Setup-Zeit verletzungen 
am Zielregister kommt. Das heißt, dass das ENABLE sich zu einem so 
blöden Zeitpunkt ändert, an dem die Register-Eingänge der Ziel-Domain 
stabil sein müssen, um Metastabilitäten zu verhindern.

Steuerst du mit dem ENABLE nur EIN einzelnes Register, kann das Problem 
noch gering sein. Wenn das Register kurz metastabil wird, fällt es bis 
zum nächsten Takt entweder in den alten Zustand zurück oder übernimmt 
doch den neuen.
Aber wenn du einen Zähler hast, und ein paar Register "sehen" beim Takt 
das ENABLE und ein paar Register nicht, dann gerät der Zähler außer Rand 
und Band..

Das ist ein generelles Problem. Wo jetzt genau in deinem Code die 
Ursache liegt, kann ich nicht sagen, aber die o.g. Stelle mit dem ENABLE 
ist auf jeden Fall eine, die Probleme machen kann.
Aber ich vermute, dass sich da noch mehr so Stellen finden lassen, wenn 
man genau hinschaut.

von GS (chromosoma)


Lesenswert?

Erstmal dankeschön für die Antwort.
 Mit dem ACK Signal  sorge ich dafür, dass Der Zähler nur einmal zählt.
1
 IF(ENABLE ='1' AND ACK='0')THEN
2
            ACK<='1';
3
             IF (AV_WRQ='0') THEN -----------IF SDRAM is not busy
4
               SDRAM_ADDR<=STD_LOGIC_VECTOR(to_unsigned(SDRAM_ADDR2,25));  
5
               AV_WRDATA(7 downto 0)<=REDD;
6
             END IF;
7
END IF;

Das 2. Problem ist wirklich echtes ein Problem. Ich habe verstanden was 
du meinst,  aber  wie  kann ich sowas  vermeiden?

von Schlumpf (Gast)


Lesenswert?

Böser Kommunist schrieb:
> Das 2. Problem ist wirklich echtes ein Problem. Ich habe verstanden was
> du meinst,  aber  wie  kann ich sowas  vermeiden?

Das kann man z.B. dadurch vermeiden, dass ein Steuersignal aus der einen 
Domain immer nur auf EIN Steuersignal in der anderen Domain wirkt. Oder 
zumindest nur auf Register wirkt, die nicht unbedingt konsistent 
zueinander sein müssen.

Also z.B.:
Du steuerst mit dem ENABLE-Signal nicht direkt alle Zählerregister an, 
sondern nur EIN Register in der Zieldomain. Du synchronisierst quasi 
erst das Steuersignal in die Zieldomain ein und das einsynchronisierte 
Signal verwendest du dann, um deinen Zähler zu steuern.
So kannst du sicherstellen, dass alle Register des Zählers immer das 
identische Steuersignal sehen.


Domain 1:           Domain 2:

ENABLE ------------> en_sync(0) ---> en_sync(1)--------> counter(0...n)

ggf kannst du dann auch bei der Einsynchronisierung gleich die Flanke 
des Steuersignals erkennen und dann nur für EINEN Takt der Domain 2 
einen enable-Impuls erzeugen. Dann kannst du dir das mit dem ACK sparen.

also so, wenn sichergestellt ist, dass die Metastabilität der Register 
deutlich kürzer als ein Takt der Zeildomain ist:

Domain 1:           Domain 2:

ENABLE ------------> en_sync(0) ---> en_sync(1)
                         en_sync = "10" --------> counter(0...n)

oder so, wenn Zweifel bestehen, ob die Metastabilität bis zur nächsten 
Flanke nicht abgeklungen ist:

Domain 1:           Domain 2:

ENABLE ------------> en_sync(0) ---> en_sync(1) ---> en_sync(2)
                             en_sync(1,2) = "10" --------> 
counter(0...n)

von GS (chromosoma)


Lesenswert?

Schlumpf du bist der Hammer. Danke!
omain 1:           Domain 2:

ENABLE ------------> en_sync(0) ---> en_sync(1)--------> counter(0...n)


hat geholfen!=)

Wieder was neues gelernt;)

von berndl (Gast)


Lesenswert?

Sehr lesenswert (und ausserdem kurz und knackig) dazu:
http://www.fpga4fun.com/CrossClockDomain.html

von Schlumpf (Gast)


Lesenswert?

Freut mich, wenn es geholfen hat. Und der Link von Berdl ist auf jeden 
Fall 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.