Zwei Clockdomains, ein Signal.

OP #3980099
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.
Angehängte Dateien:
Gast #3981288
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.
OP #3981648
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?
Gast #3981965
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)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren