www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Bitte Hilfe beim SPI-Code *verzweifel*


Autor: Der Daimlerfahrer (daimlerfahrer)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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!

Autor: Nephilim (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Volker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

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

Bewertung
0 lesenswert
nicht lesenswert
> 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?
   if (Reseta = '0') then
      SPI_SR(15 downto 0) <= (others => '0');
      counter <= 0;
   elsif (SPI_Enable = '0') then
      if rising_edge(SPI_Clock) then
        :
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):
signal SPI_SR : std_logic_vector(15 downto 0);
signal OUTPUT : std_logic_vector(15 downto 0);

begin
SchiebeReg : process(SPI_Clock)
begin
  if rising_edge(SPI_Clock) then -- steigende Flanke --> Bit einlesen
      SPI_SR <= SPI_SR(14 downto 0) & SPI_Data;
  end if;
end process;

Ausgabe : process(SPI_Enable)
begin
   if rising_edge(SPI_Enable) then -- deselektieren --> Daten übernehmen
      OUTPUT <= SPI_SR;
   end if;
end process;

EDIT:
Für ein CPLD ist das ok,
aber in einem FPGA wäre der 2. Takt schon ein Kündigungsgrund ;-)

Autor: Volker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

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

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Autor: Der Daimlerfahrer (daimlerfahrer)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Der Daimlerfahrer
könnten ggf. die SPI-CLK Flanken unsauber sein?
Die steigende Flanke erkenne ich mindestens so:
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.

Autor: Volker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Volker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>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.

Autor: Der Daimlerfahrer (daimlerfahrer)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!

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

Bewertung
0 lesenswert
nicht lesenswert
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.

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.