mikrocontroller.net

Forum: Compiler & IDEs STM32 - Stack overflow?!


Autor: Martin K. (dschadu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi.

ich habe aktuell ein sehr merkwürdiges Problem. Ich bin aktuell ein 
einfaches CAN-Protokoll am basteln.
Neben dem Hardwarepuffer habe ich noch einen Softwarepuffer 
eingerichtet, ein simpler FiFo.

Zum Ablauf:
Jeden Zyklus wird CAN_Main() aufgerufen. Innerhalb davon wird 
CAN_ReceiveSequenceData() augerufen.
#define MAX_DATA_RECEIVE_SEQUENCES 6

volatile int CanRX_Head = 0;
volatile int CanRX_Tail = 0;

ReceiveSequenceStruct ReceiveSequence[MAX_DATA_RECEIVE_SEQUENCES];

void CAN_ReceiveSequenceData()
{
  //If there is data to read...
  if (CanRX_Head != CanRX_Tail)
  {
    //uint8_t Temp_CanRX_Head = CanRX_Head;
    uint8_t Status = 0;

    //First test if the received ID is within the data-ID range
    if (CanRxMessage[CanRX_Head].StdId >= CAN_DATATYPE_LOWEST_ID && CanRxMessage[CanRX_Head].StdId <= CAN_DATATYPE_HIGHEST_ID)
    {
      [...]
    }
    else
    {
      for (int i = 0; i < ReceiveSequenceIDsCount; i++)
      {
        if (CanRxMessage[CanRX_Head].StdId == ReceiveSequenceIDs[i])
        {
          Status = 1;    //Mark as valid sequence ID

          //Reset data if header is received again
          int BufferID = 0;
          BufferID = CAN_ReceiveSequence_SearchBuffer(ReceiveSequenceIDs[i]);

          if (BufferID >= 0)
          {
            CAN_ReceiveSequence_Reset(BufferID);
          }
        }
      }
    }
  }
}

//Search the buffer that is used  
int CAN_ReceiveSequence_SearchBuffer(uint8_t CAN_StartID)
{
  for (int i = 0; i < MAX_DATA_RECEIVE_SEQUENCES; i++)
  {
    if (ReceiveSequence[i].CAN_StartID == CAN_StartID)
    {
      return i;
    }
  }

  return -1;
}

Zum Problem: Nehmen wir an CanRX_Head ist 0 und CanRX_Tail ist 1, dann 
ist die erste if-Bedingung erfüllt. Nehmen wir weiterhin an dass die 
zweite if Bedingung nicht erfüllt wird, also springt das Programm in den 
else-Zweig.
Spring das Programm nun in die Funktion 
CAN_ReceiveSequence_SearchBuffer() ändert sich CanRX_Head zu 135. Und 
das sobald er auf die for() schleife springt. Kopiere ich den kram aus 
der Funktion raus, gehts. Dann passiert das gleiche (selber Wert von 
CanRX_Head) in der nächsten Funktion in die er springt.
Daher gehe ich davon aus dass der Speicher überläuft - warum auch immer. 
Ich bin bei 4% RAM-Auslastung.

Jetzt habe ich mir den Spaß gemacht und die beiden Variablen in der 
Initialisierung gedreht
volatile int CanRX_Tail = 0;
volatile int CanRX_Head = 0;
Und siehe da, es geht. Ohne dass jetzt CanRX_Tail betroffen ist. Zuvor 
habe ich mal ein uin8_t draus gemacht aus beiden Variablen, selbes 
Problem. Nur das drehen der Reihenfolge brachte jetzt "Besserung".

Warum? Was ist da passiert? Kann mir das jemand erklären?

IC ist ein STM32F103RB auf einem Olimex Board.
Programmiert mit VisualGDB (GCC 7.2.0 / GDB 8.0.1)

Edit: Okay, das Problem bleibt, nur anders rum. CanRX_Tail wird jetzt 
immer auf 0 gesetzt. Selbe stelle, selber Sprung in die Funktion

: Bearbeitet durch User
Autor: Frank M. (ukw) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn die erste der beiden Variablen versehentlich überschrieben wird:

Welches Array wird vor der Definition
volatile int CanRX_Tail = 0;

definiert? Dieses läuft wohl aufgrund mangelnder Prüfung über.

EDIT:

Die Situation ist etwas verworren beschrieben: Wenn es die zweite 
Variable ist, die verbotenerweise verändert wird, dann liegts wohl eher 
an dem Array

ReceiveSequenceStruct ReceiveSequence[MAX_DATA_RECEIVE_SEQUENCES];

Dieses wird dann mit dem Index -1 beschrieben.

Bitte nochmal genau beschreiben, welche Variable versehentlich 
überschrieben wird. Die obere oder die untere?

: Bearbeitet durch Moderator
Autor: Martin K. (dschadu)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es wird die erste Variable überschrieben:
#define CAN_BUFFERCOUNT        10    

CanRxMsg CanRxMessage[CAN_BUFFERCOUNT];

volatile int CanRX_Tail = 0;
volatile int CanRX_Head = 0;

Hier wird CanRxMessage geschrieben:
extern "C" void USB_LP_CAN1_RX0_IRQHandler(void)
{
  CAN_Receive(CAN1, CAN_FIFO0, &CanRxMessage[CanRX_Tail]);

  if (CanRX_Tail >= CAN_BUFFERCOUNT)
  {
    CanRX_Tail = 0;
  }
  else
  {
    CanRX_Tail++;
  }
}


Und jetzt wo ich mir das ansehe, sehe ich den Fehler. Wenn er mit 
CanRX_Tail = 9 in den interrupt springt, geht er mit 10 raus - springt 
wieder rein und landet mit [10] im Array out of bounds...

Was nen hinterhältiger Fehler.


Danke für den Schubs in die richtige Richtung

Edit:
Ich kapier aber nicht warum bei einem Sprung in eine andere Funktion? 
Müsste das nicht sofort passieren sobald der Überlauf stattfindet, also 
beim Empfangen der Nachricht?

: Bearbeitet durch User

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.