Forum: FPGA, VHDL & Co. FPGA als SPI Slave


von Tobias B. (tobiasz80)


Lesenswert?

Hallo,

ich implementiere in meinem FPGA (Digilent CMOD7 mit einem Artix7 35) 
eine Hardware, die ich als ein SPI Slave ansteuern will. Dazu benutze 
ich dieses Modul 
https://github.com/nandland/spi-slave/blob/master/Verilog/source/SPI_Slave.v
Als Master benutze ich ein Nucleo Board mit einem STM32L552. Mein 
Problem ist, das ich zwischen FPGA und MCU keine zuverlässige Verbindung 
aufbauen kann. Ständig passieren Übertragungsfehler (nach ~100kB an 
Daten). Bei Debug Versuchen haben ich mir die Clock von dem SPI Slave im 
always Block ausgeben lassen, mit diesem Testcode:
1
  always @(posedge i_SPI_Clk or posedge i_SPI_CS_n)
2
  begin
3
    if (i_SPI_CS_n)
4
    begin
5
      o_SPI_DBG <= 0;
6
    end
7
    else
8
    begin
9
      o_SPI_DBG <= ~o_SPI_DBG;
10
    end
11
  end
und dabei festgestellt, das manchmal auch zur fallenden Flanke von 
i_SPI_Clk getacktet wird. Gemessen habe ich alles über einen Logic 
Analyzer. Das ist nicht immer der Auslöser von Übertragungsfehlern, aber 
sehr oft.
Dabei ist auch kurrios: SPI Frequenzen von unter 1MHz scheinen 
problemlos zu funktionieren, dadrüber bekomme ich ziemlich sicher 
Übertragungsfehler. Auch Kurios: Mit einem RPi Pico funktioniert es 
problemlos, auch bei Frequenzen um die 30MHz.
Die SPI Verbindung ist über Jumper Wires auf einem Breadboard 
ausgeführt. Kabellängen sind ca 20cm.
Der i_SPI_Clk benutzt einen clock eingang im FPGA.

Ich muss ehrlich sagen, ich bin gerade ziemlich Ratlos was hier schief 
läuft und hoffe, hier ein paar Ideen zu bekommen, was ich ausprobieren 
könnte. Leider habe ich kein Oszi um mir die Clockleitung genau 
anzuschauen. Ich kann sie nur mit 50MHz mit dem Logic Analyzer 
absamplen. Das reicht sicherlich um eine Idee von dem Signal zu 
bekommen, aber reicht wohl bei weitem nicht für eine Analyse.
Ein weiterer Versuch war ein Serienwiderstand in die Clockleitung rein 
zu setzen. Das hat ein wenig geholfen, habe werte von 22-39Ohm 
ausprobiert, aber der große Schuss wars jetzt nicht. Bei den Versuchen 
habe ich den Widerstand direkt ins Nucleoboard gesteckt und bin dann 
über ein Jumperwire zum FPGA.

So, nun bitte ich um Hilfe, was könnte hier schief laufen? Mache ich 
hier was grundsätzlich falsch? Wie sieht es z.B. aus, das der SPI Slave 
das Clock Signal vom SPI als Clock benutzt? Wäre es besser den SPI 
direkt mit dem FPGA Clock zu samplen?

Vielen Dank
Tobias

von Jens W. (jensw)


Lesenswert?

Hallo,

deine Infos sind noch ein bisschen dürftig für eine Vermutung, aber ich 
versuche es mal.
Wie hoch ist denn dein Clock für das FPGA? Und wie hoch ist dein 
angestrebter SPI clock?

Welchen Mode hast du bei der SPI gewählt? Da gibt es ja vier 
verschiedene, je nachdem wie und wo geshiftet und gesampled werden soll.
Und ist das auch der gleiche Mode wie bei deinem SPI Master?

Ohne Oszi wird es schwer. Dein Loigc Analyser kann nur digitale Werte 
anzeigen, du müsstest dir aber die Signalqualität anschauen. Erreichst 
du die richtigen Pegel für high und low?

Da du schreibst, dass nach etwa 100kB Fehler auftreten könnte es auch 
gar nichts mit deinen Signalen zu tun haben, sondern damit, wie die 
Daten weiter verarbeitet werden. Vielleicht gibt es ja da ein Problem?

Grüße

von Martin S. (strubi)


Lesenswert?

Als erstes waeren die CPHA/CPOL Einstellungen interessant, klingt eher 
nach Abtastungsproblem als eingestreutes Rauschen bei langsamer Slew 
Rate (was ungewollte Flanken provozieren koennte), da es ja offenbar bei 
langsamen Frequenzen tut und der Widerstand das Verhalten noch 
verbessert. Grundsaetzlich wuerde ich mal den externen, im Verhaeltnis 
langsamen Clock abtasten und eine Entprell-Option im SPI-Core vorsehen, 
damit hat man auch die Slew-Rate-Probleme vom Tisch und die 
Moeglichkeiten, Glitches auf lange Zeit zu detektieren.

von Tobias B. (tobiasz80)


Angehängte Dateien:

Lesenswert?

Hallo,

vielen Dank für die Antworten. Das Design läuft mit 100MHz. SPI soll so 
schnell wie möglich betrieben. Aktuell wird er im Mode 0 und mit ~14MHz 
betrieben, hoffe aber das ich mich noch auf 25MHz steigern kann. Je 
schneller, um so besser.
Mit ein paar weiteren Experimenten konnte ich das Problem weiter 
eingrenzen. Meine ursprüngliche Annahme mit dem Clock ist falsch, ganz 
offensichtlich ist es die der Chip Select der das Problem verursacht. 
Dabei folgender Test Code:
1
  always @(posedge i_SPI_Clk or posedge i_SPI_CS_n)
2
  begin
3
    if (i_SPI_CS_n)
4
    begin
5
      debug <= 0;
6
    end
7
    else
8
    begin
9
      debug <= 1;
10
    end
11
  end
Ein Serien Widerstand in der Chip Select Leitung erzeugt einen deutlich 
besseres Ergebniss, und auch das mit dem Logic Analyzer gemessene 
Rauschen ist deutlich geringer, trotzdem passiert es ab und zu, das 
während dem SPI Transfer der CS gezogen wird und dadurch der Slave nicht 
mehr im Sync mit dem Master ist, wie in dem glitch Bild zu sehen.

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


Lesenswert?

Tobias B. schrieb:
> ganz offensichtlich ist es die der Chip Select der das Problem
> verursacht.
Der ist doch eh dauerhaft auf Low-Pegel (warum eigentlich?).

Das Gezappel, das du da noch im mV Bereich siehst, ist Übersprechen vom 
gesamten fliegenden Aufbau zusammen mit den Übergangswiderständen auf 
dem Steckbrett.

Sieh dir auch mal an, wie so eine übliche Übertragung per SPI abläuft. 
Da geht **vor** dem Telegramm der SS auf low und bleibt dort stabil bis 
zum Ende der Übertragung. Und dann geht er wieder auf high, damit sich 
der Slave wieder mal auf den Master synchronisieren kann, falls er mal 
ausser Takt kommt. Solange der SS low ist werden die Daten vom MOSI mit 
dem SCLK eingetaktet.

Tobias B. schrieb:
> Wie sieht es z.B. aus, das der SPI Slave das Clock Signal vom SPI als
> Clock benutzt?
Geht schon. Du musst dann nur einen Mechanismus zum Queren der 
Taktdomäne von SCLK zum FPGA-Takt ausdenken.

> Wäre es besser den SPI direkt mit dem FPGA Clock zu samplen?
Das geht laut Nyquist nur, wenn du einen FPGA-Takt >> SCLK hast. Und 
wenn du da tatsächlich bis auf 100 MHz hoch willst (bist du sicher, dass 
du das brauchst?), dann mustt du mit 500MHz samplen.


> Die SPI Verbindung ist über Jumper Wires auf einem Breadboard ausgeführt.
Nur interessehalber: du hast schon auch die Masse vom µC mit der Masse 
vom FPGA verbunden?

: Bearbeitet durch Moderator
von Tobias B. (tobiasz80)


Lesenswert?

Lothar M. schrieb:
> Sieh dir auch mal an, wie so eine übliche Übertragung per SPI abläuft.
> Da geht **vor** dem Telegramm der SS auf low und bleibt dort stabil bis
> zum Ende der Übertragung. Und dann geht er wieder auf high, damit sich
> der Slave wieder mal auf den Master synchronisieren kann, falls er mal
> ausser Takt kommt. Solange der SS low ist werden die Daten vom MOSI mit
> dem SCLK eingetaktet.

So ähnlich läuft es auch ab. Aktuell wird die CSN Leitung auf low 
gezogen, sobald das System startet. Danach bleibt sie auf low, da es nur 
einen Slave gibt und die Daten gestreamed werden. Natürlich könnte ich 
nach jeder Transaktion die CSN Leitung wieder auf high ziehen und vor 
der neuen die CSN Leitung wieder auf low. Die Datenübertragung würde 
aber dadurch nicht stabiler werden, da eben zwischen den Bits dieses 
Event auftreten kann. Warum auch immer, und genau das versuche ich 
irgendwie rauszufinden. Oft tritt das Event auch einfach zwischen den 
Bytes auf und da ist es nicht weiter schlimm.
Es ist nur so, ich würde erwarten, das wenn ich den Pin am FPGA auf low 
ziehe (egal ob durch einen GPIO, Pulldown oder direkt mit GND), das an 
der CSN Leitung genau garnichts passiert. Der Reset vom FPGA wird auch 
durch einen anderen GPIO getriggert. Ich will genauso wenig das der FPGA 
zufällig resetted wird.

> Tobias B. schrieb:
>> Wie sieht es z.B. aus, das der SPI Slave das Clock Signal vom SPI als
>> Clock benutzt?
> Geht schon. Du musst dann nur einen Mechanismus zum Queren der
> Taktdomäne von SCLK zum FPGA-Takt ausdenken.

Das wird in dem SPI_Slave erledigt.

>> Wäre es besser den SPI direkt mit dem FPGA Clock zu samplen?
> Das geht laut Nyquist nur, wenn du einen FPGA-Takt >> SCLK hast. Und
> wenn du da tatsächlich bis auf 100 MHz hoch willst (bist du sicher, dass
> du das brauchst?), dann mustt du mit 500MHz samplen.

Nein, der FPGA takt läuft mit 100MHz, beim SPI würde ich so hoch gehen 
wollen, wie es geht, aber 25MHz würden mir für den SPI erstmal reichen 
:)

>> Die SPI Verbindung ist über Jumper Wires auf einem Breadboard ausgeführt.
> Nur interessehalber: du hast schon auch die Masse vom µC mit der Masse
> vom FPGA verbunden?

Natürlich, alle Massen sind miteinander verbunden. Das FPGA-Board wird 
durch die 5V vom Nucleo Board versorgt.

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


Lesenswert?

Tobias B. schrieb:
> Aktuell wird die CSN Leitung auf low gezogen, sobald das System startet.
> Danach bleibt sie auf low
Das ist ein Designfehler. Ein einziger Störimpuls und du bist den Rest 
des Tages um 1 Bit versetzt.

SPI funktioniert nur in der Theorie ohne den SS#.


> Ich will genauso wenig das der FPGA zufällig resetted wird.
Du hast den Reset aber schon so ausgeführt und einsynchronisiert, dass 
nicht bereits ein kleiner ESD-Spike ausreicht, um das Design (evtl. 
sogar nur partiell) zurückzusetzen?

: Bearbeitet durch Moderator
von Wastl (hartundweichware)


Lesenswert?

Lothar M. schrieb:
> Nur interessehalber:

Nur interessehalber: man darf auch mal die physikalische
Verbindung von Master und Slave in Zweifel ziehen bzw.
mistrauisch betrachten.

von Tobias B. (tobiasz80)


Lesenswert?

Lothar M. schrieb:
> Das ist ein Designfehler. Ein einziger Störimpuls und du bist den Rest
> des Tages um 1 Bit versetzt.
>
> SPI funktioniert nur in der Theorie ohne den SS#.

Mir gehts hier vorallem rauszufinden und zu verstehen, warum überhaupt 
so viele Störimpulse auf der SS# Leitung vorhanden sind, und warum ich 
es nur mit einem Serienwiderstand in der SS# Leitung zum laufen bekomme. 
Das kann doch nicht sein ... da muss doch was grundsätzliches faul sein.

> Du hast den Reset aber schon so ausgeführt und einsynchronisiert, dass
> nicht bereits ein kleiner ESD-Spike ausreicht, um das Design (evtl.
> sogar nur partiell) zurückzusetzen?

Der Reset wird über das Xilinx Processor System Reset Module 
einsynchronisiert. Das Teil wartet auch bis das OK vom Clock Wizard 
kommt.

von Wastl (hartundweichware)


Lesenswert?

Tobias B. schrieb:
> da muss doch was grundsätzliches faul sein.

... an deinem physikalischen Aufbau ....

Tobias B. schrieb:
> Die SPI Verbindung ist über Jumper Wires auf einem Breadboard
> ausgeführt.

Uuuuaaaaahhhhh ...... und Abblock-Kondensatoren sind vermutlich
auch nur vom Hörensagen bekannt.

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


Lesenswert?

Wastl schrieb:
> und Abblock-Kondensatoren sind vermutlich auch nur vom Hörensagen bekannt.
Die werden wohl schon auf dem Nucleo- und dem FPGA-Board drauf sein.

Tobias B. schrieb:
> warum überhaupt so viele Störimpulse auf der SS# Leitung vorhanden sind
Mal abgesehen davon, dass die paar mV sicher noch nichts ausmachen, ist 
die Ursache ganz einfach: es sind Einkopplungen von steilflankigen 
Schaltvorgängen (die kurzen, einmal auftretenden Peaks) und eine 
undefinierte Signal- bzw. Masseführung (die an den "Bits" erkennbare 
Potentialverschiebung).

Mach es einfach mal so: klemm die Masseklemme des Oszis direkt(!) an die 
Masse des µC. Also nicht irgendwo in die Nähe des µC, sondern an einen 
kurzen Draht, den du an die Masse direkt am µC angelötet hast.

Und miss dann mit der Tastkopfspitze direkt an der *Masse am FPGA*.

Man würde jetzt wegen Masse=Masse erwarten, dass da eine durchgehende 
schnurgerade Linie auf der 0V Linie des Oszis zu sehen ist.

Was siehst du stattdessen?

Das, was du da siehst, ist ein Spannungsabfall auf der Masseleitung am 
Leitungswiderstand incl. aller Übergangswiderstände im Steckbrett. Dein 
Ziel muss nun sein, dieses Gezappel möglichst "schurgerade" auf 0V 
herunter zu bekommen.

: Bearbeitet durch Moderator
von J. S. (engineer) Benutzerseite


Lesenswert?

Wastl schrieb:
> Tobias B. schrieb:
>> da muss doch was grundsätzliches faul sein.
>
> ... an deinem physikalischen Aufbau ....

oder an der Leiterplatte, oder den FPGA-Constraints. Das Kuriose ist, 
dass die Störungen auf der Leitung ja auch dann sichtbar sind, wenn sich 
beim SPI nichts tut, wenn man das Diagram anschaut.

Was Generelles:

> Dazu benutze ich dieses Modul
https://github.com/nandland

ich weiss nicht, warum jeder reflexartig immer versucht, sich etwas 
runterzuladen. Ich habe noch nie irgendwas von diesem Plattformen 
gebrauchen können, weil der Code dort nicht passt. Oft ist er 
funktionell nicht zur Aufgabe passend und nicht selten auch noch 
technisch schlecht.

Das zu vereinen kostet am Ende mehr Aufwand, als die 10 Zeilen selber 
hinzuschreiben, wie man es braucht.

Wenn ich z.B. diese Art der Verknüpfung sehe:
"always @(posedge i_SPI_Clk or posedge i_SPI_CS_n)"
und dann die Xilinx System Reset Strat angesprochen wird, dann sehe ich 
schon wieder X Probleme.

Ein SPI-Slave-IF muss gefahren werden, wie ein Chip, d.h. mit dessen 
Takt, dessen Select und dessen Daten. Entweder komplett aysnchron mit 
angepassten timings und späterem CRC des Registers, oder eben komplett 
virtualisiert mit Synchronisation der Signale in die/der Zieldomain.

Darüber muss man sich Gedanken machen und dann die Lösung selektieren.
Was sagt denn eigentlich die Simulation?

von Gustl B. (-gb-)


Lesenswert?

J. S. schrieb:
> Wenn ich z.B. diese Art der Verknüpfung sehe:
> "always @(posedge i_SPI_Clk or posedge i_SPI_CS_n)"
> und dann die Xilinx System Reset Strat angesprochen wird, dann sehe ich
> schon wieder X Probleme.

Welche denn konkret?

J. S. schrieb:
> Ein SPI-Slave-IF muss gefahren werden, wie ein Chip, d.h. mit dessen
> Takt, dessen Select und dessen Daten. Entweder komplett aysnchron mit
> angepassten timings und späterem CRC des Registers, oder eben komplett
> virtualisiert mit Synchronisation der Signale in die/der Zieldomain.

Kann man machen, muss man aber ganz sicher nicht.

von Rick D. (rickdangerus)


Lesenswert?

J. S. schrieb:
> oder eben komplett
> virtualisiert mit Synchronisation der Signale in die/der Zieldomain.

In meinen Designs synchronisiere ich immer über /CS.
Die fallende Flanke übernimmt die Daten in das Senderegister und die 
steigende Flanke übergibt die empfangenen Daten ins restliche Design.

/CS muß natürlich nach allen Regeln der Kunst einsynchronisiert werden 
(2xFF).

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


Angehängte Dateien:

Lesenswert?

Rick D. schrieb:
> /CS muß natürlich ... einsynchronisiert werden (2xFF).
Das ist hier nicht nötig, denn hier ist der SPI-Slave eine eigene 
Taktdomäne mit dem i_SPI_Clk als Takt. Man muss dann eben sehr aufpassen 
mit der Übergabe in die

Das ist hier über einen Fifo gelöst, allerdings geht auch so manches 
Signal asynchron über diese Taktgrenze.

J. S. schrieb:
> nicht selten auch noch technisch schlecht.
Sagen wir mal so: weil der lokale SPI-Takt noch kombinatorisch 
invertiert wird, ist es recht spannend, was denn der Synthesizer da 
überhaupt draus macht und ob der Takt es auf ein Taktnetz schafft oder 
ob er über "normales" Routing händisch lokal verdrahtet wird.

Und die Implementierung des SPI-Senders als Multiplexer macht die Sache 
nicht effizienter:
1
      r_SPI_MISO_Bit <= r_TX_Byte[r_TX_Bit_Count];

von J. S. (engineer) Benutzerseite


Lesenswert?

Gustl B. schrieb:
>> schon wieder X Probleme.
> Welche denn konkret?
weil da regelmäßig Beschreibungen mit asynchronen Resets und synchronen 
Resets gemischt werden, was zu teilweise absonderlichen Schaltungen und 
problematischen Verhalten führt.

Gustl B. schrieb:
> Kann man machen, muss man aber ganz sicher nicht.
Welche dritte Möglichkeit siehst du denn noch ??

Rick D. schrieb:
> In meinen Designs synchronisiere ich immer über /CS.
Ja, das wäre die zweite von mir beschriebene Möglichkeit.

> /CS muß natürlich nach allen Regeln der Kunst einsynchronisiert werden
> (2xFF).
Läuft dann aber alles stromfressend auf dem sehr hohen Systemtakt und 
hat zumindest kleine Latenzen. Bei sehr niedrigem Systemtakt in einem 
BAT-System wiederum kann es ein timing Problem geben.

Und dann gibt es spezielle Designs, die keinen kontinuierlichen 
Systemtakt mit PLL haben dürfen, weil das FPGA patient sein muss. Dann 
geht das nur oldstyle asynchron direkt in Kombinatorik.

Alle möglichen Versionen haben ihre Nischen

von J. S. (engineer) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> weil der lokale SPI-Takt noch kombinatorisch
> invertiert wird, ist es recht spannend, was denn der Synthesizer da
> überhaupt draus macht

Solche Geschichten fange ich durch meine Design STRAT ab: Es gibt ein 
physisches Design und ein darin innliegendes Logik design. In letzterem 
gibt es kein invertierten Takte oder low aktive Geschichten. Das wird 
alles brav außen abgefangen. Wenn da negierte Takte / Takte vorkommen, 
muss man immer entscheiden, ob die wirklich negiert sind, wegen low 
activer Ports am Chip, oder ob sie verschoben sind und wie man das 
intern korrigiert. Bei einem kontinuierlich laufenden Takt würde man das 
z.B. auch an einer PLL abfangen (können).

Negierte Takte gibt es im FGPA nur an den Stellen, wo die Zellen das 
physisch erfordern, z.B. an DDR-Takt-Treibern und DDR-IO-Zellen, die 
wirklich 2 Takteingänge haben und auch das steckt bei mir immer im 
äußeren Toplevel.

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.