Forum: Mikrocontroller und Digitale Elektronik STM32 SPI Interrupt Ringpuffer verliert Zeichen


von J. S. (grooc)


Lesenswert?

Hallo ich habe Probleme mit einem SPI Ringpuffer für den STM32F103. Das 
Senden und Empfangen funktioniert ohne Interrupt. Auch mit einem 
Interrupt funktioniert es. In dieser Implementation mit Ringpuffer wird 
der letzte Wert nicht empfangen. Also zum Beispiel sende ich 6 Zeichen 
empfange aber nur 5. Wenn ich im nachhinein schaue, ist das 
SPI_I2S_FLAG_RXNE Bit sogar gesetzt, ich bekomme jedoch keinen 
Interrupt. Wieso nicht? Seltsam ist, dass wenn ich
1
SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
auskommentiere nichts mehr funktioniert.

Habt ihr eine Idee hier ist meine ISR, vielleicht sehr ihr ja was da 
falsch läuft.
Danke
1
void SPI2_IRQHandler(void){
2
3
  // Receive
4
  if(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == SET){
5
    
6
    if(inCurrent != bufferPos){
7
      // Data in Receive Buffer
8
      inBuffer[inCurrent] = SPI2->DR; // save data
9
      inCurrent = (inCurrent + 1) % FLA_BUFFER_SIZE;
10
11
    }else{ // all data received  disable RX Interrupt
12
      SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE | SPI_I2S_IT_RXNE, DISABLE);
13
    }
14
    SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_RXNE);
15
    DEBUG_YELLOW_OFF;
16
    
17
  // Transmit
18
  }else if(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == SET){
19
    
20
    DEBUG_YELLOW_ON;
21
    if(outCurrent != bufferPos){ // Transmit buffer contains data to send
22
      SPI2->DR = outBuffer[outCurrent]; // send data
23
      outCurrent = (outCurrent + 1) % FLA_BUFFER_SIZE;
24
    }else{ // Transmit buffer empty
25
      SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE, DISABLE);
26
    }
27
    SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_TXE);
28
  }
29
}

von Frank L. (frank_l)


Lesenswert?

Wie groß ist Dein Ringbuffer und welchen Wert hat bufferPos?

Gruß
Frank

von J. S. (grooc)


Lesenswert?

mein Ringpuffer ist 16 Zeichen lang. Ich schreibe in einem Beispel 6 
Zeichen und bekomme über SPI nur 5 zurück. Gleiches passiert, wenn ich 
nur ein Zeichen sende. Dann bekomme ich kein Zeichen zurück.

Die Variable bufferPos gibt die aktuelle Position des Schreibzeigers an. 
Also wenn ich Daten senden will erhöht sich bufferPos. Wenn sie gesendet 
wurden, rückt outCurrent nach und wenn ich ein Zeichen zurück bekomme, 
wird inCurrent erhöht.

von Frank L. (frank_l)


Lesenswert?

Da ich nicht weiss, wo Du und wie bufferPos veränderst, würde ich 
trotzdem sagen, dass Deine Prüfung if(outCurrent != bufferPos) falsch 
ist. So wie es für mich aussieht, müßte es if(outCurrent == bufferPos)
 Gruß
Frank

von Jens Schröder (Gast)


Lesenswert?

Also nochmal zu bufferPos:
Wenn xxxCurrent noch nicht gleich bufferPos, dann existieren noch Daten, 
die gesendet, empfangen werden. Wenn es gleich ist (else) wurde alles 
gesendet/empfangen. Ist doch egal wie rum man es dreht ... oder etwa 
nicht? :/
1
||||||||||||||||||||| ... |||| <- Daten
2
       |  |         |
3
       |  |         bufferPos
4
       |  |         
5
       |  outCurrent         
6
       |  
7
       inCurrent
Wenn Daten hinzukommen wird auch bufferPos erhöht. outCurrent und 
inCurrent werden erst erhöht, wenn Daten gesendet/empfangen wurden.

von Frank L. (frank_l)


Lesenswert?

Sorry, ich sehe nur das inCurrent und outCurrent verändert werden.
Wo bufferPos geändert wird sagt mir selbst meine Glaskugel nicht.

So wie Du es beschreibst und so wie Dein Code es darstellt, kann es 
passieren, inCurrent outCurrent überholt...

Vielleicht solltest Du mal Deinen ganzen Code zeigen...

Gruß
Frank

von J. S. (grooc)


Lesenswert?

1
void Send(uint8_t d){
2
  outBuffer[bufferPos] = d;
3
  bufferPos = (bufferPos+ 1) % FLA_BUFFER_SIZE;
4
}
5
6
void ClearBuffer(){
7
  for (uint8_t i = 0; i < FLA_BUFFER_SIZE; i++){
8
    inBuffer[i]  = 0x00;
9
    outBuffer[i] = 0x00;
10
  }
11
  inCurrent = 0;
12
  outCurrent = 0;
13
  bufferPos= 0;
14
}


Also ich hoffe es ist klar geworden, dass nur bufferPos manuell gesetzt 
wird. inCurrent und ourCurrent sind also die beiden "Read" Zeiger in 
Ringpuffer sprache. Ich dachte, dass ich bei SPI immer so verfahren 
kann, da ich pro gesendetem Zeichen auch eines zurückbekomme.

von Frank L. (frank_l)


Lesenswert?

Nochmals meine Bitte, zeig Deinen kompletten Code oder reduziere ihn auf 
ein lauffähiges Stück Code mit dem das ganze nachvollzogen werden kann.

So ist meine antwort "42" weil die paar Zeilen aus Deinem letzten 
Posting helfen nicht weiter.

Gruß
Frank

von J. S. (grooc)


Lesenswert?

Ich verstehe nicht ganz, warum die Init Routine noch entscheidend ist. 
Die Kommunikation läuft ja. Ist nur der Ringpuffer der nicht 
funktioniert.
Hier ist der Code: http://codepad.org/RHoJqQPJ

Hoffe das es Hilft ...

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

J. S. schrieb:
> Ich verstehe nicht ganz

Weißt du, was ich nicht verstehe?
Ich verstehe nicht, warum das so schwer ist seinen Source Code so wie er 
ist, hier ganz einfach im Forum als Attachment anzuhängen.

von Frank L. (frank_l)


Lesenswert?

Erklärst Du mir bitte, warum Du in dieser Zeile
1
}else{ // all data received  disable RX Interrupt
2
      SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_TXE | SPI_I2S_IT_RXNE, DISABLE);
3
    }

beide Flags betrachtest?

Gruß
Frank

von J. S. (grooc)


Lesenswert?

Interessant, ja du hast recht, für den Fall dass der inCurrent Zeiger 
den outCurrent Zeiger überholt, kann es zu einem Fehler führen. Ich 
werde es nachher mal testen.

von Frank L. (frank_l)


Lesenswert?

Damit hast Du Dir wahrscheinlich Deine Frage auch schon beantwortet...

Gruß
Frank

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.