Guten Tag zusammen, so langsam verzweifle ich. Die Aufgabenstellung ist so simpel wie (inwzischen) zeitraubend! Ich habe 16 Bit die ich über eine SPI Schnittstelle auf meinen FPGA bekommen will. Inzwischen habe ich 3 Versionen SPI-Code und keiner funktioniert zuverlässig, obgleich die Simulation bei allen funktioniert. SPI1a und SPI1b unterscheiden sich nur unwesentlich, jedoch erschien mir Version a nicht besonders sauber, da ich einem Signal einen Wert zuweise und es direkt wieder zurücksetze. Darum ist Version b entstanden, die bisher am ehesten Funktioniert, jedoch nicht immer... Version 2 arbeitet mit einem "Masterclock" (50 MHz) der den SPI (500 kHz) abtastet. Simulation ist hier OK - Realität FAILED. Würde mich über eine kurze Code-Review sehr freuen und bedanke mich schonmal im Voraus!
hast du dir schonmal den realen datenstrom angeschaut ? z.B. mitm logic analyser. dann könnte man mit hilfe der ergebnisse im fpga dann rausfinden woran er sich stört. vielleicht is ja der reelle datenstrom anders als du ihn dir vorstellt.
1. In Version 2 wird SPI_Enable nicht sauber eingetaktet. Real geht es an die Eingänge von verschiedenen FFs. Nun überleg die mal, was passiert, wenn die Änderung vom SPI_Enable Eingang exakt mit dem abtastenen Takteingang stattfindet. 2. Simulation ist hier OK - Realität FAILED. was bedeutet dies konkret, was geht nicht? 3. Schau die am besten mal den RTL-View an. Gruß Volker
> In Version 2 wird SPI_Enable nicht sauber eingetaktet.
Merksatz:
Ein Signal geht durch (mindestens) 2 FFs, erst dann wird es verwendet.
Bei deinen 1er-Lösungen mußt du übrigens anschliessend noch die
Taktdomäne wechseln (also das Schieberegister einsynchronisieren), falls
das mit einem Mastertakt weiterverarbeitet werden soll.
Lösung 1a) und 1b) ist eine recht unübliche Beschreibung eines
Clock-Enables. Sieh dir mal die gängigen Lehrbücher an: findest du dort
so einen Konstrukt? Falls die Antwort "Nein" lauten sollte: warum wohl
nicht?
1 | if (Reseta = '0') then |
2 | SPI_SR(15 downto 0) <= (others => '0'); |
3 | counter <= 0; |
4 | elsif (SPI_Enable = '0') then |
5 | if rising_edge(SPI_Clock) then |
6 | :
|
Was da herauskommt ist in der Hardware wohl dem Zufall (oder eher dem Synthesizer) überlassen ... Wie sieht dein SPI_Clock real aus? Ist das ein "schönes" Signal oder hat der Überschwinger...? Probiers doch mal so (abgeleitet von 1a):
1 | signal SPI_SR : std_logic_vector(15 downto 0); |
2 | signal OUTPUT : std_logic_vector(15 downto 0); |
3 | |
4 | begin
|
5 | SchiebeReg : process(SPI_Clock) |
6 | begin
|
7 | if rising_edge(SPI_Clock) then -- steigende Flanke --> Bit einlesen |
8 | SPI_SR <= SPI_SR(14 downto 0) & SPI_Data; |
9 | end if; |
10 | end process; |
11 | |
12 | Ausgabe : process(SPI_Enable) |
13 | begin
|
14 | if rising_edge(SPI_Enable) then -- deselektieren --> Daten übernehmen |
15 | OUTPUT <= SPI_SR; |
16 | end if; |
17 | end process; |
EDIT: Für ein CPLD ist das ok, aber in einem FPGA wäre der 2. Takt schon ein Kündigungsgrund ;-)
>aber in einem FPGA wäre der 2. Takt schon ein Kündigungsgrund ;-) das ganze hängt aber auch davob ab, wie das "externe Timing" seiner SPI-Signale zueinander ist (speziell SPI_Enable zu SPI_Clock). >Wie sieht dein SPI_Clock real aus? >Ist das ein "schönes" Signal oder hat der Überschwinger...? Und die Flanke selbst muss sauber sein, also keine Treppenstufe.
> das ganze hängt aber auch davob ab, wie das "externe Timing" seiner > SPI-Signale zueinander ist (speziell SPI_Enable zu SPI_Clock). Ja, gut, dass nach den SPI_Enable (landläufig wohl eher SlaveSelect SS#) etwas Zeit vergangen sein sollte, bevor der Clock kommt, und vice versa bevor der SPI_Enable inaktiv wird, das sollte schon sichergestellt sein. Aber dafür gibt es ja Datenblätter von anderen SPI-Slaves. Da ist es hilfreich, wenn man sich sowas mal vorher anschaut. >> Ist das ein "schönes" Signal oder hat der Überschwinger...? > Und die Flanke selbst muss sauber sein, also keine Treppenstufe. Und halbwegs akzeptable Anstiegszeiten haben...und nicht verrauscht sein... Eben schön... ;-) @ daimlerfahrer SPI sind gekoppelte Schieberegister. Damnach braucht SPI keinen Zähler für die Anzahl der übertragenen Bits. Das Ende der Übertragung wird über den SlaveSelect markiert. Die letzten davor übertragenen Bits werden intern weiterverarbeitet. Wenn du 56 Takte machst, dann werden also nur die Bits 41-56 verwendet, weil die beim Deselektieren im Schieberegister stehen.
Zu aller erst bedanke ich mich mal für eure Hinweise. Hier ein Screenshot des SPI-Signals, mit diesem Signal gehe ich davon aus, dass dies nicht der Fehler ist. Die Daten werden zur fallenden Flanke gesetzt und zur steigenden übernommen. Den Zähler habe ich eingebaut um eine gewisse "Sicherheit" zu haben, dass ein kompletter Datensatz gesendet wurde. In der Realität tauchen verschiedenen "Symptome" auf. 1. Es werden 90% der Daten richtig übernommen und bei 10% werden die Daten an die zuvor eingestellte Adresse gesendet. 2. Die Zähler-Sicherung greift viel zu oft und es werden kaum Daten übernommen Problematischer für meine Anwendung sind eher falsch übernommene Datensätze als ausbleibende Daten. Soll heissen - lieber kommt mal ein Datensatz NICHT an, als dass ein falscher ankommt.
@Der Daimlerfahrer könnten ggf. die SPI-CLK Flanken unsauber sein? Die steigende Flanke erkenne ich mindestens so:
1 | if SPI_Clock_old2 = '0' and SPI_Clock_old1 = '1' and SPI_Clock = '1' then |
und muss natürlich SPI_Clock 2 mal mit dem Systemtakt syncronisiert haben.
meine ich dies nur, aber ist auf der 3. und 6. steigenden Taktflanke nicht eine Stufe vorhanden? Kann zwar an der Auflösung des Bildes liegen, aber mach mal folgendes: Code mal in VHDL nen kleinen Counter, der einfach die SPI-Taktflanken zählt und schau dann mal, ob das Ergebnis mit den tatsächlich gesendeten übereinstimmt.
>2. Die Zähler-Sicherung greift viel zu oft und es werden kaum Daten >übernommen Dann gib halt mal das Zählerergebnis im Fehlerfall aus, vieleicht ist man dann ein Stück schlauer.
Also nachdem ich den Zählerstand mal ausgegeben habe musste ich feststellen, dass mein SPI richtig detektiert wurde, obgleich eine fehlerhafte Ausgabe erfolgte. Also SPI steht richtig, aber Ausgang steht falsch! Dies brachte mich auf eine andere Fehlerursache: Meine kombinatorische Logik scheint teilweise zu lang zu brauchen. Demnach werden schon Werte an die Ausgänge übergeben, obgleich die "Weichenstellung" durch meine CASE Struktur noch nicht durchlaufen ist. Nach dem heruntertakten des Clocks an dieser Stelle treten bisher keine Fehler mehr auf. Ich war der Meinung im ISE gab es einer Stelle an der einem die maximal Mögliche Arbeitsfrequenz eines Design vorgegeben wird, finde es aber nicht mehr - weiss einer wo das steht? Danke und Grüße!
Dein Stichwort ist: Timing-Constraints Processes - User Constraints - Create Timing Constraints Im Tab Global im Constraints Editor dann die Zykluszeit für den Takt eingeben. Daraufhin findet sich in der UCF-Datei mit einem Eintrag wie z.B. für das Signal clk mit 100MHz: NET "clk" TNM_NET = "clk"; TIMESPEC "TS_clk" = PERIOD "clk" 10 ns HIGH 50 %; Das kann auch manuell in der UCF-Datei eingegeben werden. Aber einen ersten Tip gibt schon die Synthese mit der Angabe der maximalen Taktfrequenz ab.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.