www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Actel Flash FPGA


Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo liebe Community,

ich bin zur Zeit Praktikant in einem Unternehmen und lerne das 
"Arbeiten" :) Bin in der Entwicklungsabteilung und krieg seid paar 
Wochen ein Problem von meinem Kollegen mit, dass sich wohl nicht lösen 
lässt.

Es handelt sich um einen Flash FPGA der Firma Actel. Die 
Datenverarbeitung läuft wohl seriell, wozu man ein Schieberegister 
braucht. Die Vorgabe ist ein 192 Bit Schieberegister zu bauen.

Ein 8 Bit Schieberegister arbeitet wohl einwandfrei, aber erweitert er 
es auf 32 oder 192 Bit, so gibt es extreme Bitfehler. In der Simulation 
klappt aber alles.

Ich selbst hab leider noch nich mit VHDL oder FPGA gearbeitet, aber ich 
würd dem Kollegen helfen und eventl. Lösungsmöglichkeiten vorschlagen, 
die natürlich nur durch eure Hilfe möglich wären:)

Der Kollege vermutet, dass es zu internen Laufzeitproblemen kommt. Daher 
hat er die Taktfrequenz von 20 bis 2 Mhz durchgespielt. Aber überall das 
gleiche.

Mich würd es freuen, wenn ihr eventl. schon solche Erfahrung gehabt habt 
und mir / ihm dabei weiterhelfen könntet.

Danke schön:)

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Ein 8 Bit Schieberegister arbeitet wohl einwandfrei, aber erweitert er
> es auf 32 oder 192 Bit, so gibt es extreme Bitfehler. In der Simulation
> klappt aber alles.
Wenn die Simulation ok ist, liegen solche Fehler meistens am Übergang 
zwischen Taktdomänen oder an irgendwelchen asynchronen kombinatorischen 
Resets.
Wie ist das Schieberegister getaktet?
Hat das Schieberegister einen asynchronen Set/Reset?
Wie werden die Daten einsynchronisiert?

Kannst du Code zu dem Problem posten?

> Taktfrequenz von 20 bis 2 Mhz durchgespielt.
Das packt jedes Schieberegister in jedem FPGA.
So langsame FPGAs gibts gar nicht (mehr).

Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;
entity RisingEdgeFlag is
  port (lSignal      : in   STD_LOGIC;
        lClock       : in   STD_LOGIC;
        lResetFlag   : in   STD_LOGIC;
        lReset       : in   STD_LOGIC;
        lFlag        : out  STD_LOGIC
       );
end RisingEdgeFlag;

---------------------------------------------------------------------
architecture Behavioral of RisingEdgeFlag is
  -- signal declaration ---------------------------------------------
  signal lSyncSignal    : STD_LOGIC := '0';

  
  -- component declaration ------------------------------------------
  -------------------------------------------------------------------
 
  begin
  
  -- component instantiation ----------------------------------------
  -------------------------------------------------------------------
 
  -- Signal Synchronisieren
  process(lSignal, lReset, lClock)
  begin
  if(lReset = '1') then
    lSyncSignal  <= '0';
  elsif (lClock = '1' and lClock'event) then
    -- Synchronisieren von Signal nach Flanke Clock
    lSyncSignal  <= lSignal;
  end if;
  end process;


  process(lClock, lReset, lSignal)
  begin
  if(lReset = '1') then
    lFlag <= '0';
  elsif (lClock = '1' and lClock'event) then
    if(lResetFlag = '1') then
      -- Ruecksetzen des Flags
      lFlag <= '0';
    -- Synchronisieren zu Takt
    elsif (lSyncSignal = '0') and (lSignal = '1') then
      -- Flanke erreicht ...
      lFlag <= '1';
    end if;
  end if;
  end process;

end Behavioral;




------------------------------------------------------------------------
-- main modul-----------------------------------------------------------




  -- Synchronisieren des SPI Clocks zum internen Systemclock
  Sync1: SyncRisingEdge
  port map(lSignal    => lSpiClock,
           lClock     => lClockSys,
           lReset     => lReset,
           lSyncEdge  => lSpiClockSync);


  -- Synchronisieren des ChipSelect zum internen Systemclock
  -- Erzeugung einse Pulses mit der Periodenlänge einer Clock
  -- wenn fallende Flanke des ChipSelect 

  -- ChipSelect ist low active
  lSpiChipSelectHighAct <= not(lSpiChipSelect);

  Sync2: SyncRisingEdge
  port map(lSignal    => lSpiChipSelectHighAct,
           lClock     => lClockSys,
           lReset     => lReset,
           lSyncEdge  => lSpiChipSelectLow);



  Sync3: SyncRisingEdge
  port map(lSignal    => lSpiChipSelect,
           lClock     => lClockSys,
           lReset     => lReset,
           lSyncEdge  => lSpiChipSelectHigh);


  process (lReset, lSpiDataIn, lSpiChipSelectLow, lClockSys)
    variable iCtr : integer range 0 to 10;
  begin
  if (lReset = '1') then
    lvSpiDataReg    <=  (others => '0');
    iCtr            :=  0;

  elsif (lClockSys = '1') and (lClockSys'event) then

    -- Datenübernahme ins Sende-/Empfangsregister
    if (lSpiChipSelectLow = '1') then
      lvSpiDataReg <= x"AA";
      lvSpiDataReg <= lvSpiDataOut;

    elsif (lSpiClockSync = '1') then
      lvSpiDataReg <= lvSpiDataReg(lvSpiDataReg'high - 1 downto 0) & lSpiDataIn;

    elsif (lSpiChipSelectHigh = '1') then
      lvSpiDataIn <= lvSpiDataReg;

    end if;

  end if;
  end process;


Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Prozesse sind überdefiniert. Das ist an sich nicht schlimm, zeigt 
aber evtl. ein Verständnisproblem auf. Statt:
  process (lReset, lSpiDataIn, lSpiChipSelectLow, lClockSys)
    variable iCtr : integer range 0 to 10;
  begin
  if (lReset = '1') then
    lvSpiDataReg    <=  (others => '0');
    iCtr            :=  0;

  elsif (lClockSys = '1') and (lClockSys'event) then
  :
  :
Reicht:
  process (lReset, lClockSys)
weil alles nur von diesen beiden Signalen abhängt.


Das Einsynchronisieren über nur 1 FF ist zu wenig:
  -- Signal Synchronisieren
  process(lSignal, lReset, lClock)
  begin
  if(lReset = '1') then
    lSyncSignal  <= '0';
  elsif (lClock = '1' and lClock'event) then
    -- Synchronisieren von Signal nach Flanke Clock
    lSyncSignal  <= lSignal; ---   <<<< lSignal ist asynchron???
  end if;
  end process;

Wenn ich dann davon ausgehe, dass lSignal noch asynchron ist, geht 
sowas
    -- Synchronisieren zu Takt
    elsif (lSyncSignal = '0') and (lSignal = '1') then   ---   <<<< lSignal ist asynchron???
sicher in die Hose :-o

BTW:
warum beginnen eigentlich alle Signalnamen mit l...

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die entity
>> RisingEdgeFlag
wird übrigens gar nicht verwendet, sondern eine Komponente namens
>> SyncRisingEdge

Aber ich vermute, da gehts so ähnlich zu...  :-/

Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Den Code habe ich mehrmals abgeändert, deshalb überdefinierter Prozess. 
In der Endversion wird er sauber!

Danke, ich dabe da das flasche Modul hochgeladen, aber es ist ähnlich, 
sogar der Name ...
hier das Richtige:
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.NUMERIC_STD.all;
entity SyncRisingEdge is
  port (lSignal      : in   STD_LOGIC;
        lClock       : in   STD_LOGIC;
        lReset       : in   STD_LOGIC;
        lSyncEdge    : out  STD_LOGIC
       );
end SyncRisingEdge;

---------------------------------------------------------------------
architecture Behavioral of SyncRisingEdge is
  -- signal declaration ---------------------------------------------
  signal lEdgeArrived   : STD_LOGIC := '0';
  signal lPreSyncEdge   : STD_LOGIC := '0';
 
  begin
 
  -- Signal Synchronisieren
  process(lSignal, lReset, lPreSyncEdge)
  begin
  if(lReset = '1') then
    lEdgeArrived  <= '0';
  elsif (lPreSyncEdge = '1') then
  -- Rücksetzen, wenn PreSyncEdge gesetzt
    lEdgeArrived  <= '0';
  elsif (lSignal = '1' and lSignal'event) then
    -- nach steigender Falke setzen von ...
    lEdgeArrived  <= '1';
  end if;
  end process;


  process(lClock, lReset, lEdgeArrived)
  begin
  if(lReset = '1') then
    lPreSyncEdge <= '0';
  elsif (lClock = '1' and lClock'event) then
    -- Synchronisieren zu Takt
    if (lEdgeArrived = '1') then
      -- Flanke erreicht ...
      lPreSyncEdge <= '1';
    else
      -- bei nächster Periode von Takt rücksetzen
      lPreSyncEdge <= '0';
    end if;
  end if;
  end process;

  -- Ausgangssynchronisation
  lSyncEdge <= lPreSyncEdge;

end Behavioral;


Zu l: Ich für alle logic ein "l" vorangestellt, "i" für integer, "lv" 
für logic-vector. Hat sich für mich als sinnvoll erwiesen.

Danke!

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das:
  if(lReset = '1') then
    lEdgeArrived  <= '0';
  elsif (lPreSyncEdge = '1') then
  -- Rücksetzen, wenn PreSyncEdge gesetzt
    lEdgeArrived  <= '0';
  elsif (lSignal = '1' and lSignal'event) then
  :
könnte auch so geschrieben werden:
  if(lReset = '1' or lPreSyncEdge = '1') then
  -- Rücksetzen, wenn PreSyncEdge gesetzt
    lEdgeArrived  <= '0';
  elsif (lSignal = '1' and lSignal'event) then
  :
Und jetzt sieht man es klar: Kombinatorik im asynchronen Reset.
Das ist "No Good Design Practice"  :-/

Sehr zu Denken gibt mir diese Zeile:
  :
  elsif (lSignal = '1' and lSignal'event) then
  :

Da drängt sich noch wesentlich mehr die Frage auf:
Ist lSignal ein Eingangssignal (FPGA-Pin)?
Falls ja: lEdgeArrived ist nach wie vor asynchron zum lClock
Da hilft die ganze Zwischenpufferei nichts, das ist nur Sand in die 
Augen gestreut.

Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sehe ich nicht so.
lSignal ist ein Eingangssignal des FPGA's.
lEdgeArrived ist auch noch asynchron zu lClock. Sinn ist, auch schnelle 
Pulse, die bei nächster Flanke bereits abgefallen sein könnten, nicht zu 
verlieren. Aber das Ausgangssignal des Moduls lPreSyncEdge ist synchron 
zum Takt und nach einer Flanke für eine Periode des Taktsignals high. 
Dieses synchronisierte Signal wird dann weiterverwendet. Ist fuer die 
jetzige Anwendung etwas uebertrieben, sollte aber doch problemlos 
arbeiten, oder?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Aber das Ausgangssignal des Moduls lPreSyncEdge ist synchron
> zum Takt und nach einer Flanke für eine Periode des Taktsignals high.
Falsch. Ich zitiere mich selber:
Um auf der sicheren Seite zu sein brauchst du 2 FF Stufen.

Das hier ist nur eine davon:
  elsif (lClock = '1' and lClock'event) then
    -- Synchronisieren zu Takt
    if (lEdgeArrived = '1') then
      -- Flanke erreicht ...
      lPreSyncEdge <= '1';  -- <<< erste FF-Stufe nach einem asynchronen Signal
      :


Das hier wird durch den Kommentar auch nicht besser:
  -- Ausgangssynchronisation
  lSyncEdge <= lPreSyncEdge;
Da wird nämlich gar nicht synchronisiert, sondern das Signal ganz 
einfach geradeaus rausgegeben. Wenn wenigstens noch ein Takt drumrum 
wäre:
  if (lClock = '1' and lClock'event) then
    -- Ausgangssynchronisation
    lSyncEdge <= lPreSyncEdge;
  end if;
Das ist jetzt die zweite FF Stufe. Ab hier bist du garantiert synchron.


> Das sehe ich nicht so.
Ich habe diesen Fehler auch schon gemacht, glaubs mir ;-)

Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube ich brauche jetzt Nachhilfe. Wieso sind denn für eine 
Dateneingangssynchronisation bei FPGA zwei FF notwendig???? Da verliere 
ich ja einen Taktzyklus! Das ist nicht immer toll.

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ragdar wrote:
> Ich glaube ich brauche jetzt Nachhilfe. Wieso sind denn für eine
> Dateneingangssynchronisation bei FPGA zwei FF notwendig???? Da verliere
> ich ja einen Taktzyklus! Das ist nicht immer toll.

Verlieren wirst du nix, bekommst nur einen Takt mehr Latenz rein. 
Wichtig ist das, weil sonst evtl. die Setup-Zeit des FFs verletzt wird, 
das FF nicht gesetzt werden kann, und bei der nächsten Flanke ist das 
Eingangssignal schon wieder weg, weil da gerade so die Setup-Zeit 
eingehalten wurde. Also hast du einen ganzen Puls verloren. Ich hab das 
auch schon oft vergessen, die Effekte sind lustig und äußerst schwer zu 
finden, weil´s eben fast immer klappt.

Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke! Da hab ich wieder was gelernt!

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie schnell ist denn dein lClockSys und dein lSpiClockSync.

Ich glaube, du (bzw. dein Kollege ;-) könntest gut ohne diese 
vertrickste Flankenmerkerei auskommen. So ein asynchrones Merker-FF 
brauchst du nämlich erst, wenn der Eingangsimpuls kürzer ist (bzw. sein 
kann) als der FPGA-Takt. Im Normalfall reicht Einsynchronisieren über 
ein 2-Bit Schieberegister locker aus (3-Bit SR, falls eine 
Flankenerkennung nötig wäre).

Autor: Ragdar (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, das ist richtig. Die Clock lSpiClockSync ist ca. 1MHz und die 
lClockSys ist >= 10MHz. Für diese Anwendung brauche ich die schnelle 
Flankenerkennung nicht. Ich habe einfach das fertige Modul aus meiner 
Bibliothek genommen mit der festen Überzeugung es sei ok. Aber das werde 
ich noch umschreiben. Für mich war wichtig, wo ich ansetzen muß. Die 
Problematik mit dem Einsynchronisieren war mir bisher noch nicht ganz 
klar.

Danke fuer die Unterstutzung !

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Problematik mit dem Einsynchronisieren war mir bisher
> noch nicht ganz klar.
Das Thema wurde hier im Forum schon ein paar mal diskutiert.
Stichworte: Eintakten, Metastabilität, einsynchronisieren, 
Synchronisierungs-Flipflops...

Hier ist mein Bookmark zum Thema:
http://www.lothar-miller.de/s9y/categories/5-Entprellung

Autor: Stefan Helmert (Firma: dm2sh) (stefan_helmert)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich hatte mal die Fehlermeldung: "Clockscew larger than datadelay". 
Das heißt die Daten überholen den Takt, da er nicht an allen FF 
zeitgleich ankommt und auch nicht beim letzten FF zuerst, sondern beim 
ersten zuerst (wo auch die Daten reingehen). Das bringt folgendes 
Problem: Bit liegt am ersten FF, erstes FF kriegt Takt, übernimmt Bit 
und gibt es aus, jetzt wandert der Taktimpuls zum nächsten FF, das 
übernimmt nun nicht den alten Zustand des ersten, wie es sollte, sondern 
den neuen - und schwups rutscht das Bit von Anfang bis Ende mit einem 
Mal durch. Abhilfe lässt sich ganz einfach schaffen: Man nimmt doppelt 
so viele FF und taktet jedes zweite mit dem inversen Takt.

Autor: Mac (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Abhilfe lässt sich ganz einfach schaffen: Man nimmt doppelt
so viele FF und taktet jedes zweite mit dem inversen Takt.

= Master Slave Flip Flop :-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.