PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Ringpuffer für UART-Kommunikation



Leonhard1978
31.08.2017, 08:33
Guten Morgen,

auf dem XMC4700 Mikrocontroller von Infineon wird eine UART eingesetzt. Es sollen die ankommenden Daten von UDP über die UART an ein anderes Device gesendet werden.
Es kann nun passieren, dass die ankommenden UDP Daten schneller ankommen als die UART die Daten verarbeiten kann. Deshalb sollen Die Daten (Frames) in einen Ringpuffer abgelegt werden. Auf folgender Seite habe ich eine Implementierung gefunden https://www.google.de/url?sa=t&rct=j&q=&esrc=s&sou... die mein Problem eventuell lösen könnte.

Der folgende Quellcode habe ich auf dem PC mit Visual Studio erfolgreich getestet. Auf dem Mikrocontroller läuft dieser Quellcode nicht. Der Mikrocontroller bleibt hängen.
Wo könnte hier das Problem liegen?




#define BUFFER_SIZE 512
#define NUMBER_OF_FRAMES 10

//Struktur fuer die Daten
typedef struct
{
int length;
char data[BUFFER_SIZE];
} userdata_t;

//Struktur fuer einen Ringbuffer-Handler
//wird benoetigt, um mehrere Listen zu verwalten
typedef struct
{
//Index zum Lesen
int readIndex;
//Index zum Schreiben
int writeIndex;
//Platz fuer Speicherelemente, eigentlicher Buffer
userdata_t fifo[NUMBER_OF_FRAMES];
//Groesse des Buffers, d.h. Anzahl der Elemente
int size;
} ringbuffer_handler_t;


/*-------------------------------------------------------------------------*/

//eine Funktion, um einen Ringbuffer anzulegen
//Parameter size: Groesse des Buffers (Anzahl der Elemente)
//Rückgabewert: Zeiger auf Ringbuffer-Handler
ringbuffer_handler_t * createFIFO(int size)
{
static char Memory[6000];
ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)Memory;

//Werte des Handler belegen
//readIndex und WriteIndex zu Anfang 0
//fuer fifo muss genuegend Speicher reserviert werden,
//um size Datenelemente aufnehmen zu koennen
//size gibt Anzahl der Elemente im Ringbuffer an (aus Parameter)
buffer->readIndex = 0;
buffer->writeIndex = 0;
buffer->size = size;

return buffer;
}

/*-------------------------------------------------------------------------*/

//eine Funktion, um Elemente anzuhaengen, d.h. in den Buffer zu schreiben
//Parameter data: Daten, die in den Buffer geschrieben werden sollen
//Parameter *buffer: Zeiger auf Ringbuffer-Handler
//kein Rueckgabewert
void appendFIFO(userdata_t data, ringbuffer_handler_t *buffer)
{
//Daten in den entsprechenden Platz im Buffer schreiben
//dafuer ist writeIndex da
buffer->fifo[buffer->writeIndex] = data;
//writeIndex wird fuer das naechste Schreiben auf den neuen Wert
//gesetzt
//Achtung: wenn der Buffer voll ist, wird wieder vorne hineinge-
//schrieben (deshalb RINGbuffer), Daten koennen verloren gehen,
//wenn nicht zwischendurch gelesen wird
buffer->writeIndex = buffer->writeIndex++ % (buffer->size + 1);
//an dieser Stelle ist es deshalb sinnvoll, den readIndex auf den
//letzen wahren Wert zu setzen, wenn NICHT zwischendurch gelesen
//wurde
if (buffer->readIndex == buffer->writeIndex)
buffer->readIndex = buffer->readIndex++ % (buffer->size + 1);
}

//eine Funktion, um Elemente aus dem Buffer zu lesen
//Parameter *data: Zeiger auf ein Datenelement, das die gelesenen Daten
//aufnehmen soll
//Parameter *buffer: Zeiger auf Ringbuffer-Handler
//Rueckgabewert -1, wenn nicht gelesen werden konnte
//Rueckgabewert 1, wenn gelesen werden konnte
int readFIFO(userdata_t *data, ringbuffer_handler_t *buffer)
{
//der writeIndex zeigt immer auf das naechste zu beschreibende Element,
//d.h. dieses Element ist noch nicht beschrieben worden und enthaelt
//deshalb keine gueltigen Daten
//wenn readIndex also gleich writeIndex, darf nicht gelesen werden
if (buffer->readIndex != buffer->writeIndex)
{
//Daten kopieren
*data = buffer->fifo[buffer->readIndex];
//readIndex fuer das naechste Lesen hochsetzen
buffer->readIndex = buffer->readIndex++ % (buffer->size + 1);
//Rueckgabewert 1, da gelesen wurde
return 1;
}
else
//es konnten keine Daten gelesen werden, da keine gueltigen Daten
//Rueckgabewert also -1
return -1;
}

void main (void)
{
ringbuffer_handler_t *local_buffer;
userdata_t write_data;
userdata_t read_data;
int ergebnis;

local_buffer = createFIFO(NUMBER_OF_FRAMES);

char DummyData[500];
memset(DummyData, 0x33, 500);

write_data.length = 101;
memcpy(write_data.data, DummyData, 101);
appendFIFO(write_data, local_buffer);

readFIFO(&read_data, local_buffer);
}

vohopri
31.08.2017, 09:27
Jetzt deinen Quälcode zu analysieren, hab ich nicht die Zeit zur Verfügung.

Nur so als Tip, was bei mir optimal funktioniert:

Debugbefehle einbauen und anzeigen lassen, wie der Programmablauf vorangeht und wie die Daten im Speicher verarbeitet werden. Da sieht man sehr schnell, was Sache ist. Die Debugstrategie überlegt man sich am Besten noch bevor die erste Codezeile geschrieben wird. Aber besser spät, als nie.

Du hast einen uart zur Verfügung, wenn du den zum debuggen nutzt, brauchst du nicht einmal Zusatzhardware und -software.

White_Fox
19.09.2017, 21:16
Ich hab auf den Abend auch keine Lust mehr mich durch Code kämpfen zu müssen. Aber einen alternativen Lösungsansatz hätte ich vielleicht, sowas könnte ich demnächst vielleicht auch gebrauchen. Also:



//globaler Zugriff:
*TBuffercell FirstBuffercell;
*TBuffercell LastBuffercell;

typedef struct{
char[128] buffer; //Kleines Array, das deine Daten aufnimmt, kann natürlich auch eine andere Größe haben, die Größe sollte aber als Konstante hinterlegt werden
int queueStart; //Gibt den Anfang des beschriebenen Bereichs an, bei "vollem" buffer also 0, so findest du den Anfang wieder wenn du das Array nicht auf einen Schlag auslesen willst
int queueEnd; //Gibt das Ende des beschriebenen Bereichs an, bei "vollem" buffer also 127, so findest du das Ende wieder wenn du das Array nicht auf einen Schlag beschreiben willst
*nextTBuffercell; //Pointer auf das nächste Speicherelement, bei Null ist das vordere Ende der Queue erreicht
}TBuffercell

Das wars dann auch fast schon, noch eine Funktion die deine Daten auf lauter TBuffercells quer durch den Speicher verteilt () und eine, die mit dem Pointer FirstBuffercell hinterherkriecht und die Daten wieder zurückgibt, aber das kriegst du selber hin. Nicht vergessen, LastBuffercell und queueEnd bzw. FirstBuffercell und queueStart zu inkrementieren.

Jetzt war ich doch mal neugierig und hab mir mal deinen Code nochmal angesehen, viel Arbeit ist so ein Ringpuffer nun doch nicht. Warum der nicht funktioniert kann ich dir auf die Rasche nicht sagen, allerdings belegt der den Speicher in einem einzigen Stück, ist fest begrenzt und belegt den Platz auch wenn du ihn nicht brauchst.
Das Konzept mit der struct-Kette ist da weitaus flexibler, kann gerne fragmentieren, kann ausgedehnt werden solange noch Speicher da ist (du kannst ja ohne weiteres ein neues struct erstellen und dem jetzt struct das nun an zweiter Stelle steht den Pointer umsetzen), eine Größenbeschränkung kannst du auch einbauen (vom ersten struct bis zum letzten durchzählen). Dafür hast du etwas mehr Überbau an Speicherbedarf für die Pointer.

Edit:
Zumindest denk ich mir das so einfach, seit ich mich mal etwas ernsthaft mit OOP befaßt habe fällt mir prozedurale Programmierung echt schwer und C geht mir sehr auf die Nerven...ich bin auf die Probleme gespannt die dieses Konzept aufwirft.