Hallo!
Ich versuche mich an einer SPI Kommunkation zwischen 2 STM32F103 Boards.
Dabei kann ich mit dem Master senden, und dem Slave empfangen. Weiter
als das komme ich jedoch nicht. Ich habe versucht mich in die Register
einzulesen und es scheint mir richtig zu sein. Jedoch kann ich mit dem
Slave nichts senden, MISO bleibt einfach HIGH.
Dabei habe ich die Grundstruktur mit CubeMX erzeugt.
Die Slave while Schleife sieht folgendermaßen aus:
Warum benutzt du die direkten Register Zugriffe?
HAL hat für alles so schöne Funktionen.
Wenn du wissen willst was mit den Registern passiert,
lass dir diese Funktionen einfach anzeigen.
Ein Beispiel für alle Arten der SPI Übertragung findet sich unter:
STM32Cube_FW_F1_V1.6.1/Projects/STM32F103RB-Nucleo/Examples/SPI/
Alleine HAL_SPI_TransmitReceive(..) hat knapp 200 Zeilen, prinzipiell
geht SPI auch kürzer, vor allem wenn ich eigentlich nur 1 byte abfragen
möchte.
Unabhängig davon, habe ich bereits die HAL Funktionen probiert, und
komme exakt genauso weit.
Naja so wie ich es im Datenblatt verstehe, steuere ich bei NSS Software
das Chipselect über ein SSI Bit, was ich widerum low setze am Anfang und
wieder high am Ende.
CS high dient nur um in der while Schleife den Slave Transceive Block
auszulösen.
[c]
SPI2->CR1 &= ~(1UL << 8);
[\c]
Bit 8SSI: Internal slave select
This bit has an effect only when the SSM bit is set. The value of this
bit is forced onto the NSS pin and the IO value of the NSS pin is
ignored.
Und zu Bit 9:
"When the SSM bit is set, the NSS pin input is replaced with the value
from the SSI bit."
D.h. Dein Slave-SPI ist freigegeben, wenn Du nichts sendest (Low) und
wenn Du sendest, deaktivierst Du sie sauber (HIGH) ;-)
Die Polarität lässt sich mWn auch nicht ändern. Das ließ mich neulich
etwas grübeln, weil ich die SPI über invertierende H11L1-Optokoppler
führen wollte, aber glücklicherweise konnte mein Master (Raspberry) das
CS-Signal invertiert ausgeben :-)
P.S.: Ich mag den ganzen HAL-Kram auch nicht mehr - die gesamte
Schnittstelle kann man mit zwei Zeilen viel übersichtlicher
konfigurieren.
Ja das mit CS war auch so gemeint. Ich versteh das schon so das wenn SSM
gesetzt ist, ich quasi ein externes NSS Signal durch SSI ersetze...
Das SSM und SSI setze ich ja vor der while Schleife auf 1, und erst nach
der Abfrage ob mein Transmit leer ist, setze ich es auf 0 und beschreibe
das DataRegister. Hier würde ich ja nun eine Regung auf MISO
erwarten....
Das CS High kommt nur von einem Pin mit dem ich das Ganze überhaupt
starte. Da ich ja durch SOFTNSS nun keinen Start mehr mit polling
bekomme.
Oder ist das Verständnis hier nicht ganz richtig?
Anton Weiss schrieb:> Ja das mit CS war auch so gemeint. Ich versteh das schon so das wenn SSM> gesetzt ist, ich quasi ein externes NSS Signal durch SSI ersetze...>> Das SSM und SSI setze ich ja vor der while Schleife auf 1, und erst nach> der Abfrage ob mein Transmit leer ist, setze ich es auf 0 und beschreibe> das DataRegister. Hier würde ich ja nun eine Regung auf MISO> erwarten....
Ah ok.
Aber wenn Du NSS anfangs vor der While-Schleife auf 1 setzt und damit
die Schnittstelle abkoppelst/deaktivierst - warum sollte die
SPI-Schnittstelle dann danach irgendetwas im Statusregister ändern?
Solange NSS auf 1 ist, macht die SPI nix - dann wird weder geschoben
noch irgendein Statusbit gesetzt. So habe ich das jedenfalls verstanden.
NSS musst Du während der gesamten Zeit aktiv (Low) halten, also noch
bevor irgendetwas vom Master kommt.
Wieso überlässt Du das eigentlich nicht dem Master? Der weiss, was gut
für seinen Sklaven ist ;-)
Weil ich bei HardwareNSS keine Regung gesehen hab. Und der Softwareteil
eigentlich genauso gehen sollte.
Bei den Projektbeispielen hab ich dann stattdessen das Problem das
HAL_SPI_TransmitReceive erstmal in den HAL_Delay geht und nie wieder
kommt.
Anton Weiss schrieb:> Weil ich bei HardwareNSS keine Regung gesehen hab. Und der Softwareteil> eigentlich genauso gehen sollte.
Ja, aber wohl nur, wenn man NSS dann auch auf 0 zieht.
Und vermutlich muss dies auch rechtzeitig geschehen, da der SPI-Takt ja
deutlich unter dem Prozessortakt liegt.
> Bei den Projektbeispielen hab ich dann stattdessen das Problem das> HAL_SPI_TransmitReceive erstmal in den HAL_Delay geht und nie wieder> kommt.
Ich mache das lieber immer direkt nach der Registerbeschreibung. Für die
STMF0 gibt es auch so schöne Beispiele ganz ohne StdLib und HAL im
Reference Manual. Leider gibt es die ab F1 aufwärts nicht (nennt sich
"STM32SnippetsF0") :-/
Hier ist der Code meines Slaves (BluePill, also auch STM32F103, Master
ist ein Raspberry über galvanische Trennung. Die Ein-/Ausgänge müssen
natürlich vorher gesetzt werden):
1
// SPI als Slave initialisieren:
2
SPI->CR2=0;
3
// Hardware-NSS aktivieren, unidirektional, Slave, 8 Bit, SPI aktivieren, CPOL und CPHA auf Null (steigende erste Flanke)
4
SPI->CR1=SPI_CR1_SPE;
5
6
// Hauptschleife
7
while(1)
8
{
9
// Warte auf gefüllten SPI-Empfangspuffer
10
while((SPI->SR&SPI_SR_RXNE)==0)
11
{
12
// Währenddessen werte A/D-Eingänge aus:
13
// Wenn die Wandlung beendet ist, speichere diese ab
14
if(ADC1->SR&ADC_SR_EOC)
15
{
16
// Speichere Wert in Zwischenspeicher
17
adc[nr]=ADC1->DR;
18
// Starte neue Wandlung
19
ADC1->CR2|=ADC_CR2_ADON;
20
// Wähle nächsten Zwischenspeicher
21
if(nr<5)nr++;elsenr=0;
22
}
23
}
24
25
// Lese Byte aus
26
cmd=SPI->DR;
27
28
// Wenn wir ein Dummybyte empfangen, mache nichts (= nur Ausgabe eines Datenbytes)
29
if(cmd==0xFF)
30
{
31
// Wenn wir einen ADC-Wert auslesen, schiebe noch das High-Byte nach
32
if(mode)
33
{
34
SPI->DR=tmp;
35
mode=0;
36
}
37
continue;
38
}
39
...
40
}
Da ist NSS aber eben hardwarebasierend.
Ich warte also jeweils auf einen gefüllten Empfangspuffer, lese und
werte diesen "Befehl" dann aus und packe die Antwort des Slaves dann in
SPI->DR (falls es eine Antwort gibt). Der Master schiebt dann noch ein
Dummy-Byte nach und holt sich so die Antwort. Bei 12-Bit-A/D-Werten
benötigt man natürlich zwei Bytes (wie oben im Code angedeutet ist).
BTW: Du solltest beim Setzen von Registerbits immer auf die Definitionen
in der stm32f3xx.h zurückgreifen anstatt irgendwelche Zahlen zu
schieben, sonst wird das Ganze sehr unübersichtlich (und fehleranfällig)
Sieht gut aus, es funktioniert nun.
Ich habe MOSI auf Input und MISO auf PushPull gesetzt.. Beides beim
Slave logischerweise. Ist mir bei den CubeMX Examples nicht aufgefallen
das es dort passiert ist. Aus dem Datenblatt ist mir das nicht
ersichtlich geworden, da scheinbar PushPull auch empfangen kann, aber
Input nicht senden.
Hardware NSS funktioniert nun auch beim Slave. Master läuft noch mit
HAL.
Vielen dank an der Stelle schonmal.
Anton W. schrieb:> Sieht gut aus, es funktioniert nun.>> Ich habe MOSI auf Input und MISO auf PushPull gesetzt.. Beides beim> Slave logischerweise.> Ist mir bei den CubeMX Examples nicht aufgefallen> das es dort passiert ist. Aus dem Datenblatt ist mir das nicht> ersichtlich geworden, da scheinbar PushPull auch empfangen kann, aber> Input nicht senden.
Jepp, so habe ich die Pins meines Slaves auch konfiguriert: PP und AF
bei SCK und MISO, "floating in" bei MOSI.
> Hardware NSS funktioniert nun auch beim Slave. Master läuft noch mit> HAL.>> Vielen dank an der Stelle schonmal.
Gerne. Passte halt gerade wirklich gut, weil ich das letzte Woche alles
selbst "durchgemacht" habe ;-)