Forum: FPGA, VHDL & Co. Actel Flash FPGA


von Ragdar (Gast)


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:)

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


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).

von Ragdar (Gast)


Lesenswert?

1
library IEEE;
2
use IEEE.STD_LOGIC_1164.all;
3
use ieee.NUMERIC_STD.all;
4
entity RisingEdgeFlag is
5
  port (lSignal      : in   STD_LOGIC;
6
        lClock       : in   STD_LOGIC;
7
        lResetFlag   : in   STD_LOGIC;
8
        lReset       : in   STD_LOGIC;
9
        lFlag        : out  STD_LOGIC
10
       );
11
end RisingEdgeFlag;
12
13
---------------------------------------------------------------------
14
architecture Behavioral of RisingEdgeFlag is
15
  -- signal declaration ---------------------------------------------
16
  signal lSyncSignal    : STD_LOGIC := '0';
17
18
  
19
  -- component declaration ------------------------------------------
20
  -------------------------------------------------------------------
21
 
22
  begin
23
  
24
  -- component instantiation ----------------------------------------
25
  -------------------------------------------------------------------
26
 
27
  -- Signal Synchronisieren
28
  process(lSignal, lReset, lClock)
29
  begin
30
  if(lReset = '1') then
31
    lSyncSignal  <= '0';
32
  elsif (lClock = '1' and lClock'event) then
33
    -- Synchronisieren von Signal nach Flanke Clock
34
    lSyncSignal  <= lSignal;
35
  end if;
36
  end process;
37
38
39
  process(lClock, lReset, lSignal)
40
  begin
41
  if(lReset = '1') then
42
    lFlag <= '0';
43
  elsif (lClock = '1' and lClock'event) then
44
    if(lResetFlag = '1') then
45
      -- Ruecksetzen des Flags
46
      lFlag <= '0';
47
    -- Synchronisieren zu Takt
48
    elsif (lSyncSignal = '0') and (lSignal = '1') then
49
      -- Flanke erreicht ...
50
      lFlag <= '1';
51
    end if;
52
  end if;
53
  end process;
54
55
end Behavioral;
56
57
58
59
60
------------------------------------------------------------------------
61
-- main modul-----------------------------------------------------------
62
63
64
65
66
  -- Synchronisieren des SPI Clocks zum internen Systemclock
67
  Sync1: SyncRisingEdge
68
  port map(lSignal    => lSpiClock,
69
           lClock     => lClockSys,
70
           lReset     => lReset,
71
           lSyncEdge  => lSpiClockSync);
72
73
74
  -- Synchronisieren des ChipSelect zum internen Systemclock
75
  -- Erzeugung einse Pulses mit der Periodenlänge einer Clock
76
  -- wenn fallende Flanke des ChipSelect 
77
78
  -- ChipSelect ist low active
79
  lSpiChipSelectHighAct <= not(lSpiChipSelect);
80
81
  Sync2: SyncRisingEdge
82
  port map(lSignal    => lSpiChipSelectHighAct,
83
           lClock     => lClockSys,
84
           lReset     => lReset,
85
           lSyncEdge  => lSpiChipSelectLow);
86
87
88
89
  Sync3: SyncRisingEdge
90
  port map(lSignal    => lSpiChipSelect,
91
           lClock     => lClockSys,
92
           lReset     => lReset,
93
           lSyncEdge  => lSpiChipSelectHigh);
94
95
96
  process (lReset, lSpiDataIn, lSpiChipSelectLow, lClockSys)
97
    variable iCtr : integer range 0 to 10;
98
  begin
99
  if (lReset = '1') then
100
    lvSpiDataReg    <=  (others => '0');
101
    iCtr            :=  0;
102
103
  elsif (lClockSys = '1') and (lClockSys'event) then
104
105
    -- Datenübernahme ins Sende-/Empfangsregister
106
    if (lSpiChipSelectLow = '1') then
107
      lvSpiDataReg <= x"AA";
108
      lvSpiDataReg <= lvSpiDataOut;
109
110
    elsif (lSpiClockSync = '1') then
111
      lvSpiDataReg <= lvSpiDataReg(lvSpiDataReg'high - 1 downto 0) & lSpiDataIn;
112
113
    elsif (lSpiChipSelectHigh = '1') then
114
      lvSpiDataIn <= lvSpiDataReg;
115
116
    end if;
117
118
  end if;
119
  end process;

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


Lesenswert?

Die Prozesse sind überdefiniert. Das ist an sich nicht schlimm, zeigt 
aber evtl. ein Verständnisproblem auf. Statt:
1
  process (lReset, lSpiDataIn, lSpiChipSelectLow, lClockSys)
2
    variable iCtr : integer range 0 to 10;
3
  begin
4
  if (lReset = '1') then
5
    lvSpiDataReg    <=  (others => '0');
6
    iCtr            :=  0;
7
8
  elsif (lClockSys = '1') and (lClockSys'event) then
9
  :
10
  :
Reicht:
1
  process (lReset, lClockSys)
weil alles nur von diesen beiden Signalen abhängt.


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

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

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

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


Lesenswert?

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

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

von Ragdar (Gast)


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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.all;
3
use ieee.NUMERIC_STD.all;
4
entity SyncRisingEdge is
5
  port (lSignal      : in   STD_LOGIC;
6
        lClock       : in   STD_LOGIC;
7
        lReset       : in   STD_LOGIC;
8
        lSyncEdge    : out  STD_LOGIC
9
       );
10
end SyncRisingEdge;
11
12
---------------------------------------------------------------------
13
architecture Behavioral of SyncRisingEdge is
14
  -- signal declaration ---------------------------------------------
15
  signal lEdgeArrived   : STD_LOGIC := '0';
16
  signal lPreSyncEdge   : STD_LOGIC := '0';
17
 
18
  begin
19
 
20
  -- Signal Synchronisieren
21
  process(lSignal, lReset, lPreSyncEdge)
22
  begin
23
  if(lReset = '1') then
24
    lEdgeArrived  <= '0';
25
  elsif (lPreSyncEdge = '1') then
26
  -- Rücksetzen, wenn PreSyncEdge gesetzt
27
    lEdgeArrived  <= '0';
28
  elsif (lSignal = '1' and lSignal'event) then
29
    -- nach steigender Falke setzen von ...
30
    lEdgeArrived  <= '1';
31
  end if;
32
  end process;
33
34
35
  process(lClock, lReset, lEdgeArrived)
36
  begin
37
  if(lReset = '1') then
38
    lPreSyncEdge <= '0';
39
  elsif (lClock = '1' and lClock'event) then
40
    -- Synchronisieren zu Takt
41
    if (lEdgeArrived = '1') then
42
      -- Flanke erreicht ...
43
      lPreSyncEdge <= '1';
44
    else
45
      -- bei nächster Periode von Takt rücksetzen
46
      lPreSyncEdge <= '0';
47
    end if;
48
  end if;
49
  end process;
50
51
  -- Ausgangssynchronisation
52
  lSyncEdge <= lPreSyncEdge;
53
54
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!

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


Lesenswert?

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

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

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.

von Ragdar (Gast)


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?

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


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:
1
  elsif (lClock = '1' and lClock'event) then
2
    -- Synchronisieren zu Takt
3
    if (lEdgeArrived = '1') then
4
      -- Flanke erreicht ...
5
      lPreSyncEdge <= '1';  -- <<< erste FF-Stufe nach einem asynchronen Signal
6
      :


Das hier wird durch den Kommentar auch nicht besser:
1
  -- Ausgangssynchronisation
2
  lSyncEdge <= lPreSyncEdge;
Da wird nämlich gar nicht synchronisiert, sondern das Signal ganz 
einfach geradeaus rausgegeben. Wenn wenigstens noch ein Takt drumrum 
wäre:
1
  if (lClock = '1' and lClock'event) then
2
    -- Ausgangssynchronisation
3
    lSyncEdge <= lPreSyncEdge;
4
  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 ;-)

von Ragdar (Gast)


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.

von Christian R. (supachris)


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.

von Ragdar (Gast)


Lesenswert?

Danke! Da hab ich wieder was gelernt!

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


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).

von Ragdar (Gast)


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 !

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


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

von Stefan H. (Firma: dm2sh) (stefan_helmert)


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.

von Mac (Gast)


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 :-)

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.