Forum: Mikrocontroller und Digitale Elektronik Bug im STM32F103ZE SPI-Modul?


von Tim S (Gast)


Lesenswert?

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
void spi_xfer(char* data, int size)
2
{
3
    int i;
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
int main(void)
16
{
17
    int i;
18
    char buffer[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

von Tim S (Gast)


Lesenswert?

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
void spi_xfer(char* data, int size)
2
{
3
    int i=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

von Tim S (Gast)


Lesenswert?

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?

von holger (Gast)


Lesenswert?

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.

von Tim S (Gast)


Lesenswert?

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

von holger (Gast)


Lesenswert?

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

von holger (Gast)


Lesenswert?

Wo kommt das hier eigentlich her?

SPI_SR_RXNE

laut StandardPeripheral Lib heisst das

SPI_I2S_FLAG_RXNE

von Tim S (Gast)


Lesenswert?

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.

von Arne (Gast)


Lesenswert?

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.

von Gebhard R. (Firma: Raich Gerätebau & Entwicklung) (geb)


Lesenswert?

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.