Forum: FPGA, VHDL & Co. SPI Problem, Counter zählt nicht jede Flanke


von Der D. (daimlerfahrer)


Lesenswert?

Morgen zusammen,

ich habe derzeit ein komisches Problem mit einer SPI Schnittstelle.
Hier erstmal der Code:
1
Schieberegister : process (Takteingang,SPI_Clock) 
2
begin
3
  if Takteingang'event and Takteingang='1' then
4
  SPI_Clock_old <= SPI_Clock; -- saving the actual values
5
    if SPI_Clock_old='0' and SPI_Clock='1' then -- detect the rising edge of the SPI clock
6
      for i in 0 to Register_width-2 loop
7
      temp_signal(i+1) <= temp_signal(i);
8
      end loop;
9
    Counter <= Counter + 1;
10
    temp_signal(0) <= SPI_Data;
11
    end if;
12
  end if;
Der SPI_Clock liegt bei 50 kHz und der "Masterclock" Takteingang bekommt 
von mit 13 MHz.
ich taste den SPI-Takt ab und zähle auf die steigende Flanke einen 
Zähler auf 16. Danach sollte das Schieberegister voll sein und die Werte 
werden übernommen.
Jetzt passiert jedoch folgendes: Der Counter kommt häufig nur bis 15 und 
damit ist das Schieberegister noch nicht voll. Die Signale am Oszi sind 
aber prima (also Clock, CS und Daten sind da und haben schöne, steile 
Flanken).
Muss ich da noch etwas grober "entprellen" oder gibts andere 
Fehlerquellen für den falschen Zähler?

Danke schonmal für eure Tipps!

von Duke Scarring (Gast)


Lesenswert?

Hast Du das ganze schonmal simuliert?
Wo/wann wird Counter zurückgesetzt?

Duke

von SeriousSam (Gast)


Lesenswert?

Wieso taucht SPI_Clock in der sensitivity list auf? Sind die 
Eingangssignale synchronisiert?

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Also zunächst würde ich mal SPI_Clock aus der Sensitivity Liste 
herausnehmen und durch einen ordentlichen Reset Eingang ersetzen 
(welchen Wert hat SPI_Clock_old nach dem Einschalten?).

Dann muss SPI_Clock natürlich auf Takteingang synchronisiert werden 
bevor es verwendet wird. Am besten nach der klassischen Methode zweier 
hintereinander geschalteter Register. Wie man Schieberegister 
implementiert weißt Du ja schon.

Den Rest kann man aus diesem Fragment nicht erkennen.

In jedem Fall schließe ich mich Duke's Meinung bezüglich einer 
Simulation an.

Gruß
Marcus

von Der D. (daimlerfahrer)


Lesenswert?

Der Counter wird mit der steigenden Enable Flanke auf 16 geprüft und 
zurückgesetzt. Wenn 16 erreicht wird ausgegeben, zurückgesetzt wird 
immer.

Simulation tut...

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


Lesenswert?

Ist SPI_Clock direkt der Pin?
Falls ja: dann solltest du noch (mindestens) 1 FF dazwischenschalten.
Stichwort hier wieder: Metastabilität.

SPI_Data muß übrigens nicht synchronisiert werden, das ist zu dem 
Zeitpunkt garantiert stabil. tsu und th werden nicht verletzt.

Wenn schon generisch programmiert, dann doch nicht so verschleift. Das 
hier sieht doch viel kompakter aus (und ist genauso generisch):
1
Schieberegister : process (Takteingang,SPI_Clock) 
2
begin
3
  if Takteingang'event and Takteingang='1' then
4
  SPI_Clock_old <= SPI_Clock; -- saving the actual values
5
    if SPI_Clock_old='0' and SPI_Clock='1' then -- detect the rising edge of the SPI clock
6
       temp_signal <= temp_signal(temp_signal'length-1 downto 0) &  SPI_Data;
7
       Counter <= Counter + 1;
8
    end if;
9
  end if;

von Der D. (daimlerfahrer)


Lesenswert?

Danke schonmal für eure Tipps.
Das mit der sens. Liste gibts natürlich keinen Sinn - da habt ihr 
vollkommen recht!

Zum Thema Synchronisieren habe ich noch eine Frage - ich war der Meinung 
ich müsste die beiden Takte bei dieser Methode nicht synchronisieren, 
wenn ich auf den Master-Clock den Zustand vergleiche und so die Flanke 
detektiere.
Ich dachte schlimmstenfalls erhalte ich dabei einen Jitter von meinen 13 
MHz bei der "Abtastung" - oder wo liegt bei den nicht synchronisierten 
Signalen das Problem?

Das Eingangs-FF werde ich der Metastabilität wegen implementieren (ich 
erinnere mich an eine Vorlesung zu dem Thema... da war was, ja irgenwas 
war da :P)

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


Lesenswert?

> oder wo liegt bei den nicht synchronisierten Signalen das Problem?
>> Stichwort hier wieder: Metastabilität.

Auf gut Deutsch heißt das:
mal geht es und mal geht es nicht.
In der Simulation funktioniert es aber immer.

EDIT:
Was macht die Simulation, wenn beide Flanken gleichzeitig kommen?
Ja: immer das selbe.

Und was macht deine reale Schaltung?
"Gleichzeitig" gibt es hier nicht. Du hast aber auf jeden Fall eine tsu 
(Setup) und th (Hold) Verletzung, und deine FFs machen, was sie wollen.

von Der D. (daimlerfahrer)


Angehängte Dateien:

Lesenswert?

Ich hab hier mal den kompletten Code angehängt.
Mein Problem habe ich soweit eingrenzen können:
- wenn ich auf die SPI-Flanke triggere, dann tut meine Schnittstelle, 
ich kann jedoch nicht mit dem Counter prüfen ob tatsächlich alle Bits 
geschoben wurden.
- wenn ich den Vergleich von Signal zu Signal_old als event nutze, 
erhalte ich nicht nachvollziehbares verhalten, obgleich die Simulation 
funktioniert

Ist mein erstr Code zu SPI - demnach bin ich über jegliche Tipps dankbar 
:D

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


Lesenswert?

Dein SPI_Enable ist komplett asynchron, und wird einfach mit dem Takt 
abgefragt. Das geht schief, ab und zu.
1
    if SPI_Enable='1' then
2
       counter <= "00000";
3
    end if;
4
    
5
    if SPI_Enable='0' then


Mach das mal auch so hübsch synchron wie
1
  SPI_Clock <= SPI_Clock_ext;
2
  SPI_Clock_old <= SPI_Clock; -- saving the actual values

Aber i.A. solltest du das mit jedem Signal, das von Aussen kommt, 
machen. Ab und zu brauchst du es nicht, das muß aber gut überlegt sein.

Schöner sieht das übrigens aus, wenn du ein Schieberegister nimmst:
1
:
2
signal SCLK_sr: std_logic_vector (1 downto 0);
3
signal SS_sr: std_logic_vector (1 downto 0);
4
:
5
:
6
process (Takteingang) is 
7
begin
8
  if rising_edge (Takteingang) then
9
    SS_sr   <= SS_sr(0) & SS;      -- Slave-Select
10
    SCLK_sr <= SCLK_sr(0) & SCLK;  -- SPI Clock
11
    :
12
    if (SCLK_sr="01") then         -- steigende Flanke
13
    :
14
    if (SS_sr="10") then           -- fallende Flanke
15
    :
16
  end if;
17
end process;
18
:

von Der D. (daimlerfahrer)


Lesenswert?

Okay Danke Lothar,

ich habe nun alle Eingänge synchronisiert und damit treten deutlich 
seltener Aussetzer auf.
Leider kommt dennoch nicht jedes SPI-Packet am Ziel an.
Ist es denn üblich, den SPI-Takt mit einem Masterclock "abzustasten" und 
mit den geänderten Zuständen zu arbeiten?

Grüße

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


Lesenswert?

> und damit treten deutlich seltener Aussetzer auf.
Dann ist immer noch irgendwo so ein Bock drin ;-)

> Ist es denn üblich, den SPI-Takt mit einem Masterclock "abzustasten" und
> mit den geänderten Zuständen zu arbeiten?
Nein, ich würde das etwas anders machen. Zum Eintakten wird der SCLK 
verwendet, und wichtig ist nur, dass die Daten bei der Übernahme in 
die Masterclock-Domäne stabil sind.
Falk Brunner hat es hier mal schön aufgezeigt: 
Beitrag "Re: SPI im CPLD mit State Machine - geht das so?"

von Tom (Gast)


Lesenswert?

1
    if SPI_Enable='1' then
2
    counter <= "00000";
3
    end if;
4
5
6
    if SPI_Enable_old='0' and SPI_Enable='1' then
7
      if counter = "10000" then -- detect the rising edge of the Enable signal
8
      OK_Programm_Signal <= '1';
9
      else
10
      OK_Programm_Signal <= '0';
11
      end if

Wird die Abfrage des counters überhaupt erreicht, ich denke nicht, da er 
sobald SPI_Enable '1' wird auf Null zurückgesetzt wird.

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


Lesenswert?

Prinzipiell ist es sogar noch krasser. Zeilen wie
1
      if counter = "10000" then 
2
           OK_Programm_Signal <= '1';
3
      :
sind komplett unnötig, wenn man sich das SPI-Protokoll mal genau 
durchliest.

In dem Protokoll wird nämlich nicht eine bestimmte Anzahl eingeschobener 
Bits zur Datenübernahme spezifiziert, sondern das Deselektieren des 
Bausteins. Die Datenübernahme erfolgt also per Definition mit der 
steigenden Flanke des SS-Signals. Und damit werden alle Zähler, die 
irgendwelche eingetaktete Bits zählen, unnötig. Ich könnte hier also 
z.B. 123 Bits eintakten, verwendet würden die letzten 16 davon.

Und der andere Vorteil bei der Datenübernahme per SS ist der, dass 
mehrere Slaves einfach hintereinander geschaltet werden können, und 
diese Diasy-Chain mit 1 SS bedient werden kann. Siehe dazu z.B. 
http://www.maxim-ic.com/appnotes.cfm/an_pk/3947

Allerdings gibt es durchaus kommerzielle Bausteine, bei denen explizit 
im DB steht, dass nicht die letzten, sondern die ersten eingeschobenen 
Bits intern weiterverwendet werden. Das deutet wieder auf einen Zähler 
oder ein nicht nur vom SCLK gesteuertes Schieberegister hin.

von Der D. (daimlerfahrer)


Lesenswert?

Okay ich hab das ganze nun nochmal ohne irgendwelche Zähler-Abfragen 
implementiert.
Recht nahe angelehnt an den verlinkten Code von Falk Brunner. Leider 
bekomme ich auch weiterhin einige Bits falsch detektiert. Verstehen will 
ich es nicht mehr so recht, da das SPI Signal wirklich keinen Fehler 
aufweist, und im FPGA dennoch falsch übergeben wird...
Also herzlichen Dank für eure Hilfe und wenn ihr weitere Tipps habe 
freue ich mich natürlich. Werde jetzt mal versuchen noch einige 
Sicherheiten einzubauen, dass ein falsches Ergebnis nicht übernommen 
wird. Das wäre bei meiner Anwendung nämlich ziemlich blöd - lieber sende 
ich die Daten nochmal.

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


Lesenswert?

> Verstehen will ich es nicht mehr so recht, da das SPI Signal
> wirklich keinen Fehler aufweist, und im FPGA dennoch falsch
> übergeben wird...
Es ist ohne weiteres möglich, auf beide angesprochenen Arten (alles 
einsynchronisieren  bzw. lokaler SPI-Takt) das SPI-Protokoll auf einem 
FPGA zu implementieren. Und dazu ist keine Fehlerbehandlung nötig.

Ich habe so eine Fehlerbehandlung bei mir mal implementiert, nur, um 
nach mehreren 10000 Maschinenjahren (5000 Maschinen * 6 Jahre) 
festzustellen, daß diese Fehlerbehandlung unnötig ist.

Wenn du meinst, deine Beschreibung wäre ok, dann kommt als nächstes:
Hardware?
Layout?
Masseführung?
Blockkondensatoren?

von Volker (Gast)


Lesenswert?

Poste halt noch mal deinen Code.

von Der D. (daimlerfahrer)


Lesenswert?

Okay ich hab das ganze heute nochmal geprüft. Das problem ist nicht mehr 
der SPI - der klappt. Ich habe ihn wie oben beschrieben ohne Zähler und 
detektiere bisher alles fehlerfrei.
Das Problem das ausftrat, hatte mit meinem auswertenden Code zu tun und 
nicht mit dem SPI.
Also vielen Dank euch allen - mein SPI-Problem ist gelöst :D

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.