Forum: FPGA, VHDL & Co. 16bit -> 8bit Wandlung mit Taktverdopplung


von Marcus W. (Gast)


Lesenswert?

Hallo,

ich habe mal wieder ein kleines Problemchen.

Vorgeschichte:
Ich habe ein Videosignal (ITU.656) mit 27 MHz Pixeltakt und 8bit 
Datenbreite.
Es werden hierbei Luminanz- und Chrominanzdaten alternierend geschickt. 
Ich selbst arbeite jedoch intern nur mit dem Luminanzanteil 
(schwarz-weiß) und daher mit 13,5 MHz Pixeltakt.

Problem:
Mein verarbeiteter Luminanzanteil kommt mit 13,5 MHz aus meiner 
Verarbeitungspipeline und soll nun an den Videoencoder mit 27 MHz 
übergeben werden. Hierfür ist es notwendig, dass der Chrominanzanteil 
"blanked" übertragen wird.
Einfachste Lösung wäre wahrscheinlich ein asynchrones FIFO, dass mir die 
16bit->8bit Wandlung (8 bit Luminanz und 8 bit Chrominanz "blanked") und 
den Taktübergang (13,5 MHz -> 27 MHz) abnimmt. Diese Lösung möchte ich 
aber vermeiden, da mir der Blockram langsam ausgeht.

Gibt es eine Lösung für mein Problem, die ohne Blockram auskommt?

Bin für jeden Tipp dankbar

Gruß Marcus

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


Lesenswert?

> Gibt es eine Lösung für mein Problem, die ohne Blockram auskommt?
Distributed Ram   ;-)

Sind die beiden Takte synchron zueinander? Wird ein Takt aus dem anderen 
gewonnen? Falls ja: warum dann für diese Wandlung überhaupt ein Fifo? Da 
würde offenbar ein einfacher MUX ausreichen...

von Marcus W. (Gast)


Lesenswert?

Hallo Lothar,

nochmal kurz mein Vorhaben:
Daten kommen mit 13,5 MHz und 16bit breit an und müssen mit 27 MHz und 
8bit breit wieder raus.

Den 27 MHz Takt erzeuge ich per DCM aus dem 13,5 MHz Takt.

Die Distributed RAM FIFOs, die der Xilinx Coregen erzeugen kann 
akzeptieren leider keine unterschiedlichen Eingangs/Ausgangsbreiten.

> Da würde offenbar ein einfacher MUX ausreichen...
Stimmt, theoretisch wäre es ein einfacher MUX (bzw. eigentlich eine Art 
SERDES), aber ich weiß nicht wie ich das realisieren soll.
(Das FIFO ist mir nur als schneller Workaround eingefallen)

Wenn ich die 16bit mit dem 13,5 MHz Takt aktualisier und dann mit 27 MHz 
je high- und lownibble übernehme, wie stelle ich sicher dass das 16bit 
Signal schon stabil anliegt wenn die nächste steigende 27 MHz Flanke 
kommt (zeitgleich zur fallenden 13,5 MHz Flanke)?
Oder mach ich mir hier zu viele Gedanken und die Xilinx-Tools erkennen 
was ich vorhab?

Gruß

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


Lesenswert?

> Oder mach ich mir hier zu viele Gedanken und die Xilinx-Tools erkennen
> was ich vorhab?
Wenn die Takte über einen DCM zusammenhängen und du die entsprechenden 
Constraints gesetzt hast, tun sie das.

von Christian R. (supachris)


Lesenswert?

Das geht dann wirklich über einen einfachen Mux. Die Phasenbeziehung 
zwischen Eingangs- und Ausgangstakt des DCM ist ja fest (sofern du kein 
PhaseShift machst) und da kannst du das ganz einfach umschalten. Ich 
würde aber den Takt außerdem noch vervierfachen (CLKFX) und damit wieder 
ein FlipFlip ansteuern, dessen Ausgang den Muxer schaltet. ISE mag es 
nicht, wenn der Takt für Kombinatorik verwendet wird, weil der Router 
dann keine dedizierten CLock Leitungen benutzen kann. Den doppelten Takt 
für das weitere System bekommst du aus dem CLK2X des DCM dann...

Nutzt du direkt den 2-fachen Takt zum Muxen bekommst du das:

LIT:176 - Clock buffer is designated to drive clock loads. BUFG symbol 
"Clock/BUFG_inst" (output signal=BusCLK2) has a mix of clock and 
non-clock loads. The non-clock loads are: ...

Und das

Route:455 - CLK Net:BusCLK2 may have excessive skew because
   0 CLK pins and 2 NON_CLK pins failed to route using a CLK template.

von Marcus W. (Gast)


Lesenswert?

Hi,

hier mein erster Versuch:
1
reg: process(CLK_0)
2
begin
3
   if rising_edge(CLK_0) then
4
      mux   <= DI_16b;
5
   end if;
6
end process;
7
8
mux: process(CLK_2X)
9
begin
10
   if rising_edge(CLK_2X) then
11
      if nibble = '0' then
12
         DO_8b    <= mux( 7 downto 0);
13
      else
14
         DO_8b    <= mux(15 downto 8);
15
      end if;
16
      nibble   <= not(nibble);
17
   end if;
18
end process;

Problematisch ist hier allerdings, dass Beziehung vom nibble zum CLK_0 
nicht sichergestellt ist. Wie kann ich sicherstellen, dass während CLK_0 
= '1' das untere nibble rausgeht und während CLK_0 = '0' das obere?

> Ich würde aber den Takt außerdem noch vervierfachen (CLKFX) und damit
> wieder ein FlipFlip ansteuern, dessen Ausgang den Muxer schaltet.
Hab mir das mal aufgezeichnet, aber verstehe nicht, was ich mit dem 
vierfachen Takt schalten soll. Ich glaub ich steh grad etwas auf dem 
Schlauch :)

von Christian R. (supachris)


Lesenswert?

Achso, 4-facher Takt ist nicht nötig, da hab ich mich wohl vertan (Das 
kam aus einem Design bei uns hier....sorry). So wie du es jetzt hast, 
sollte es doch gehen? Oder nicht? Der 2-fache Takt ist durch den DCM in 
Phase mit dem CLK_0. Was sagt denn der Simulator dazu?

von Marcus W. (Gast)


Lesenswert?

> wie du es jetzt hast, sollte es doch gehen?
Es geht leider nur gelegentlich.

Die Takte sind zwar in Phase, aber es gibt da noch eine Fehlerquelle:
Das Design muss nach der steigenden Flanke der CLK_0 zuerst das untere 
nibble rausschieben und dannach das obere. Das ist derzeit nicht 
sichergestellt, da der Wert von "nibble" bei der steigenden CLK_0 Flanke 
entweder 1 oder 0 sein kann. Das hängt wahrscheinlich vom Start der DCM 
ab, am Anfang können da ja noch krumme Takte auftreten.

Der Simulator sagt zu dem Fall nchts, denn die DCM ist ja beim Start 
etwas vom Zufall beherrscht.

von Marcus W. (Gast)


Lesenswert?

Soo, hab eine Lösung gefunden, die anscheinend auch funktioniert :)
1
   reg: process(CLK_0)
2
   begin
3
      if rising_edge(CLK_0) then
4
         sv_mux   <= DI_16b;
5
         sl_tog   <= not(sl_tog);
6
      end if;
7
   end process;
8
9
   mux: process(CLK_2X)
10
   begin
11
      if rising_edge(CLK_2X) then
12
         if(sl_nibble = '1') then
13
            DO_8b    <= sv_mux( 7 downto 0);
14
         else
15
            DO_8b    <= sv_mux(15 downto 8);
16
         end if;
17
         sl_tog_p    <= sl_tog;
18
         if(sl_tog /= sl_tog_p) then
19
            sl_nibble   <= '1';
20
         else
21
            sl_nibble   <= '0';
22
         end if;
23
      end if;
24
   end process;

Am Schalten von sl_tog kann ich die Flankenbeziehung zwischen den beiden 
Takten zurückgewinnen und so den MUX richtig synchronisieren.

Nur noch eine Frage: Brauche ich um dieses Modul abzusichern noch eine 
Timing Constraint? Muss ich ISE mitteilen, dass sl_tog (durch CLK_0 
geschaltet) bis zur nächsten steigenden Flanke von CKL_2X geschalten 
haben muss?
Wenn ja, wie mach ich das? ;)

von Christian R. (supachris)


Lesenswert?

Naja, die Quick´n´Dirty Lösung ginge ja auch noch:
1
...
2
if CLK_0 = '1' then DO_8b <= mux( 7 downto 0);
3
else DO_8b <= mux(15 downto 0);
4
...

Allerdings gibts dann diese Warnungen. Bei 27Mhz sollte es aber keine 
Timing-Probleme am Ende geben. Das beste wäre, wenn man ein DDR Register 
intern verwenden könnte....aber das geht ja schlecht, weil die direkt 
auf den IOB sitzen.

von Andreas (Gast)


Lesenswert?

Hallo Markus,

Du hast hier ja schon eine menge Möglichkeiten aufgezeigt bekommen, wie 
Du die 13,5MHz wieder aus 27MHz bekommst und die Daten dazu muxen 
kannst.

Was mir bei der ganzen Diskussion fehlt ist die Frage, warum Du aus 
deinen 27MHz erst 13,5MHz machst, wenn Du am Schluss doch wieder 27MHz 
benötigst...

Du hast jetzt nicht geschrieben welche Targettechnologie Du verwendest, 
aber es sollte eigentlich kein Problem darstellen, die Datenverarbeitung 
intern mit 27MHz laufen zu lassen.

Im Bedarfsfall hast Du auch die Möglichkeit bei den getakteten Teilen 
über den Clockenable das Ding sozusagen auf 13,5 Mhz runterzufahren und 
dies auch dem Synthesetool mitzugeben ( Multicycle Constraints ).
was meist nicht mitspielt, sind Xilinx Corecomponenten...

Aber bevor ich mir Gedanken mache meinen Takt erst zu halbieren und dann 
wieder zu verdoppeln...

Gruß

Andreas

von Marcus W. (Gast)


Lesenswert?

Hallo Andreas,

also das ganze war eigentlich mal so geplant:
Die Daten sollten vom Decoder über einen 16bit Bus mit 13,5 MHz kommen, 
durch einen Verarbeitungsblock laufen und anschließend über einen 16bit 
Bus mit 13,5 MHz zum Encoder laufen.
Der neue Encoder kann jetzt allerdings nur mit einem 8bit Datenbus, mit 
27 MHz umgehen. Um möglichst wenig am Design zu ändern dacht ich mir, 
ein asymmetrisches asynchrones FIFO löst das Problem schnell und 
einfach, dann hab ich aber bemerkt, dass der BRAM schon am Ende ist. 
Daher nun die Sache mit dem MUX.

Es kommt also derzeit vom Decoder Daten und Takt mit 13,5 MHz rein. 
Intern wird dann per DCM der 27 MHz Takt für den Ausgang generiert.
Würde ich jetzt den Eingang aber mit der "clock enable" Methode abtasten 
wollen, so müsste ich auch hier die Flankenbeziehung zwischen dem 13,5 
MHz und dem 27 MHz Takt wissen (ich darf ja nur bei 13,5 MHz rising_edge 
abtasten). Ich hätte also das Problem nur vom Ausgang zum Eingang 
verlagert.

> Aber bevor ich mir Gedanken mache meinen Takt erst zu halbieren und dann
> wieder zu verdoppeln..
Ich hab mich im ersten Post leider etwas missverständlich ausgedrückt
> Daten kommen mit 13,5 MHz und 16bit breit an und müssen mit 27 MHz und
> 8bit breit wieder raus.

Danke für eure Mithilfe, mit meinem geposteten Schnipsel funkionierts 
jetzt so wie es soll (ohne Warnungen ;).

Gruß Marcus

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.