Hallo zusammen,
ich habe gerade versucht das SPI1-Modul des STM32F103ZE in Betrieb zu
nehmen. Das SPI1 Modul soll im Masterbetrieb, Full Duplex, mit maximaler
Taktrate arbeiten. Um das /CS Signal kümmert sich die Software.
Nachfolgend ist die Sende-/Empfangsfunktion der SPI-Schnittstelle:
1
voidspi_xfer(char*data,intsize)
2
{
3
inti;
4
CLEAR_CS();
5
for(i=0;i<size;i++)
6
{
7
SPI1->DR=*(data+i);
8
while((SPI1->SR&SPI_SR_TXE)==0x00000000);
9
while((SPI1->SR&SPI_SR_RXNE)==0x00000000);
10
*(data+i)=SPI1->DR;
11
}
12
SET_CS();
13
}
14
15
intmain(void)
16
{
17
inti;
18
charbuffer[1024];
19
20
init_gpio();
21
init_spi();
22
23
while(1)
24
{
25
for(i=0;i<1000;i++)spi_xfer(buffer,1024);
26
TOGGLE_LED();
27
}
28
}
Grundsätzlich funktioniert die Schnittstelle und die Kommunikation über
diese mit einer Gegenstelle. Aus diesem Grund gehe ich davon aus, dass
alles korrekt initialisiert ist. Alle Daten sind korrekt, wenn ich die
Schnittstelle jedoch intensiv nutze, z.B. wenn in einer Endlosschleife
jeweils 1kBytes über SPI gesendet bzw. empfangen werden passiert
folgendes:
- die spi_xfer Funktion braucht nach einer Zeit länger als zu Beginn, da
sehr lang auf das RXNE-Flag gewartet wird,
- gelegentlich kommt das RXNE-Flag garnicht, so dass die Funktion hängen
bleibt und der Controller neu gestartet werden muss,
- beim Step-By-Step Debuggen durch die spi_xfer-Funktion bleibt der
Debugger in der while-RXNE-Schleife hängen, da das Flag nie gesetzt
wird. Mit dem Debugger lässt sich ein gesetztes RXNE-Flag nie sehen,
selbst wenn die Daten nicht aus dem SPI1->DR Register gelesen werden.
- setzt man eine kleine Verzögerung zwischen dem Senden und dem Warten
auf das RXNE-Flag, so bleibt die Funktion beim Warten auf das Flag
hängen.
Es scheint als würde das RXNE-Flag sehr zufällig gesetzt werden (bei
einer hohen Auslastung später als erwartet) und von alleine wieder
zurückgesetzt werden, obwohl dies laut Datenblatt nur durch das Auslesen
des SPI1->DR Registers geschehen sollte.
Sieht jemand was ich falsch mache? Hat/hatte schon jemand das gleiche
Problem bzw. kann das Problem nachgestellt werden?
Liebe Grüße,
Tim
Ich habe den Fehler soeben mit großer Wahrscheinlichkeit selber
gefunden.
Für die Übertragung eines einzigen Bytes ist die oben beschriebene
Funktion richtig, wenn man jedoch einen Datenstream übertragen will muss
die Funktion aufgrund der Sende-/Empfangsbuffer etwas anders aussehen.
Deutlich wird das durch das Reference Manual:
http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/REFERENCE_MANUAL/CD00171190.pdf
Kapitel 25.3.5, bzw. Abbildung 239.
Hier mal die neue Variante der spi_xfer-Routine. Ich habe diese leider
noch nicht testen können, werde dies aber noch tun und eine Rückmeldung
geben, wenn die Funktion nicht tut, was sie soll.
1
voidspi_xfer(char*data,intsize)
2
{
3
inti=0;
4
CLEAR_CS();
5
SPI1->DR=*(data+0);
6
7
while(i<size-1)
8
{
9
while((SPI1->SR&SPI_SR_TXE)==0x00000000);
10
SPI1->DR=*(data+i+1);
11
while((SPI1->SR&SPI_SR_RXNE)==0x00000000);
12
*(data+i)=SPI1->DR;
13
i++;
14
}
15
16
while((SPI1->SR&SPI_SR_RXNE)==0x00000000);
17
*(data+i)=SPI1->DR;
18
SET_CS();
19
}
Ich hoffe das hilft allen, die ggf. auf das gleiche Problem stoßen.
Liebe Grüße,
Tim
Leider besteht das Problem auch weiterhin, irgendwann nach x Bytes wird
das RXNE-Flag vom Controller nicht gesetzt und die Kommunikation steht
still.
Hat jemand noch eine Idee?
Grundsätzlich funktioniert das so wie du es machst.
Also
1
while((SPI1->SR&SPI_SR_TXE)==0x00000000);
2
SPI1->DR=*(data+i+1);
3
while((SPI1->SR&SPI_SR_RXNE)==0x00000000);
4
*(data+i)=SPI1->DR;
Wenn dein SPI sich irgendwann aufhängt könnte das daran
liegen das dein Zugriff auf
*(data+i)
evtl. ins Nirvana zeigt. Also auf einen RAM Bereich den
es nicht gibt. Dann hüpft der STM in einen Fault Handler.
Ja, an so etwas habe ich anfangs auch gedacht, ich habe dies allerdings
inzwischen mehrmals überprüft, ich übergebe einen Pointer auf einen
globalen Puffer mit 1024 Bytes, und als size übergebe ich 1024.
Ich bin inzwischen leider ziemlich sicher, dass das nicht das Problem
ist. Leider aus dem Grund, da ich sonst eine Lösung des Problems hätte.
Dazu kommt, dass der STM32 definitiv in der Warteschleife auf das
RXNE-Flag wartet, wenn ich diesen mit dem Debugger anhalte.
Ich habe das ganze jetzt noch einfacher gestaltet:
1
while(1)
2
{
3
while(!(SPI1->SR&SPI_SR_TXE));
4
SPI1->DR=0xFF;
5
while(!(SPI1->SR&SPI_SR_RXNE));
6
byte=SPI1->DR;
7
counter++;
8
}
Nur um noch einmal daran zu erinnern, die Initialisierung funktioniert,
da ich grundsätzlich auch über SPI mit einer Gegenstelle kommunizieren
kann. Das Problem ist, dass sich selbst der einfache Beispielcode nach
wenigen Sekunden aufhängt, da das RXNE-Flag nicht mehr gesetzt wird...
Weitere Ideen? Ich weiss leider nicht mehr weiter. Mich würde
interessieren, ob jemand anderes ein ähnliches Verhalten bekommt, u.U.
auch bei einem anderen STM32.
Liebe Grüße
>Dazu kommt, dass der STM32 definitiv in der Warteschleife auf das>RXNE-Flag wartet, wenn ich diesen mit dem Debugger anhalte.
Und was passiert wenn du ihn NICHT mit dem Debugger anhältst?
Lass da mal ne LED blinken.
Ich arbeite schon lange mit STM32F103VBT6 und übertrage rund um
die Uhr Daten über SPI. Das SPI Modul ist nicht buggy.
Auch im laufenden betrieb ohne Debugger mit einer blinkenden LED ist das
Problem zu sehen. Die LED macht irgendwann nichts mehr.
Das SPI_SR_RXNE kommt aus einem Header-File mit allen Definitionen des
Controllers, unabhängig von der ST Library. Aber auch diese habe ich
überprüft. Gleiches Problem habe ich übrigens auch mit den Definitionen
der ST Library, die ich in einem anderen Projekt mal eingesetzt habe.
Ja, ich habe auch nicht gedacht, dass das SPI buggy ist. Es fällt auch
garnicht auf, wenn nur vereinzelt Daten übertragen werden. Wenn man aber
durchweg Daten überträgt, so dass das SPI auf Dauer sehr gut ausgelastet
ist, hängt sich mein Controller auf, da das RXNE-Flag nicht gesetzt
wird.
Funktioniert bei dir das dauerhafte Senden und Empfangen von Daten in
einer Schleife?
Mit dem Debugger kann ich selbst dann kein gesetztes RXNE-Flag sehen,
wenn ich das Datenregister nach dem Senden nicht auslese. In diesem Fall
sollte das Flag doch definitiv gesetzt sein, bis das Datenregister
ausgelesen wird.
Unter Umständen habe ich bei meinem STM32F103ZE eine Revision erwischt,
die nicht ganz fehlerfrei ist. So ist zumindest meine Vermutung im
Moment.
Ich arbeit mit demselben Typ wie Holger auch - keine Probleme mit dem
SPI bei 4,5MHz (mehr macht das EEPROM nicht mit). Allerdings nicht mit
der ST-Lib.
Schon mal mit dem Oszi die Signale (CS,CLK,MISO,MOSI)angeschaut? Es
könnte auch die Initialisierung falsch sein,und das Ganze trotzdem kurz
werkeln.
Grüsse