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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Andi P. (jamaram90)


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:
1
Xst:3002 - This design contains one or more registers/latches that are directly
2
   incompatible with the Spartan6 architecture. The two primary causes of this is
3
   either a register or latch described with both an asynchronous set and
4
   asynchronous reset, or a register or latch described with an asynchronous
5
   set or reset which however has an initialization value of the opposite 
6
   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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use ieee.std_logic_unsigned.all;
4
5
6
entity ParalellToSerial is
7
        
8
generic( n : integer := 16);
9
      Port (   
10
          reset   : in STD_LOGIC;
11
          sclk    : in std_logic;
12
          CS     : in std_logic;
13
          data_in   : in STD_LOGIC_VECTOR (n-1 downto 0);
14
          
15
          data_out  :  out STD_LOGIC
16
         );
17
end ParalellToSerial;
18
19
architecture Behavioral of ParalellToSerial is
20
        signal DST     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
21
        signal DATA    : STD_LOGIC := '0';
22
23
begin
24
25
process(reset,sclk, CS)
26
       
27
 begin
28
    
29
    if reset = '1' then
30
        
31
        DST  <= (others => '0');
32
         DATA <= '0';
33
              
34
    elsif rising_edge(sclk) then
35
    
36
      if CS = '0' then
37
                   
38
        DATA <= DST(n-1);            
39
            DST  <= DST(n-2 downto 0) & '0'; 
40
                      
41
      else
42
                        
43
        DST <= data_in;
44
        
45
      end if;
46
      end if;
47
end process;
48
       
49
     data_out <= DATA;
50
51
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
von Christian R. (supachris)


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.

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
entity ParalellToSerial is
5
        
6
generic( n : integer := 16);
7
      Port (   
8
          clk100MHz : in STD_LOGIC;
9
          sclk      : in std_logic;
10
          CS        : in std_logic;
11
          data_in   : in  STD_LOGIC_VECTOR (n-1 downto 0);
12
          data_out  : out STD_LOGIC_VECTOR (n-1 downto 0);
13
          MISO  :  out STD_LOGIC;
14
          MOSI  :  in STD_LOGIC
15
         );
16
end ParalellToSerial;
17
18
architecture Behavioral of ParalellToSerial is
19
        signal DST     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
20
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
21
        signal sclkCS  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
22
begin
23
24
  process begin
25
     wait until rising_edge(clk100MHz);    -- der einzige Mastertakt für ALLES im ganzen FPGA!
26
     sclkSR  <= sclkSR(0) & sclk;
27
     sclkCS  <= sclkCS(0) & CS;
28
   
29
     if CS = '0' then
30
       if sclkSR="01" then                 -- steigende Flanke am SCLK
31
         DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
32
       end if;
33
     else
34
       if sclkSR="01" then                 -- steigende Flanke am CS
35
         data_out <= DST;                  -- Übertragung fertig: Daten übergeben
36
       end if;
37
       DST <= data_in;                     -- neue Daten übernehmen
38
     end if;
39
  end process;
40
  
41
  -- Ausgangstreiber für MISO umschalten
42
  data_out <= DST(n-1) when CS = '0' else 'Z';           
43
44
end Behavioral;

: Bearbeitet durch Moderator
von bit blaser (Gast)


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.

von Andi P. (jamaram90)


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

von Andi P. (jamaram90)


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!

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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...

von Andi P. (jamaram90)


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?

von Christian R. (supachris)


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.

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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
von Andi P. (jamaram90)


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.

von Andi P. (jamaram90)


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.

von Christian R. (supachris)


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
von Lothar M. (lkmiller) (Moderator) Benutzerseite


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?

von Andi P. (jamaram90)


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.

von Andi P. (jamaram90)


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!

von Thorsten F. (tfol)


Lesenswert?

Lothar Miller schrieb:
>
1
> library IEEE;
2
> use IEEE.STD_LOGIC_1164.ALL;
3
> 
4
> entity ParalellToSerial is
5
> 
6
> generic( n : integer := 16);
7
>       Port (
8
>           clk100MHz : in STD_LOGIC;
9
>           sclk      : in std_logic;
10
>           CS        : in std_logic;
11
>           data_in   : in  STD_LOGIC_VECTOR (n-1 downto 0);
12
>           data_out  : out STD_LOGIC_VECTOR (n-1 downto 0);
13
>           MISO  :  out STD_LOGIC;
14
>           MOSI  :  in STD_LOGIC
15
>          );
16
> end ParalellToSerial;
17
> 
18
> architecture Behavioral of ParalellToSerial is
19
>         signal DST     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
20
>         signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
21
>         signal sclkCS  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
22
> begin
23
> 
24
>   process begin
25
>      wait until rising_edge(clk100MHz);    -- der einzige Mastertakt für 
26
> ALLES im ganzen FPGA!
27
>      sclkSR  <= sclkSR(0) & sclk;
28
>      sclkCS  <= sclkCS(0) & CS;
29
> 
30
>      if CS = '0' then
31
>        if sclkSR="01" then                 -- steigende Flanke am SCLK
32
>          DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
33
>        end if;
34
>      else
35
>        if sclkSR="01" then                 -- steigende Flanke am CS
36
>          data_out <= DST;                  -- Übertragung fertig: Daten 
37
> übergeben
38
>        end if;
39
>        DST <= data_in;                     -- neue Daten übernehmen
40
>      end if;
41
>   end process;
42
> 
43
>   -- Ausgangstreiber für MISO umschalten
44
>   data_out <= DST(n-1) when CS = '0' else 'Z';
45
> 
46
> end Behavioral;
47
>

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

von berndl (Gast)


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)

von berndl (Gast)


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...

von Thorsten F. (tfol)


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

von berndl (Gast)


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...

von Thorsten F. (tfol)


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

von berndl (Gast)


Lesenswert?

genau so

von Thorsten F. (tfol)


Lesenswert?

Lothar Miller schrieb:
>
1
>      if CS = '0' then
2
>        if sclkSR="01" then                 -- steigende Flanke am SCLK
3
>          DST  <= DST(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
4
>        end if;
5
>      else
6
>        if sclkSR="01" then                 -- steigende Flanke am CS
7
>          data_out <= DST;                  -- Übertragung fertig: Daten 
8
> übergeben
9
>        end if;
10
>        DST <= data_in;                     -- neue Daten übernehmen
11
>      end if;
12
>

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

von Tim R. (mugen)


Lesenswert?

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

Die Zeile
1
 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.

von Jonas B. (jibi)


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

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
4
entity ParalellToSerial is
5
        
6
generic( n : integer := 16);
7
      Port (   
8
          clk100MHz : in STD_LOGIC;
9
          SCLK      : in std_logic;
10
          CS        : in std_logic;
11
          data_in   : in  STD_LOGIC_VECTOR (n-1 downto 0);
12
          data_out  : out STD_LOGIC_VECTOR (n-1 downto 0);
13
          MISO  :  out STD_LOGIC;
14
          MOSI  :  in STD_LOGIC
15
         );
16
end ParalellToSerial;
17
18
architecture Behavioral of ParalellToSerial is
19
        signal dSR     : STD_LOGIC_VECTOR (n-1 downto 0):=(others=>'0');
20
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
21
        signal csSR    : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
22
begin
23
24
  process begin
25
     wait until rising_edge(clk100MHz);    -- der einzige Mastertakt für ALLES im ganzen FPGA!
26
     sclkSR  <= sclkSR(0) & SCLK;          -- Eintakten der
27
     csSR    <= csSR(0) & CS;              -- asynchronen Signale
28
   
29
     if csSR(0)='0' then
30
       if sclkSR="01" then                 -- steigende Flanke am SCLK
31
         dSR  <= dSR(n-2 downto 0) & MOSI; -- Daten ins SR einlesen
32
       end if;
33
     else
34
       if csSR="01" then                   -- steigende Flanke am CS
35
         data_out <= dSR;                  -- Übertragung fertig: Daten übergeben
36
       end if;
37
       dSR <= data_in;                     -- neue Daten übernehmen
38
     end if;
39
  end process;
40
  
41
  -- unabhängig vom Takt: Ausgangstreiber für MISO umschalten
42
  data_out <= dSR(n-1) when CS = '0' else 'Z';           
43
44
end Behavioral;

: Bearbeitet durch Moderator
von Tim R. (mugen)


Lesenswert?

Lothar Miller schrieb:
>
1
>        if csSR="01" then                   -- steigende Flanke am CS
2
>          data_out <= dSR;                  
3
>        end if;
4
>        dSR <= data_in;                     -- neue Daten übernehmen
5
>      end if;
6
> end Behavioral;
7
>

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;

von Lothar M. (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

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-Einfacher-SPI-Slave.html

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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity SPI_Slave is
6
    Port ( clk    : in  STD_LOGIC;
7
           SSn    : in  STD_LOGIC;
8
           SCLK   : in  STD_LOGIC;
9
           MOSI   : in  STD_LOGIC;
10
           MISO   : out STD_LOGIC;
11
           Dout : out  STD_LOGIC_VECTOR (15 downto 0);
12
           Din  : in  STD_LOGIC_VECTOR (15 downto 0));
13
end SPI_Slave;
14
15
architecture Behavioral of SPI_Slave is
16
        signal dSR     : STD_LOGIC_VECTOR (15 downto 0):=(others=>'0');
17
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
18
        signal ssSR    : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
19
begin
20
21
  sclkSR  <= sclkSR(0) & SCLK when rising_edge(clk); -- Eintakten der
22
  ssSR    <= ssSR(0) & SSn    when rising_edge(clk); -- asynchronen Signale
23
24
  -- Parallel-Eingänge --> MISO
25
  process begin
26
     wait until rising_edge(clk);
27
     if (ssSR="11") then                        -- solange deselektiert: immer Daten vom Din übernehmen
28
        dsr <= Din;
29
     elsif (sclkSR="01") then                   -- mit der steigenden SCLK-Flanke 
30
        dsr <= dsr(dsr'left-1 downto 0) & MOSI; -- wird MOSI eingetaktet
31
     end if;
32
  end process;
33
  
34
  MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
35
  
36
  -- Parallel-Ausgänge übernehmen mit steigender SS-Flanke 
37
  process begin
38
     wait until rising_edge(clk);
39
     if (ssSR="01") then    -- steigende Flanke am SS: Device wird deselektiert
40
        Dout <= dsr;        -- Ausgangssignale an Dout ausgeben
41
     end if;
42
  end process;
43
44
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
von chris (Gast)


Angehängte Dateien:

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:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.NUMERIC_STD.ALL;
4
5
entity SPI_Slave is
6
    Port ( clk      : in  STD_LOGIC;
7
           SSn      : in  STD_LOGIC;
8
           SCLK      : in  STD_LOGIC;
9
           MOSI      : in  STD_LOGIC;
10
           MISO      : out  STD_LOGIC;
11
           Dout      : out  STD_LOGIC_VECTOR (15 downto 0);
12
           Din      : in  STD_LOGIC_VECTOR (15 downto 0);
13
       newDataFlag  : out  std_logic
14
       );
15
end SPI_Slave;
16
17
architecture Behavioral of SPI_Slave is
18
        signal dSR     : STD_LOGIC_VECTOR (15 downto 0):=(others=>'0');
19
        signal sclkSR  : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
20
        signal ssSR    : STD_LOGIC_VECTOR (1 downto 0):=(others=>'0');
21
    signal misoLoc : std_logic;
22
begin
23
24
  sclkSR  <= sclkSR(0) & SCLK when rising_edge(clk); -- Eintakten der
25
  ssSR    <= ssSR(0) & SSn    when rising_edge(clk); -- asynchronen Signale
26
27
  -- Parallel-Eingänge --> MISO
28
  process begin
29
     wait until rising_edge(clk);
30
     if (ssSR="11") then                        -- solange deselektiert: immer Daten vom Din übernehmen
31
        dsr <= Din;
32
     elsif (sclkSR="01") then                   -- mit der steigenden SCLK-Flanke 
33
        dsr <= dsr(dsr'left-1 downto 0) & MOSI; -- wird MOSI eingetaktet
34
     end if;
35
   if ( sclkSR="10" ) then -- mit der fallenden Flanke an MISO ausgeben
36
    misoLoc <= dsr(dsr'left);
37
   end if;
38
  end process;
39
  
40
  --MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
41
  MISO <= misoLoc when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
42
  
43
  -- Parallel-Ausgänge übernehmen mit steigender SS-Flanke 
44
  process begin
45
     wait until rising_edge(clk);
46
     if (ssSR="01") then    -- steigende Flanke am SS: Device wird deselektiert
47
        Dout <= dsr;        -- Ausgangssignale an Dout ausgeben
48
    newDataFlag<='1';
49
   else
50
    newDataFlag<='0';
51
     end if;
52
  end process;
53
54
end Behavioral;

von ElKo (Gast)


Angehängte Dateien:

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

von chris (Gast)


Lesenswert?

1
process begin
2
     wait until rising_edge(clk);
3
     if (ssSR="11") then                        -- solange deselektiert: immer Daten vom Din übernehmen
4
        dsr <= Din;
5
     elsif (sclkSR="01") then                   -- mit der steigenden SCLK-Flanke 
6
        dsr <= dsr(dsr'left-1 downto 0) & MOSI; -- wird MOSI eingetaktet
7
     end if;
8
end process;
9
  
10
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?

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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
1
   if ( sclkSR="10" ) then -- mit der fallenden Flanke an MISO ausgeben
2
    misoLoc <= dsr(dsr'left);
3
   end if;
4
  end process;
5
  
6
  --MISO <= dsr(dsr'left) when SSn='0' else 'Z';  -- Richtungsteuerung MISO direkt über SSn
7
  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
von chris (Gast)


Angehängte Dateien:

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

von ElKo (Gast)


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

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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

von chris (Gast)


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.

von eddy (Gast)


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.

von Duke Scarring (Gast)


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

von ElKo (Gast)


Lesenswert?

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

https://www.xilinx.com/support/documentation/boards_and_kits/ug330.pdf
> 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)

von Weltbester FPGA-Pongo (Gast)


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.

von Lothar M. (lkmiller) (Moderator) Benutzerseite


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]
  • [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.