mikrocontroller.net

Forum: FPGA, VHDL & Co. Erfahrung mit SPI Slave und Spartan 6 FPGA?


Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte gerade ein SPI Slave beschreiben und habe mir dazu einige 
Beschreibungen im Internet angeschaut. Nach der ständig wiederholten 
Warnung:
Xst:3002 - This design contains one or more registers/latches that are directly
   incompatible with the Spartan6 architecture. The two primary causes of this is
   either a register or latch described with both an asynchronous set and
   asynchronous reset, or a register or latch described with an asynchronous
   set or reset which however has an initialization value of the opposite 
   polarity (i.e. asynchronous reset with an initialization value of 1).

verzweifel ich so langsam.

Auch bei den Beispielen aus dem Internet kam bei mir immer diese 
Message.

Wenn damit schon mal jemand Erfahrung gemacht hat, speziell mit dem 
Spartan6 und eben eine Lösung für das Problem bereit stellt, wäre ich 
sehr dankbar.

Ich habe auch ein simples parallel zu seriell Register auch schon bei 
dem die Synthese und Simulation einwandfrei funktionieren:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;


entity ParalellToSerial is
        
generic( n : integer := 16);
      Port (   
          reset   : in STD_LOGIC;
          sclk    : in std_logic;
          CS     : in std_logic;
          data_in   : in STD_LOGIC_VECTOR (n-1 downto 0);
          
          data_out  :  out STD_LOGIC
         );
end ParalellToSerial;

architecture Behavioral of ParalellToSerial is
        signal DST     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
        signal DATA    : STD_LOGIC := '0';

begin

process(reset,sclk, CS)
       
 begin
    
    if reset = '1' then
        
        DST  <= (others => '0');
         DATA <= '0';
              
    elsif rising_edge(sclk) then
    
      if CS = '0' then
                   
        DATA <= DST(n-1);            
            DST  <= DST(n-2 downto 0) & '0'; 
                      
      else
                        
        DST <= data_in;
        
      end if;
      end if;
end process;
       
     data_out <= DATA;

end Behavioral;

Nur ist es da ja so das beim SPI ja die Clock erst einsetzt bei der 
Übertragung und wenn das CS auf 'Low' ist. Hier ist es ja noch momentan 
so das es die Clock benötigt zum einlesen der Daten und zum senden der 
Daten.

Ich wäre für Tipps zur weiteren Umsetzung zum SPI Slave oder eben warum 
der Spartan 6 Probleme mit den anderen Designs haben könnte, sehr 
dankbar.

Gruß

: Bearbeitet durch User
Autor: Christian R. (supachris)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Sowas macht man indem man den SCLK einsychronisiert und bei der 
entsprechenden Flanke ein Clock Enable für den internen Takt erzeugt. 
Geht natürlich nur, wenn die Frequenz des SCLK ein ganzes Stück 
niedriger (Faktor 4) ist als die interne Taktfrequenz, was ja aber in 
den allermeisten Fällen passen sollte.

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

Bewertung
1 lesenswert
nicht lesenswert
Andi P. schrieb:
> process(reset,sclk, CS)
Vorneweg: CS gehört hier nihct in die Sensitivliste.

> Nach der ständig wiederholten Warnung:
> (i.e. asynchronous reset with an initialization value of 1).
Dann mach doch den asynchronen Reset raus. Wofür brauchst du denn 
überhaupt?

> Ich wäre für Tipps zur weiteren Umsetzung zum SPI Slave oder eben warum
> der Spartan 6 Probleme mit den anderen Designs haben könnte, sehr
> dankbar.
Wie schnell ist dein FPGA-Quarztakt?
Wie schnell ist dein SPI?

Als Tipp: sieh dir an, wie Mikrocontroller das machen. Da geht der SCLK 
nicht direkt auf den Takteingang eines Flipflops, sondern es wird eine 
Flankenerkennung darauf gemacht und dann das Datenbit übernommen.
So etwa:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity ParalellToSerial is
        
generic( n : integer := 16);
      Port (   
          clk100MHz : in STD_LOGIC;
          sclk      : in std_logic;
          CS        : in std_logic;
          data_in   : in  STD_LOGIC_VECTOR (n-1 downto 0);
          data_out  : out STD_LOGIC_VECTOR (n-1 downto 0);
          MISO  :  out STD_LOGIC;
          MOSI  :  in STD_LOGIC
         );
end ParalellToSerial;

architecture Behavioral of ParalellToSerial is
        signal DST     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
        signal sclkCS  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
begin

  process begin
     wait until rising_edge(clk100MHz);    -- der einzige Mastertakt für ALLES im ganzen FPGA!
     sclkSR  <= sclkSR(0) & sclk;
     sclkCS  <= sclkCS(0) & CS;
   
     if CS = '0' then
       if sclkSR="01" then                 -- steigende Flanke am SCLK
         DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
       end if;
     else
       if sclkSR="01" then                 -- steigende Flanke am CS
         data_out <= DST;                  -- Übertragung fertig: Daten übergeben
       end if;
       DST <= data_in;                     -- neue Daten übernehmen
     end if;
  end process;
  
  -- Ausgangstreiber für MISO umschalten
  data_out <= DST(n-1) when CS = '0' else 'Z';           

end Behavioral;

: Bearbeitet durch Moderator
Autor: bit blaser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nicht alles was takt heisst wird auch als FF-Takt im FPGA genutzt ->

Statt den SPI-clk alles mit dem FPGA-systemtakt erzeugen respektive 
abtakten.


Hier in verilog: http://www.fpga4fun.com/SPI2.html


Das http://www.lothar-miller.de/s9y/categories/26-SPI-Slave ist zwar in 
VHDL allerdings für eine CPLD-Architektur und ohne Systemtakt.

Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian R. schrieb:
> Sowas macht man indem man den SCLK einsychronisiert

Vielen Dank, kann ich beim einsynchronisieren der beiden Clocks vorgehen 
wie im Beispiel von Lothar Miller?

www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
bit blaser schrieb:

> Das http://www.lothar-miller.de/s9y/categories/26-SPI-Slave ist zwar in
> VHDL allerdings für eine CPLD-Architektur und ohne Systemtakt.

Das Beispiel habe ich mir auch schon angeschaut aber ist eben für CPLD 
und ohne Systemtakt, genau. :-)

> Statt den SPI-clk alles mit dem FPGA-systemtakt erzeugen respektive
> abtakten.
> Hier in verilog: http://www.fpga4fun.com/SPI2.html

Werde ich mir anschauen, vielen Dank!

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

Bewertung
0 lesenswert
nicht lesenswert
bit blaser schrieb:
> Das http://www.lothar-miller.de/s9y/categories/26-SPI-Slave ist zwar in
> VHDL allerdings für eine CPLD-Architektur und ohne Systemtakt.
Ich werde das nochmal ausdrücklich vermerken...

Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Andi P. schrieb:
>> process(reset,sclk, CS)
> Vorneweg: CS gehört hier nihct in die Sensitivliste.

Ahja, ok. könntest du mir das eventuell kurz erklären wieso nicht? Ich 
ging davon aus in der Sensitivliste die Signale stehen auf die auch 
reagiert werden soll?

>> Nach der ständig wiederholten Warnung:
>> (i.e. asynchronous reset with an initialization value of 1).
> Dann mach doch den asynchronen Reset raus. Wofür brauchst du denn
> überhaupt?

Du hast Recht nach der Übertragung ist das SR eh "leer" also mit 0 
besetzt.

>> Ich wäre für Tipps zur weiteren Umsetzung zum SPI Slave oder eben warum
>> der Spartan 6 Probleme mit den anderen Designs haben könnte, sehr
>> dankbar.
> Wie schnell ist dein FPGA-Quarztakt?
> Wie schnell ist dein SPI?

Meinen Takt den ich in mein System rein geben werde sind 40 MHZ oder 
auch mehr. Auf jedenfall wird dieser dann auf 400 MHZ erhöht durch eine 
PLL die mit vier phasenverschobenen Takten dann vier Zähler taktet. 
Bestimmte Zählerstände werden irgendwann ausgegeben und diese sollen 
dann eben "gebündelt" durch diesen SPI Slave auf ein 
Mikrocontroller(SPI) Interface übertragen werden.

Der Takt des SPI Interface ist 8 MHz.

>DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen

Wahrscheinlich doofe Frage :-/: Kann MOSI nicht auch mit '0' ersetzt 
werden?

Autor: Christian R. (supachris)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andi P. schrieb:
> Meinen Takt den ich in mein System rein geben werde sind 40 MHZ oder
> auch mehr. Auf jedenfall wird dieser dann auf 400 MHZ

> Der Takt des SPI Interface ist 8 MHz.

Dann passt das ja locker mit der Abtastung.

Andi P. schrieb:
> Wahrscheinlich doofe Frage :-/: Kann MOSI nicht auch mit '0' ersetzt
> werden?

Klar, aber dann liest der Slave ja keine Daten mehr ein, sondern nur 0. 
Wo liegt da der Sinn? An MOSI (Master Out Slave In) kommen doch die 
Daten von deinem µC.

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

Bewertung
1 lesenswert
nicht lesenswert
Andi P. schrieb:
> Wahrscheinlich doofe Frage :-/: Kann MOSI nicht auch mit '0' ersetzt
> werden?
Wenn der Master nichts zu senden und der Slave nichts zu empfangen hat, 
dann schon. Aber im Normalfall ist der eigentlich Vorteil ja der, dass 
mit jedem SCLK Takt ein Bit vom Master zum Slave und gleichzeitig ein 
Bit vom Slvae zum Master übertragen wird:
http://www.lothar-miller.de/s9y/archives/15-SPI.html

> Ahja, ok. könntest du mir das eventuell kurz erklären wieso nicht? Ich
> ging davon aus in der Sensitivliste die Signale stehen auf die auch
> reagiert werden soll?
Die Sensitivliste sagt dem Simulator, wann er den Prozess neu 
berechnen muss. Und er muss in deinem Fall den Prozess nur berechnen, 
wenn sich der Takt ändert. Denn wenn sich CS ändert und SCLK keine 
steigende Flanke hat, dann wird sich auch das Ergebnis des Prozesses 
nicht ändern.

Der Synthese ist die Sensitivliste eh' komplett schnuppe!

> Meinen Takt den ich in mein System rein geben werde sind 40 MHZ oder
> auch mehr. Auf jedenfall wird dieser dann auf 400 MHZ erhöht durch eine
> PLL die mit vier phasenverschobenen Takten dann vier Zähler taktet.
> Bestimmte Zählerstände werden irgendwann ausgegeben und diese sollen
> dann eben "gebündelt" durch diesen SPI Slave auf ein
> Mikrocontroller(SPI) Interface übertragen werden.
Dann nimm die 40MHz zum Abtasten der SPI Signale.
BTW: es wird sicher spannend, wie du die Zählerstände konsistent aus der 
400MHz-Domäne herausbekommst. Durch die Phasenverschiebung wird der 
virtuelle "Takt" sogar noch höher (oder andersrum: die Marge zur 
Übergabe an die 40MHz-Flipflops wird knapper). Dort musst du dir also 
auch noch irgendeinen Synchronisationsmechanismus ausdenken.

: Bearbeitet durch Moderator
Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian R. schrieb :
> Andi P. schrieb:
>> Wahrscheinlich doofe Frage :-/: Kann MOSI nicht auch mit '0' ersetzt
>> werden?
>
> Klar, aber dann liest der Slave ja keine Daten mehr ein, sondern nur 0.
> Wo liegt da der Sinn? An MOSI (Master Out Slave In) kommen doch die
> Daten von deinem µC.

Wenn ich aber später über MOSI, Daten vom SPI Interface an den FPGA 
übergebe dann sollen die ja anders im FPGA verwendet werden und nicht in 
dieses Register eingelesen werden.

Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>> Ahja, ok. könntest du mir das eventuell kurz erklären wieso nicht? Ich
>> ging davon aus in der Sensitivliste die Signale stehen auf die auch
>> reagiert werden soll?
> Die Sensitivliste sagt dem Simulator, wann er den Prozess neu
> berechnen muss. Und er muss in deinem Fall den Prozess nur berechnen,
> wenn sich der Takt ändert. Denn wenn sich CS ändert und SCLK keine
> steigende Flanke hat, dann wird sich auch das Ergebnis des Prozesses
> nicht ändern.
>
> Der Synthese ist die Sensitivliste eh' komplett schnuppe!

Sehr gute Erklärung! Vielen Dank. :-)

> BTW: es wird sicher spannend, wie du die Zählerstände konsistent aus der
> 400MHz-Domäne herausbekommst. Durch die Phasenverschiebung wird der
> virtuelle "Takt" sogar noch höher (oder andersrum: die Marge zur
> Übergabe an die 40MHz-Flipflops wird knapper). Dort musst du dir also
> auch noch irgendeinen Synchronisationsmechanismus ausdenken.

Alles klar, wird ich beachten.

Autor: Christian R. (supachris)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Andi P. schrieb:
> Wenn ich aber später über MOSI, Daten vom SPI Interface an den FPGA
> übergebe dann sollen die ja anders im FPGA verwendet werden und nicht in
> dieses Register eingelesen werden.

Hm, das versteh ich jetzt nicht. SPI sind im einfachsten Fall 2 
gekoppelte Schieberegister. Eins im Master, eins im Slave. Beim Transfer 
werden die Inhalte der beiden Register ausgetauscht. Die Daten, die der 
Master (Bei der der µC) an das FPGA (den Slave) senden will, muss er aus 
seinem Schieberegister in das das Slave-Schieberegister schieben (über 
den MOSI), anders gehts nicht. Wenn der Transfer abgeschlossen ist, 
kannst du mit den parallelen Daten ja machen was du willst.
Will der Master was vom Slave lesen, muss der Slave die Daten in seinem 
Schieberegister bereitstellen und beim Transfer raus schieben. Bei jedem 
SPI Transfer wird vom Master sowieso das Register des Slave ausgelesen 
(über MISO).
Du musst also immer über die zwei Schieberegister gehen.

: Bearbeitet durch User
Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andi P. schrieb:
> Wenn ich aber später über MOSI, Daten vom SPI Interface an den FPGA
> übergebe dann sollen die ja anders im FPGA verwendet werden und nicht in
> dieses Register eingelesen werden.
Machst du dann für jedes Register einen eigenen Slave-Select?

Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian R. schrieb:
> Hm, das versteh ich jetzt nicht. SPI sind im einfachsten Fall 2
> gekoppelte Schieberegister ...

Du hast Recht, da stand ich wohl auf dem Schlauch! -.- Ich glaub ich 
brauch erst mal ne Kaffeepause :-D.

Autor: Andi P. (jamaram90)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
> Andi P. schrieb:
>> Wenn ich aber später über MOSI, Daten vom SPI Interface an den FPGA
>> übergebe dann sollen die ja anders im FPGA verwendet werden und nicht in
>> dieses Register eingelesen werden.
> Machst du dann für jedes Register einen eigenen Slave-Select?

Nein passt schon, ich war da durcheinander. Das Problem nagte nun schon 
zu lange an meinen Nerven. ;-) Danke euch!

Autor: Thorsten F. (tfol)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>
> library IEEE;
> use IEEE.STD_LOGIC_1164.ALL;
> 
> entity ParalellToSerial is
> 
> generic( n : integer := 16);
>       Port (
>           clk100MHz : in STD_LOGIC;
>           sclk      : in std_logic;
>           CS        : in std_logic;
>           data_in   : in  STD_LOGIC_VECTOR (n-1 downto 0);
>           data_out  : out STD_LOGIC_VECTOR (n-1 downto 0);
>           MISO  :  out STD_LOGIC;
>           MOSI  :  in STD_LOGIC
>          );
> end ParalellToSerial;
> 
> architecture Behavioral of ParalellToSerial is
>         signal DST     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
>         signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
>         signal sclkCS  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
> begin
> 
>   process begin
>      wait until rising_edge(clk100MHz);    -- der einzige Mastertakt für 
> ALLES im ganzen FPGA!
>      sclkSR  <= sclkSR(0) & sclk;
>      sclkCS  <= sclkCS(0) & CS;
> 
>      if CS = '0' then
>        if sclkSR="01" then                 -- steigende Flanke am SCLK
>          DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
>        end if;
>      else
>        if sclkSR="01" then                 -- steigende Flanke am CS
>          data_out <= DST;                  -- Übertragung fertig: Daten 
> übergeben
>        end if;
>        DST <= data_in;                     -- neue Daten übernehmen
>      end if;
>   end process;
> 
>   -- Ausgangstreiber für MISO umschalten
>   data_out <= DST(n-1) when CS = '0' else 'Z';
> 
> end Behavioral;
> 

Ich habe 2 Fragen zu der SPI-Slave Beschreibung:

1. wofür ist den sclkCS drin, das wird ja gar nicht weiter verwendet.

2. und wie kann ich mit
sclkSR  <= sclkSR(0) & sclk;
if sclkSR="01" then
...
eine steigende Flanke von SLK erkennen?

Danke
Thorsten

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten F. schrieb:
> 1. wofür ist den sclkCS drin, das wird ja gar nicht weiter verwendet.
ich denke mal, da hat der Lothar einfach geschlampt! sclkCS ist das 
einsynchronisiert chip-select, er hat in der Abfrage aber das 'rohe' 
Eingangssignal verwendet. Sollte im Normalfall wurscht sein

>
> 2. und wie kann ich mit
> sclkSR  <= sclkSR(0) & sclk;
> if sclkSR="01" then
> ...
> eine steigende Flanke von SLK erkennen?
Naja, wenn du die 'sclk' in deinen FPGA Takt einsynchronisierst 
(Schieberegister mit FPGA Takt), dann erkennst du in dem Schieberegister 
mit dem Pattern "01" eine steigende, mit dem Pattern "10" eine fallende 
Flanke von 'sckl' (halt mit etwas zeitlicher Verzoegerung)

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten F. schrieb:
>>      if CS = '0' then
>>        if sclkSR="01" then                 -- steigende Flanke am SCLK
>>          DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
>>        end if;
>>      else
>>        if sclkSR="01" then                 -- steigende Flanke am CS
>>          data_out <= DST;                  -- Übertragung fertig: Daten
>> übergeben
>>        end if;
>>        DST <= data_in;                     -- neue Daten übernehmen
>>      end if;
achso, das hier halte ich fuer bedenklich... Und zwar der 'else' Zweig 
von CS. Wenn CS=1 ist, also im 'else', dann wartet er noch auf eine 
sclkSR=01 um die Daten an den Ausgang der Komponente zu geben. Das ist 
aber nicht korrekt! Wenn CS am Ende eines SPI-Transfers auf 1 geht, dann 
ist der Transfer beendet, spaetestens dann muesste data_out valide sein 
(evtl. schon vorher wenn man die SPI clocks mitzaehlt).
Erscheint mir ziemlich unsauber...

Autor: Thorsten F. (tfol)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:
> Thorsten F. schrieb:
>> 1. wofür ist den sclkCS drin, das wird ja gar nicht weiter verwendet.
> ich denke mal, da hat der Lothar einfach geschlampt! sclkCS ist das
> einsynchronisiert chip-select, er hat in der Abfrage aber das 'rohe'
> Eingangssignal verwendet. Sollte im Normalfall wurscht sein

hatte ich mir schon gedacht aber nicht gewagt zu äussern. ;)

>>
>> 2. und wie kann ich mit
>> sclkSR  <= sclkSR(0) & sclk;
>> if sclkSR="01" then
>> ...
>> eine steigende Flanke von SLK erkennen?
> Naja, wenn du die 'sclk' in deinen FPGA Takt einsynchronisierst
> (Schieberegister mit FPGA Takt), dann erkennst du in dem Schieberegister
> mit dem Pattern "01" eine steigende, mit dem Pattern "10" eine fallende
> Flanke von 'sckl' (halt mit etwas zeitlicher Verzoegerung)

Aber wie kann denn aus
sclkSR  <= sclkSR(0) & sclk;
"10" werden, sage ich nicht mit (0), dass der erste Wert eine 0 ist?
Es könnte noch "00" sein, aber dann könnte ich auch direkt sclk 
abfragen.

Ich frage mich halt wie ich bei meinem schnellen Takt sauber erkennen 
kann, jetzt hat sich was am sck von SPI getan und reagiere erst wieder 
beim nächten High werden vom sck.

Thorsten

Autor: berndl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Thorsten F. schrieb:
> Aber wie kann denn aus
> sclkSR  <= sclkSR(0) & sclk;
> "10" werden, sage ich nicht mit (0), dass der erste Wert eine 0 ist?
> Es könnte noch "00" sein, aber dann könnte ich auch direkt sclk
> abfragen.

Denkfehler! sclkSR ist ein Schieberegister mit 2 Bit. Schieberegister 
heisst, du hast einen Eingang am ersten FF (Bit 0), das wird in jedem 
Clock-Cycle mit sclk neu gesetzt. Gleichzeitig uebertraegst du den Wert 
von Bit 0 in das Bit 1 deines SR. In den beiden FFs des SR ist also der 
zeitverzoegerte Wert (gesampled mit deiner Clock) des Eingangssignals. 
Wenn du also in deinem SR eine Wertefolge "01" findest, dann heisst das, 
dass sich dein Eingangssignal in den letzten beiden Clockzyklen von 0 
auf 1 geaendert hat. Dito fuer alle anderen 2-Bit Kombinationen...

Autor: Thorsten F. (tfol)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
berndl schrieb:

> Denkfehler! sclkSR ist ein Schieberegister mit 2 Bit. Schieberegister
> heisst, du hast einen Eingang am ersten FF (Bit 0), das wird in jedem
> Clock-Cycle mit sclk neu gesetzt. Gleichzeitig uebertraegst du den Wert
> von Bit 0 in das Bit 1 deines SR. In den beiden FFs des SR ist also der
> zeitverzoegerte Wert (gesampled mit deiner Clock) des Eingangssignals.
> Wenn du also in deinem SR eine Wertefolge "01" findest, dann heisst das,
> dass sich dein Eingangssignal in den letzten beiden Clockzyklen von 0
> auf 1 geaendert hat. Dito fuer alle anderen 2-Bit Kombinationen...

Danke berndl für die Erklärung.
Das bedeutet also slk ist 0, dann steht "00" im Schieber, wenn sclk dann 
von 0 auf 1 geht steht da "01" drin, dann bei den nächsten Systemtakten 
"11" bis sclk auf 0 geht und ein mal "10" drin steht um dann beim 
nächsten Systemtakt wieder "00" zu schieben.

Das ist ja einfach. ;)


Thorsten

Autor: berndl (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
genau so

Autor: Thorsten F. (tfol)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>
>      if CS = '0' then
>        if sclkSR="01" then                 -- steigende Flanke am SCLK
>          DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
>        end if;
>      else
>        if sclkSR="01" then                 -- steigende Flanke am CS
>          data_out <= DST;                  -- Übertragung fertig: Daten 
> übergeben
>        end if;
>        DST <= data_in;                     -- neue Daten übernehmen
>      end if;
> 

dazu noch 2 Fragen.
"-- steigende Flanke am CS" müsste aber
"-- steigende Flanke am SCLK" heissen, oder?

und dann diese Zeile:
DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen

da werden die "Slave in"-Daten ja in DST Schieber geladen. aber warum 
DST(n-2 downto 0), also warum n-2. Müsste es nicht auch in den ersten FF 
rein um die anderen Werte weiter zu schieben, also DST(0)?

Thorsten

Autor: Tim R. (mugen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
    if sclkSR="01" then                 -- steigende Flanke am CS
      data_out <= DST;                  -- Übertragung fertig: Daten übergeben
    end if;
    DST <= data_in;                     -- neue Daten übernehmen
Irgendwie ist diese Anweisung nicht zielführend. Zunächst müsste es doch
if sclkCS="01" then 
heißen.

Die Zeile
 DST <= data_in; 
 sollte in diesem Zusammenhang auch nicht genutzt werden. Würde ja 
bedeuten, dass data_in quasi direkt in data_out geschrieben würde. 
Lothar trifft bestimmt keine Schuld, dafür wird hier eindeutig zu viel 
VHDL code gepostet. Aber merkt das kein Anderer?

Bis auf diese zwei Zeilen ist der Code recht gut geeignet als SPI Slave, 
der wirklich nur Daten empfängt und parallel ausgibt. Allerdings habe 
ich nach Lothars Kunst die Eingangssignale durch zweimaliges Schieben 
einsynchronisiert. Die SPI Kommunikation ist mit 180 kHz recht langsam, 
da mir eine sichere Übertragung wichtiger ist als eine schnelle 
Übertragung. System-Clock ist 50Mhz.

Autor: Jonas Biensack (jibi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>      if CS = '0' then
>        if sclkSR="01" then                 -- steigende Flanke am SCLK
>          DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
>        end if;
>      else
>        if sclkSR="01" then                 -- steigende Flanke am CS
>          data_out <= DST;                  -- Übertragung fertig: Daten
> übergeben
>        end if;
>        DST <= data_in;                     -- neue Daten übernehmen
>      end if;
>

Und vor allem sind die Kommentare nicht vollständig bzw sinnlos und 
unnötig.
Außerdem musst du COPY und PASTE üben.

sclkSR != sclkCS

Gruß Jonas

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

Bewertung
0 lesenswert
nicht lesenswert
Jonas Biensack schrieb:
> sclkSR != sclkCS
Da habe ich mal wirklich saublöde Namen ausgedacht...  :-/

Sinnvollerweise heißen die Signale natürlich sclkSR und csSR, weil es 
jeweils Schieberegister (SR) zum Eintakten und für die Flankenerkennung 
sind. Und dann nenne ich das Daten-Schieberegister auch gleich noch dSR:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity ParalellToSerial is
        
generic( n : integer := 16);
      Port (   
          clk100MHz : in STD_LOGIC;
          SCLK      : in std_logic;
          CS        : in std_logic;
          data_in   : in  STD_LOGIC_VECTOR (n-1 downto 0);
          data_out  : out STD_LOGIC_VECTOR (n-1 downto 0);
          MISO  :  out STD_LOGIC;
          MOSI  :  in STD_LOGIC
         );
end ParalellToSerial;

architecture Behavioral of ParalellToSerial is
        signal dSR     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
        signal csSR    : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
begin

  process begin
     wait until rising_edge(clk100MHz);    -- der einzige Mastertakt für ALLES im ganzen FPGA!
     sclkSR  <= sclkSR(0) & SCLK;          -- Eintakten der
     csSR    <= csSR(0) & CS;              -- asynchronen Signale
   
     if csSR(0)='0' then
       if sclkSR="01" then                 -- steigende Flanke am SCLK
         dSR  <= dSR(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
       end if;
     else
       if csSR="01" then                   -- steigende Flanke am CS
         data_out <= dSR;                  -- Übertragung fertig: Daten übergeben
       end if;
       dSR <= data_in;                     -- neue Daten übernehmen
     end if;
  end process;
  
  -- unabhängig vom Takt: Ausgangstreiber für MISO umschalten
  data_out <= dSR(n-1) when CS = '0' else 'Z';           

end Behavioral;

: Bearbeitet durch Moderator
Autor: Tim R. (mugen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar Miller schrieb:
>
>        if csSR="01" then                   -- steigende Flanke am CS
>          data_out <= dSR;                  
>        end if;
>        dSR <= data_in;                     -- neue Daten übernehmen
>      end if;
> end Behavioral;
> 

Eine Frage, wenn csSR 01 entspricht, dann wird data_in zu data_out 
direkt geschaltet oder nicht? Ich kann mir nicht vorstellen, dass es 
funktioniert. Tut es bei mir auch nicht.

data_out <= dSR;

gegen

dSR <= data_in;

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Kann nicht gehen, weil die Übergabe mit CS ungeschickt gelöst ist. Also 
einen Schritt zurückgetreten und das Original nochmal angeschaut 
(Achtung: jetzt wirds rekursiv!):
http://www.lothar-miller.de/s9y/archives/32-Einfac...

Dann ein klein wenig nachgedacht (!!) und das Nötige geändert (es ist 
ja nur die Umstellung der direkten Flanken- und Pegelabhängigkeit auf 
synchrone eingetaktete Signale). Und heraus kommt dann das hier:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity SPI_Slave is
    Port ( clk    : in  STD_LOGIC;
           SSn    : in  STD_LOGIC;
           SCLK   : in  STD_LOGIC;
           MOSI   : in  STD_LOGIC;
           MISO   : out STD_LOGIC;
           Dout : out  STD_LOGIC_VECTOR (15 downto 0);
           Din  : in  STD_LOGIC_VECTOR (15 downto 0));
end SPI_Slave;

architecture Behavioral of SPI_Slave is
        signal dSR     : STD_LOGIC_VECTOR (15 downto 0):=(others=>'0');
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
        signal ssSR    : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
begin

  sclkSR  <= sclkSR(0) & SCLK when rising_edge(clk); -- Eintakten der
  ssSR    <= ssSR(0) & SSn    when rising_edge(clk); -- asynchronen Signale

  -- Parallel-Eingänge --> MISO
  process begin
     wait until rising_edge(clk);
     if (ssSR="11") then                        -- solange deselektiert: immer Daten vom Din übernehmen
        dsr <= Din;
     elsif (sclkSR="01") then                   -- mit der steigenden SCLK-Flanke 
        dsr <= dsr(dsr'left-1 downto 0) & MOSI; -- wird MOSI eingetaktet
     end if;
  end process;
  
  MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
  
  -- Parallel-Ausgänge übernehmen mit steigender SS-Flanke 
  process begin
     wait until rising_edge(clk);
     if (ssSR="01") then    -- steigende Flanke am SS: Device wird deselektiert
        Dout <= dsr;        -- Ausgangssignale an Dout ausgeben
     end if;
  end process;

end Behavioral;

Das war ja einfach...

Und zusammen mit der Testbench im Anhang kommt dann die Waveform im 
Anhang raus. Voila, funktioniert tadellos (etwas verwirrend ist evtl. 
dass sich nach der letzten steigenden Flanke nochmal der Pegel vom MISO 
ändert, aber das passt schon und ist dem Geiz zuverdanken: es wird nur 1 
Schieberegister für Senden und Empfang verwendet).

: Bearbeitet durch Moderator
Autor: chris (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Mit dem Logikanalysator gemessen zeigt sich bei meinem Aufbau ein 
Fehler.
Miso ändert sich mit der steigenden Flanke statt mit der fallenden.

Hier meine Änderung:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity SPI_Slave is
    Port ( clk      : in  STD_LOGIC;
           SSn      : in  STD_LOGIC;
           SCLK      : in  STD_LOGIC;
           MOSI      : in  STD_LOGIC;
           MISO      : out  STD_LOGIC;
           Dout      : out  STD_LOGIC_VECTOR (15 downto 0);
           Din      : in  STD_LOGIC_VECTOR (15 downto 0);
       newDataFlag  : out  std_logic
       );
end SPI_Slave;

architecture Behavioral of SPI_Slave is
        signal dSR     : STD_LOGIC_VECTOR (15 downto 0):=(others=>'0');
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
        signal ssSR    : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
    signal misoLoc : std_logic;
begin

  sclkSR  <= sclkSR(0) & SCLK when rising_edge(clk); -- Eintakten der
  ssSR    <= ssSR(0) & SSn    when rising_edge(clk); -- asynchronen Signale

  -- Parallel-Eingänge --> MISO
  process begin
     wait until rising_edge(clk);
     if (ssSR="11") then                        -- solange deselektiert: immer Daten vom Din übernehmen
        dsr <= Din;
     elsif (sclkSR="01") then                   -- mit der steigenden SCLK-Flanke 
        dsr <= dsr(dsr'left-1 downto 0) & MOSI; -- wird MOSI eingetaktet
     end if;
   if ( sclkSR="10" ) then -- mit der fallenden Flanke an MISO ausgeben
    misoLoc <= dsr(dsr'left);
   end if;
  end process;
  
  --MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
  MISO <= misoLoc when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
  
  -- Parallel-Ausgänge übernehmen mit steigender SS-Flanke 
  process begin
     wait until rising_edge(clk);
     if (ssSR="01") then    -- steigende Flanke am SS: Device wird deselektiert
        Dout <= dsr;        -- Ausgangssignale an Dout ausgeben
    newDataFlag<='1';
   else
    newDataFlag<='0';
     end if;
  end process;

end Behavioral;



Autor: ElKo (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
chris schrieb:
> Mit dem Logikanalysator gemessen zeigt sich bei meinem Aufbau ein
> Fehler.

Tut mir leid, ich sehe nix. Wo ist denn das Signal MISO?


chris schrieb:
> Miso ändert sich mit der steigenden Flanke statt mit der fallenden.

Stimmt doch gar nicht? Die (RTL-)Simulation sagt, dass alles passt. 
Siehe Anhang. Es gibt ein Delay von einem Takt, was aber durchaus zur 
Beschreibung passt. (Wozu hat Lothar schon eine komplette Testbench 
mundgerecht angehängt, wenn sie doch nicht genommen wird?)

Vermutung: Dein Systemtakt ist nicht groß genug. Der muss mindestens(!) 
2x größer sein, als SCK. Dafür sprechen die unregelmäßigen Flanken von 
SCK.


VG ElKo

Autor: chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
process begin
     wait until rising_edge(clk);
     if (ssSR="11") then                        -- solange deselektiert: immer Daten vom Din übernehmen
        dsr <= Din;
     elsif (sclkSR="01") then                   -- mit der steigenden SCLK-Flanke 
        dsr <= dsr(dsr'left-1 downto 0) & MOSI; -- wird MOSI eingetaktet
     end if;
end process;
  
MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
Auf die Gefahr hin, dass ich mich verhaspelt habe ...
In diesem Codestück von Lothar ist es doch so, dass sich "dsr" mit der 
steigenden Flanke ändert.
MISO hängt außerhalb des Prozesses direkt an "dsr" und ändert sich 
deshalb auch mit der steigenden Flanke, oder?
Meine Messung zeigt das auch. Warum die Simulation nicht?

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

Bewertung
0 lesenswert
nicht lesenswert
chris schrieb:
> Warum die Simulation nicht?
In der Waveform der Simulation meines Codes im 
Beitrag "Re: Erfahrung mit SPI Slave und Spartan 6 FPGA?" ändert sich das 
MISO doch wie erwartet mit der steigenden Taktflanke...


Und die Simulation von ElKo zeigt doch genau das Verhalten, das dein 
Code im Beitrag "Re: Erfahrung mit SPI Slave und Spartan 6 FPGA?" mit
   if ( sclkSR="10" ) then -- mit der fallenden Flanke an MISO ausgeben
    misoLoc <= dsr(dsr'left);
   end if;
  end process;
  
  --MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
  MISO <= misoLoc when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
beschreibt.

Soweit also alles im grünen Bereich...


> Meine Messung zeigt das
Dank den nicht dargestellten "Mastertaktes" könnte sein, dass die zwei 
Takte Verzögerung durch das Flankenschieberegister dazu führen, dass der 
Wechsel erst zusammen mit der nächsten Taktflanke stattfindet. Aber eben 
nicht wegen dieser Taktflanke!

Wie schon gefragt: welche FPGA-Takt- und SCLK-Takt-Frequenzen hast du?

: Bearbeitet durch Moderator
Autor: chris (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
>ändert sich das MISO doch wie erwartet mit der steigenden Taktflanke...

Wenn ich es richtig sehe, sollten sich bei der SPI im Mode0 sollten sich 
die Signal MOSI und MISO bei der fallenden Flanke ändern.


>Wie schon gefragt: welche FPGA-Takt- und SCLK-Takt-Frequenzen hast du?

50MHz/1MHz

Autor: ElKo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
chris schrieb:
> Wenn ich es richtig sehe, sollten sich bei der SPI im Mode0 sollten sich
> die Signal MOSI und MISO bei der fallenden Flanke ändern.

Anders: Die Daten werden auf die steigende SCK-Flanke eingelatcht. Das 
heißt, auf die Flanke muss das Signal stehen. Bis zur nächsten 
steigenden SCK-Flanke muss das neue Bit auf der Leitung liegen. Zu 
welchem Zeitpunkt das auf die Leitung gelegt wird, ist egal. Eine 
Variante ist es, auf die fallende Flanke zu schreiben. Eine andere 
(Lothars) Variante ist, das neue Bit direkt nach der steigenden Flanke 
zu schreiben.

In jedem Fall musst du sicherstellen, dass zur steigenden Taktflanke 
(bei Mode 0) die Daten auf der Leitung sicher anliegen und gelesen 
werden.


VG ElKo

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

Bewertung
0 lesenswert
nicht lesenswert
ElKo schrieb:
> Eine Variante ist es, auf die fallende Flanke zu schreiben.
Das ist die "reine Lehre", die aber nur von sehr wenigen SPI-Devices 
tatsächlich eingehalten wird. Denn dadurch "verschenkt" man quasi die 
halbe Taktfrequenz, weil ja für die Setup-Zeit nur die halbe Bitzeit 
übrig bleibt.

> Eine andere (Lothars) Variante ist, das neue Bit direkt nach
> der steigenden Flanke zu schreiben.
Das ist quasi die "Schieberegister" Variante.
Und auf solchen "verketteten" Schieberegistern basiert ja der SPI(*): 
Daten liegen an und werden mit der nächsten aktiven (= entweder steigend 
oder fallend) Taktflanke weitergeschoben. Sie müssen (wie üblich) 
rechtzeitig vor der nächsten aktiven Taktflanke stabil am nächsten 
Flipflop sein.

(*) siehe http://www.lothar-miller.de/s9y/archives/15-SPI.html

Autor: chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne es jemals genauer zu reflektieren bin ich jetzt jahrelang davon 
ausgegangen, dass man den maximalen Störabstand genau dann erhält, wenn 
man genau auf der Hälfte zwischen den Abtastpunkten das Datensignal 
umschaltet.

Aber vielleicht stimmt das gar nicht und man hat zwei getrennte 
Bedingungen für einen SPI-Slave:
1. Für MOSI könnte gelten, dass man den besten Störabstand erhält, wenn 
der Master genau zwischen den Abtastzeitpunkten umschaltet.
2. Für MISO könnte gelten, dass man den maximalen Störabstand erhält, 
wenn der Slave genau nach der Abtastflanke umschaltet.

Autor: eddy (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ElKo schrieb:
> Vermutung: Dein Systemtakt ist nicht groß genug. Der muss mindestens(!)
> 2x größer sein, als SCK. Dafür sprechen die unregelmäßigen Flanken von
> SCK.

Guter Punkt: Das SCLK-Signal sieht auf den Screenshots schon sehr 
komisch aus.
Meine Vermutung ist eher, dass der Logic-Analyzer, mit dem der 
Screenshot aufgenommen wurde von der Abtastfrequenz nicht ganz hinkommt. 
Man sollte das Timing-Verhalten von MISO zu SCLK mal mit einem 
schnelleren Logic Analyzer oder Oszi aufnehmen.

Autor: Duke Scarring (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
chris schrieb:
> Ohne es jemals genauer zu reflektieren bin ich jetzt jahrelang davon
> ausgegangen, dass man den maximalen Störabstand genau dann erhält, wenn
> man genau auf der Hälfte zwischen den Abtastpunkten das Datensignal
> umschaltet.
Das kann man so pauschal leider nicht sagen. Es hängt auch von der 
Setup- und Holdzeit des Empfängers ab. Es gibt auch Devices mit 
negativer Holdzeit.
Wenn man die Signale über einen Optokoppler schickt, muß man deren 
Latenzen auch noch berücksichtigen (vor allem für das MISO-Signal).

Duke

Autor: ElKo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beispiel aus der Praxis: Spartan 3A Starter Kit (UG330), Ansteuerung DAC 
über SPI, Seite 75

https://www.xilinx.com/support/documentation/board...
> After driving the DAC_CS slave select signal Low,
> the FPGA transmits data on the SPI_MOSI signal,
> MSB first. The LTC2624 captures input data (SPI_MOSI)
> on the rising edge of SPI_SCK; the data must be
> valid for at least 4 ns relative to the rising clock
> edge.

Es wird gefordert, dass das MISO und MOSI mindestens 4 ns um die 
SCK-Flanke herum stabil bleiben müssen. Hier kann es also zu Problemen 
kommen, direkt auf die Flanke auch die neuen Daten zu schreiben. 
(unwahrscheinlich, aber möglich - auf jeden Fall nicht in der 
Spezifikation)

Autor: Weltbester FPGA-Pongo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lothar M. schrieb:
> Vorneweg: CS gehört hier nihct in die Sensitivliste.
Ich glaube, der möchte das CS aynchron beschreiben, was je nach 
Anwendung sinnvoll sein kann, falsch sein kann oder auch Pflicht ist und 
dann gehört es durchaus da rein, wobei der Code dann anders zu 
beschreiben wäre.

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

Bewertung
0 lesenswert
nicht lesenswert
Das hat man jetzt vom Herauskramen alter Threads...  :-/
Der aktuelle beginnt erst beim 
Beitrag "Re: Erfahrung mit SPI Slave und Spartan 6 FPGA?"

Weltbester FPGA-Pongo schrieb im Beitrag #5196420:
> dann gehört es durchaus da rein
In diese (drei Jahre alte) Sensitivliste aber eben nicht.
Wenn mich bei reinstem Sonnenschein einer fragt: "wie ist das Wetter?" 
dann sage ich ja auch "die Sonne scheint!" und nicht "die Sonne scheint, 
es hätte aber genausogut regnen können, wenn die Wetterlage entsprechend 
wäre"...  ;-)

: Bearbeitet durch Moderator

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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.