Mikrocontroller: Ringpuffer für UART-Kommunikation

Gast #5126029
Lesenswert?

Hallo,

auf der jetzigen Firmware läuft die UART ohne einen Ringpuffer.
Zwischen der Applikation und der UART Implementierung soll ein 
Ringpuffer
für die Senderichtung eingesetzt werden. Der Ringpuffer soll so 
gestaltet sein, dass dieser insgesamt 10 Frames mit jeweils einer 
maximalen Länge von 300 Bytes aufnehmen kann. Gibt es hier in dem Forum 
Personen die mir eventuell bei der Umsetzung helfen könnten?
#5126051
Lesenswert?

Du hast ein Array aus Frames, einen Read-Index und einen Write-Index.

Wer in den Puffer schreiben möchte, schreibt in das Array an die Stelle, 
auf die der Write-Index zeigt und incrementiert diesen dann (zeigt er 
hinter das letzte Element, wird er auf das erste Element gesetzt). 
Lesezugriffe nutzen den Read-Index.

Es gibt eine Mehrdeutigkeit zu beachten, wenn Read- und Write-Index 
gleich sind. Dann ist der Ringpuffer entweder voll oder leer, abhängig 
davon, ob der letzte Zugriff ein Schreib- oder ein Lesezugriff war.

Diese Mehrdeutigkeit kann man vermeiden, indem man das Array ein Element 
größer macht als notwendig und immer einen Frame frei lässt.

So, jetzt bist du dran.
Gast #5126053
Lesenswert?

Darf ich fragen wo du für dich ein Problem siehst? Auf den ersten Blick 
ist das doch etwas Speicher plus ein kleiner Zustandsautomat.

Woher weis dein Puffer in einem seriellen Datenstrom was ein Frame ist?
Muss er das überhaupt wissen?

Viel Erfolg & halt uns auf dem laufenden
Hauspapa
Gast #5126063
Lesenswert?

Erstmal vielen Dank für die zahlreichen Beiträge.

Folgende Link habe ich bei mir im Code versucht umzusetzen:
https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwigkJO_s_zVAhVJaxQKHVR5DrwQFggoMAA&url=http%3A%2F%2Fwww.informatik.uni-bremen.de%2Fagbs%2Flehre%2Fws0203%2Fgdi1%2Fhintergrund-info%2Fringbuffer.c&usg=AFQjCNGCzskq31fiHUxFs-iKQv10tn6cnQ

Hier wird für die Speicherreservierung malloc eingesetzt. Auf meinem 
Mikrocontroller funktioniert das leider nicht mit dem malloc.
Gast #5126067
Lesenswert?

Problem:

In der Zeit wo die UART noch beschäftigt ist die Daten zu versenden, 
kann möglicherweise wieder ein neues Frame von der 
Ethernet-Schnittstelle ankommen. Somit muss dann dieses Frames in einen 
Ringpuffer kopiert werden. Wenn die UART wieder bereit ist soll der 
Inhalt vom Ringpuffer über die UART gesendet werden.
#5126070
Lesenswert?

leo schrieb:
> Erstmal vielen Dank für die zahlreichen Beiträge.
>
> Folgende Link habe ich bei mir im Code versucht umzusetzen:
> 
https://www.google.de/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwigkJO_s_zVAhVJaxQKHVR5DrwQFggoMAA&url=http%3A%2F%2Fwww.informatik.uni-bremen.de%2Fagbs%2Flehre%2Fws0203%2Fgdi1%2Fhintergrund-info%2Fringbuffer.c&usg=AFQjCNGCzskq31fiHUxFs-iKQv10tn6cnQ
>
> Hier wird für die Speicherreservierung malloc eingesetzt. Auf meinem
> Mikrocontroller funktioniert das leider nicht mit dem malloc.

1.) Warum nicht? Fehlermeldung oder was?
2.) Dann mach deinen Ringpuffer statisch.
3.) Dir scheint es einfach noch deutlich an Erfahrung zu mangeln. Nimm 
keine sinnlosen Codeschnipsel, lies mal die Leute dir hier geschrieben 
haben und versuche es damit SELBST umzusetzen. Man kommt sich doch 
verarscht vor, wenn man dir hier breit erklärt wie es geht und dann 
einen Codeschnipsel rausziehst und mäkelst "bäh so geht's aber nicht".
Gast #5126097
Lesenswert?

leo schrieb:
> Problem:
>
> In der Zeit wo die UART noch beschäftigt ist die Daten zu versenden,
> kann möglicherweise wieder ein neues Frame von der
> Ethernet-Schnittstelle ankommen. Somit muss dann dieses Frames in einen
> Ringpuffer kopiert werden. Wenn die UART wieder bereit ist soll der
> Inhalt vom Ringpuffer über die UART gesendet werden.

Warum meinst Du, stellt das ein Problem dar? (Es geht mir mit der Frage 
darum, Dich auf eine strukturierte Denkweise hinzulenken).

Zunächst einmal wäre es gut, sich zumindest eine Übersicht zu 
verschaffen, was die Peripherie eines uC überhaupt kann.

Der UART kann full-duplex arbeiten. Das bedeutet er kann gleichzeitig 
empfangen und senden. Es gibt nur eine Operation, welche im Zusammenhang 
mit dem Datentransfer nicht simultan erledigt werden kann: Nämlich die 
Daten übernehmen bzw. übergeben. (Ob da noch DMA dazwischen ist, spielt 
dabei eine Nebenrolle).

Deine Angaben sind auch widersprüchlich: Im Eröffnungspost schreibst Du 
nur von UART, nun aber kommt auch die Ethernet-Schnittstelle ins Spiel. 
Falls Du über Ethernet empfängst, aber über UART sendest, dann 
verursacht das eher kein Problem, dass mittels eines Ringbuffers zu 
lösen ist. Es besteht allerdings die Möglichkeit, dass die 
Ausführungszeiten schon so knapp sind, dass ein Ringbuffer tatsächlich 
das Projekt rettet, ohne das ein Redesign oder auch nur ein anderer uC 
nötig ist.


Dann wieder malloc: Es ist an sich klar, dass Du Code oft nicht einfach 
nur Eins-Zu-Eins übernehmen kannst. Es hängt ein bisschen davon ab, was 
Deine Vorkenntnisse und Erfahrungen sind und in welchem Kontext Du hier 
Deine Frage stellst: Bist Du Schüler ohne Erfahrungen ist das was 
anderes als wenn Du Student im Praktikum bist oder gar auf PCs schon 
viel Code geschrieben hast, nur auf uCs noch wenig Erfahrung hast.
An sich wird man malloc auf uCs vermeiden und feste Buffer definieren.


Es wären einmal ausführliche Angaben über Situation (sowohl zum Projekt 
als auch zu Deiner Person) nützlich.

Andernfalls solltest Du wenigstens schreiben, wobei Du nun konkret Hilfe 
brauchst. Bitte bedenke, dass hier in der Regel Hilfe zur Selbsthilfe 
geleistet wird.
Gast #5126103
Lesenswert?

1) Die Adressen in Deinem Ringpuffer bilden einen Kreis.

2) Definiere einen Schreib- und einen Lesezeiger, die jeweils den 
Schreib- und Leseadressen in Deinem Puffer entsprechen.

3) Nach jedem Schreiben in den Puffer wird der Schreibzeiger um 1 (oder 
n) inkrementiert.

4) Nach jedem Lesen aus dem Puffer wird der Lesezeiger um 1 (oder 
n)inkrementiert.

5) Ist vor dem Lesen der Lesezeiger gleich dem Schreibzeiger, dann ist 
der Puffer leer.

6) Ist vor dem Schreiben der Schreibzeiger gleich dem Lesezeiger, dann 
wird der Puffer überlaufen.
Gast #5126143
Lesenswert?

Zu Deinem Code:

1) Wenn Du kein Malloc verwenden willst, dann muss der Aufrufer den 
Speicher mit übergeben. Das ist das sauberste. Am einfachsten, indem du 
ein Makro zur Verfügung stellst, dass bei gegebener Fifo-Größe den 
Gesamt-Platzbedarf in Bytes errechnet. Der Anwender legt dann ein 
Static-Array damit an.

2) Die Operation % (X+1) ist nicht sehr performant. Spielt hier keine 
Rolle, aber um den Charakter des Überlaufs besser zu zeigen wäre besser:
1
   
2
    buffer->writeIndex++;
3
    /* Bei size+1 umlaufen lassen um rIdx==wIdx zu vermeiden, ist OK */
4
    if(buffer->writeIndex > buffer->size) 
5
    {
6
        buffer->writeIndex=0; 
7
    };

3) Warum du immer nur ein Byte kopierst ist mir auch nicht klar. Eine 
Nachricht sollte doch immer komplett kopiert werden

4) Der Read-Index hat am Ende von Append nichts zu suchen. Im Gegenteil: 
Am Anfang muss geschaut werden, ob genügend Platz drin ist. Darum ist es 
in der Regel einfacher, neben rIdx und wIdx noch einen cnt mitzuführen. 
Man spart damit das "size+1" und kann direkt sagen, ob und wieviel drin 
ist (beim Lesen) oder ob genug Platz zum Schreiben ist. Die Alternative 
((wr-rd+(wr<rd?size:0)) zerfällt nur bei size=2^n und unsigned-typen in 
praktisch nichts.
Gast #5126224
Lesenswert?

hier z.B.

 #define buff_tx_sz (300*10)
 char buff_tx[buff_tx_sz];
 unsigned int   buff_tx_rd =0;
 unsigned int   buff_tx_wr =0;
 unsigned int   buff_tx_rn =0;
 unsigned int   buff_tx_wn =0;

 void put(char c) {
   while(buff_tx_wn!=buff_tx_rn && buff_tx_wr==buff_tx_rd) idle();
   buff_tx[buff_tx_wr++] = c; if(buff_tx_wr>=buff_tx_sz) buff_tx_wr=0;
   buff_tx_wn++;
 }

 char c get() {
   char c;
   while(buff_tx_wn==buff_tx_rn) idle();
   c = buff_tx[buff_tx_rd++]; if(buff_tx_rd>=buff_tx_sz) buff_tx_rd=0;
   buff_tx_rn++;
   return c;
 }
Gast #5126306
Lesenswert?

Mach ich auch immer so. Ich habe zwei FIFOs/Ringspeicher. Einer für Rx 
und einer für Tx. Dann eine getchar() für Rx und eine putchar() für Tx.
Im Interrupt der UART habe ich dann das jeweilige Gegenstück zu getchar 
und putchar.
Gast #5126350
Lesenswert?

Achim S. schrieb:

> Die Alternative
> ((wr-rd+(wr<rd?size:0)) zerfällt nur bei size=2^n und unsigned-typen in
> praktisch nichts.

Genau. Da nimmt man halt als Puffergröße statt 3001 eben 4096 Bytes und 
gut isses. Es schadet sicher nix, wenn bis zu drei Frames mehr in den 
Puffer passen als gefordert und es macht den Code erheblich schneller.

Solange man die 1095 Bytes zusätzlichen Puffer nicht dringend irgendwo 
anders benötigt, spricht absolut nix dagegen, das so zu machen.
Gast #5126769
Lesenswert?

1
#define NUMBER_OF_FRAMES  10
2

3
char Memory[20];
4

5
ringbuffer_handler_t * createFIFO(int size)
6
{
7
  ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)&Memory;
8

9
  buffer->readIndex = 0;
10
  buffer->writeIndex = 0;
11
  buffer->fifo[400* size];
12
  buffer->size = size;
13
}
14

15

16
void main(void)
17
{
18
  ringbuffer_handler_t *buffer;
19
  userdata_t data;
20
  int ergebnis;
21

22
  buffer = createFIFO(NUMBER_OF_FRAMES);
23

24
  char TxBuffer[200];
25
  for(int i = 200; i < 200; i++)
26
  {
27
    TxBuffer[i] = 0x13;
28
  }
29

30
  data.length = 100;
31
  memcpy(data.data, TxBuffer, 100);
32
  appendFIFO(data, buffer);
33

34
}
Gast #5126839
Lesenswert?

1
#define NUMBER_OF_FRAMES  10
2

3
//Struktur fuer die Daten
4
typedef struct
5
{
6
  int length;
7
  char data[BUFFER_SIZE];
8
} userdata_t;
9

10
//Struktur fuer einen Ringbuffer-Handler
11
//wird benoetigt, um mehrere Listen zu verwalten
12
typedef struct
13
{
14
  //Index zum Lesen
15
  int readIndex;
16
  //Index zum Schreiben
17
  int writeIndex;
18
  //Platz fuer Speicherelemente, eigentlicher Buffer
19
  userdata_t *fifo;
20
  //Groesse des Buffers, d.h. Anzahl der Elemente
21
  int size;
22
} ringbuffer_handler_t;
23

24

25
char Memory[6000];
26

27
ringbuffer_handler_t * createFIFO(int size)
28
{
29
  ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)&Memory;
30

31
  //Werte des Handler belegen
32
  //readIndex und WriteIndex zu Anfang 0
33
  //fuer fifo muss genuegend Speicher reserviert werden,
34
  //um size Datenelemente aufnehmen zu koennen
35
  //size gibt Anzahl der Elemente im Ringbuffer an (aus Parameter)
36
  buffer->readIndex = 0;
37
  buffer->writeIndex = 0;
38
  buffer->fifo[512 * size];
39
  buffer->size = size;
40
}
41

42
void appendFIFO(userdata_t data, ringbuffer_handler_t *buffer)
43
{
44
  //Daten in den entsprechenden Platz im Buffer schreiben
45
  //dafuer ist writeIndex da
46
  buffer->fifo[buffer->writeIndex] = data;
47
  //writeIndex wird fuer das naechste Schreiben auf den neuen Wert
48
  //gesetzt
49
  //Achtung: wenn der Buffer voll ist, wird wieder vorne hineinge-
50
  //schrieben (deshalb RINGbuffer), Daten koennen verloren gehen,
51
  //wenn nicht zwischendurch gelesen wird
52
  buffer->writeIndex = buffer->writeIndex++ % (buffer->size + 1);
53
  //an dieser Stelle ist es deshalb sinnvoll, den readIndex auf den
54
  //letzen wahren Wert zu setzen, wenn NICHT zwischendurch gelesen
55
  //wurde
56
  if (buffer->readIndex == buffer->writeIndex)
57
    buffer->readIndex = buffer->readIndex++ % (buffer->size + 1);
58
}
59

60
int readFIFO(userdata_t *data, ringbuffer_handler_t *buffer)
61
{
62
  if (buffer->readIndex != buffer->writeIndex)
63
  {
64
    //Daten kopieren
65
    *data = buffer->fifo[buffer->readIndex];
66
    //readIndex fuer das naechste Lesen hochsetzen
67
    buffer->readIndex = buffer->readIndex++ % (buffer->size + 1);
68
    //Rueckgabewert 1, da gelesen wurde
69
    return 1;
70
  }
71
  else
72
    //es konnten keine Daten gelesen werden, da keine gueltigen Daten
73
    //Rueckgabewert also -1
74
    return -1;
75
}
76

77
void main(void)
78
{
79
  ringbuffer_handler_t *buffer;
80
  userdata_t data;
81
  int ergebnis;
82

83
  buffer = createFIFO(NUMBER_OF_FRAMES);
84

85
  char TxBuffer[200];
86
  for(int i = 200; i < 200; i++)
87
  {
88
    TxBuffer[i] = 0x13;
89
  }
90

91
  data.length = 100;
92
  memcpy(data.data, TxBuffer, 100);
93
  appendFIFO(data, buffer);
94

95
}
#5126874
Lesenswert?

Ich hab gerade mal nach dem Original gegoogelt (da dein Link oben nicht 
funktioniert) und hier sieht es so aus:
1
//eine Funktion, um einen Ringbuffer anzulegen
2
//Parameter size: Groesse des Buffers (Anzahl der Elemente)
3
//Rückgabewert: Zeiger auf Ringbuffer-Handler
4
ringbuffer_handler_t *createFIFO(int size)
5
{
6
    //Zeiger auf Ringbuffer-Handler deklarieren und genuegend Speicher
7
    //reservieren
8
    ringbuffer_handler_t *buffer = 
9
  (ringbuffer_handler_t *)malloc(sizeof(ringbuffer_handler_t));
10
    
11
    //Werte des Handler belegen
12
    //readIndex und WriteIndex zu Anfang 0
13
    //fuer fifo muss genuegend Speicher reserviert werden, 
14
    //um size Datenelemente aufnehmen zu koennen
15
    //size gibt Anzahl der Elemente im Ringbuffer an (aus Parameter)
16
    buffer->readIndex=0;
17
    buffer->writeIndex=0;
18
    buffer->fifo = (userdata_t *)malloc(sizeof(userdata_t) * (size + 1));
19
    buffer->size = size;
20

21
    //Zeiger auf Ringbuffer-Handler zurueckgeben
22
    return buffer;
23
}

Schau dir noch einmal an, welche Menge speicher für welchen Zweck mit 
malloc reserviert wird und versuche das entsprechend mit statischen 
Variablen nachzubauen.
Gast #5126883
Lesenswert?

Für den kompletten Speicher habe ich 6000 Bytes vorgesehen. Deshalb das 
globale char Array Memory. Das FIFO hat eine maximale Größe von 400 * 10 
Bytes.

400 --> Framegröße von 400 Bytes
size --> Frame Anzahl = 10

1
char Memory[6000];
2

3
ringbuffer_handler_t * createFIFO(int size)
4
{
5
  ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)&Memory;
6

7
  //Werte des Handler belegen
8
  //readIndex und WriteIndex zu Anfang 0
9
  //fuer fifo muss genuegend Speicher reserviert werden,
10
  //um size Datenelemente aufnehmen zu koennen
11
  //size gibt Anzahl der Elemente im Ringbuffer an (aus Parameter)
12
  buffer->readIndex = 0;
13
  buffer->writeIndex = 0;
14
  buffer->fifo[400* size];
15
  buffer->size = size;
16
}
Gast #5126926
Lesenswert?

1
char Memory[6000];
2
char Fifo[5120];
3

4
ringbuffer_handler_t * createFIFO(int size)
5
{
6
  ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)&Memory;
7

8
  //Werte des Handler belegen
9
  //readIndex und WriteIndex zu Anfang 0
10
  //fuer fifo muss genuegend Speicher reserviert werden,
11
  //um size Datenelemente aufnehmen zu koennen
12
  //size gibt Anzahl der Elemente im Ringbuffer an (aus Parameter)
13
  buffer->readIndex = 0;
14
  buffer->writeIndex = 0;
15
  buffer->fifo = (userdata_t *)&Fifo;
16
  buffer->size = size;
17

18
  return buffer;
19
}

Sobald ich die Methode appendFIFO ausführe stürzt der Controller ab.
Gast #5126943
Lesenswert?

Die Anzahl der Fifo Elemente wird nun in der Struktur fest angelegt.
Dies bedeutet, dass die Zeile in der Funktion createFIFO wegfallen kann.
1
buffer->fifo = (userdata_t *)&Fifo;
1
typedef struct
2
{
3
  //Index zum Lesen
4
  int readIndex;
5
  //Index zum Schreiben
6
  int writeIndex;
7
  //Platz fuer Speicherelemente, eigentlicher Buffer
8
  userdata_t fifo[10];
9
  //Groesse des Buffers, d.h. Anzahl der Elemente
10
  int size;
11
} ringbuffer_handler_t;
Gast #5126994
Lesenswert?

Was passiert mit dieser Zeile buffer->fifo ?
1
ringbuffer_handler_t * createFIFO(int size)
2
{
3
  ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)&Memory;
4

5
  //Werte des Handler belegen
6
  //readIndex und WriteIndex zu Anfang 0
7
  //fuer fifo muss genuegend Speicher reserviert werden,
8
  //um size Datenelemente aufnehmen zu koennen
9
  //size gibt Anzahl der Elemente im Ringbuffer an (aus Parameter)
10
  buffer->readIndex = 0;
11
  buffer->writeIndex = 0;
12
        buffer->fifo = ????????????????????????
13
  buffer->size = size;
14

15
  return buffer;
16
}
#5127006
Lesenswert?

Ich zitiert mal aus meinem Link:

[Zitat]
Durch die Anweisung
1
ptr = element;
wird dem Zeiger ptr die Adresse des Arrays element übergeben. Dies 
funktioniert ohne den Adressoperator, da laut ANSI-C-Standard der 
Array-Name immer als Zeiger auf das erste Array-Element angesehen wird. 
Hier sind der Beweis und das Beispiel dazu:
[/Zitat]

Leider kann dir dein Compiler für deine Fehler nicht auf die Finger 
klopfen, da du ihm durch den cast sagst: "das ist schon so richtig, ich 
weiß was ich tue"
#5127156
Lesenswert?

@Vincent Hamp (vinci)

>Wenn du mit Pointern und deren Arithmetik noch nicht so vertraut bist,
>dann benutz doch einfach einen ganz klassischen Zähler zum Signalisieren
>der Lese- und Schreibposition...

Man könnte ja auch fertigen, getesteten Quelltext nutzen, der schon 
angeboten wurde. Muss man aber nicht . .  .
Gast #5127184
Lesenswert?

leo schrieb:
> Die ganze Zeiger und Adresse usw da kommt man durcheinander. Da versteht
> man dann nix mehr

Sorry aber wenn man sein Handwerkszeug nicht beherrscht dann kann man 
auch kein Gesellenstück bauen.

Dann bleibt nur

Falk B. schrieb:
> Man könnte ja auch fertigen, getesteten Quelltext nutzen, der schon
> angeboten wurde. Muss man aber nicht . .  .

Aber man muss dann zumindest soviel vom Programmieren verstehen daß man 
den Code versteht und anpassen kann falls nötig.

Programmieren ist halt nicht wie backen mit Dr. Oetger. Fertigmischung, 
Milch, rühren, Backofen, lecker (vieleicht).
Das muss man halt LERNEN.

leo schrieb:
> Bin hier quasi alleine.

Wie soll man das verstehen? Alleine beim Hausaufgaben machen oder 
alleine in einer Firma beim Entwickeln einwes Programms für das Kunden 
dann Geld zahlen sollen?
Gast #5127191
Lesenswert?

leo schrieb:
> Könnt ihr mir da nicht noch eine weitere Hilfestellung geben?

kann ich leider nicht da selbst C lernender. Kann dir aber sagen was ich 
gemacht habe.

Mir ist dieser ganze Ringbufferkram mit seine Nebenwirkungen und Risiken 
zu hoch. Das ist zwar alles jetzt wunderbar kompakt aber eben gewollt 
hochkomplex.

Deshalb habe ich den "Ringbuffer" durchgeschnitten und zwei Queues draus 
gemacht.
1
// globals in interrupt
2
unsigned char LeftBuffer[85] ;     // Left/Right Names for easy distinguishing)
3
unsigned char RightBuffer[85] ;


Darauf dann zwei Zeiger
volatile unsigned char *pDataBuffer = &LeftBuffer;
volatile unsigned char *pRcvBuffer = &RightBuffer;

Wenn die queue voll ist schalte ich das ganze einfach um
1
 
2
pRcvBuffer = &RightBuffer;
3
pDataBuffer = &LeftBuffer;


Das ist jetzt nicht so ausgefuchst wie ein Ringbuffer und braucht auch 
mehr Speicher. Dafür blicke ich da durch kann mir die Daten im Debugger 
anschauen und die Bearbeitung ist auch wesentlich schneller da ich nur 
die Prüfung auf Message Ende (wird eh gebraucht) und overflow habe.
Gast #5127270
Lesenswert?

Hab nun den ganzen Code in Visual Studio getestet. Siehe da es 
funktioniert (ohne malloc usw.)!

Die createFIFO Funktion sieht nun so aus:
1
ringbuffer_handler_t * createFIFO(int size)
2
{
3
  char Memory[6000];
4
  ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)Memory;
5

6
  buffer->readIndex = 0;
7
  buffer->writeIndex = 0;
8
  buffer->size = size;
9

10
  return buffer;
11
}

Warum tut dann das ganze nicht auf dem Mikrocontroller ?
Moderator Persönliche Seite #5127307
Lesenswert?

leo schrieb:
1
> ringbuffer_handler_t * createFIFO(int size)
2
> {
3
>   char Memory[6000];
4
>   ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)Memory;
5
> 
6
>   buffer->readIndex = 0;
7
>   buffer->writeIndex = 0;
8
>   buffer->size = size;
9
> 
10
>   return buffer;
11
> }
>
> Warum tut dann das ganze nicht auf dem Mikrocontroller ?

Weil Du das Array namens "Memory" als Auto-Variable definiert hast, 
welche bei der letzten Geschweiften-Klammer-Zu vernichtet wird. Das 
heißt, der Speicher wird wieder freigegeben und kann für andere Aufgaben 
genutzt werden. Der µC nutzt ihn für anderes und stürzt ab, Dein 
PC-Programm zufälligerweise nicht - vermutlich, weil Du nur den einen 
kleinen Teil des µC-Programms auf den PC portiert hast.

Dir fehlt gundlegendes Wissen in C, dass Du Dir dringend aneignen 
solltest. Sonst würdest Du die Speicherklasse "static" kennen und solch 
einen Anfängerfehler vermeiden.

Schreibe also
1
static char Memory[6000];
statt
1
char Memory[6000];

und teste erneut.

Das erlöst Dich aber nicht von der dringlichen Aufgabe, erst einmal C 
grundlegend zu lernen als solch eine eher fortgeschrittene 
Programmierübung zu lösen.
Gast #5128018
Lesenswert?

Korrektur:
1
#define BUFFER_SIZE      512
2
#define NUMBER_OF_FRAMES  10
3

4
//Struktur fuer die Daten
5
typedef struct
6
{
7
  int length;
8
  char data[BUFFER_SIZE];
9
} userdata_t;
10

11
//Struktur fuer einen Ringbuffer-Handler
12
//wird benoetigt, um mehrere Listen zu verwalten
13
typedef struct
14
{
15
  //Index zum Lesen
16
  int readIndex;
17
  //Index zum Schreiben
18
  int writeIndex;
19
  //Platz fuer Speicherelemente, eigentlicher Buffer
20
  userdata_t fifo[NUMBER_OF_FRAMES];
21
  //Groesse des Buffers, d.h. Anzahl der Elemente
22
  int size;
23
} ringbuffer_handler_t;
24

25

26
/*-------------------------------------------------------------------------*/
27

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

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

45
  return buffer;
46
}
47

48
/*-------------------------------------------------------------------------*/
49

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

72
//eine Funktion, um Elemente aus dem Buffer zu lesen
73
//Parameter *data: Zeiger auf ein Datenelement, das die gelesenen Daten
74
//aufnehmen soll
75
//Parameter *buffer: Zeiger auf Ringbuffer-Handler
76
//Rueckgabewert -1, wenn nicht gelesen werden konnte
77
//Rueckgabewert 1, wenn gelesen werden konnte
78
int readFIFO(userdata_t *data, ringbuffer_handler_t *buffer)
79
{
80
  //der writeIndex zeigt immer auf das naechste zu beschreibende Element,
81
  //d.h. dieses Element ist noch nicht beschrieben worden und enthaelt
82
  //deshalb keine gueltigen Daten
83
  //wenn readIndex also gleich writeIndex, darf nicht gelesen werden
84
  if (buffer->readIndex != buffer->writeIndex)
85
  {
86
    //Daten kopieren
87
    *data = buffer->fifo[buffer->readIndex];
88
    //readIndex fuer das naechste Lesen hochsetzen
89
    buffer->readIndex = buffer->readIndex++ % (buffer->size + 1);
90
    //Rueckgabewert 1, da gelesen wurde
91
    return 1;
92
  }
93
  else
94
    //es konnten keine Daten gelesen werden, da keine gueltigen Daten
95
    //Rueckgabewert also -1
96
    return -1;
97
}
98

99
void main (void)
100
{
101
        ringbuffer_handler_t *local_buffer;
102
  userdata_t write_data;
103
  userdata_t read_data;
104
  int ergebnis;
105

106
  local_buffer = createFIFO(NUMBER_OF_FRAMES);
107

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

111
  write_data.length = 101;
112
  memcpy(write_data.data, DummyData, 101);
113
  appendFIFO(write_data, local_buffer);
114

115
  readFIFO(&read_data, local_buffer);
[/c]
#5128053
Lesenswert?

Deine read/write Index Berechnung ist falsch, es kann also schon mal gar 
nichts funktionieren! (FIFO ist immer "leer")

Und wieso castest du einen Pointer vom Typ userdata auf eine Variable?? 
Erzeuge doch gleich eine lokale Variable vom Typ userdata im Modul. Dann 
sparst du dir auch gleich die ganze Pointerschubserei in den Argumenten. 
Mehr als 1 FIFO brauchst du ja nicht.

mfg
Moderator Persönliche Seite #5128157
Lesenswert?

leo schrieb:
> Korrektur:

Ich habe diesen Code mal durch den gcc unter Linux geschickt. Heraus 
kommen folgende Warnungen:
1
fifo.c: In function ‘appendFIFO’:
2
fifo.c:64:22: warning: operation on ‘buffer->writeIndex’ may be undefined [-Wsequence-point]
3
fifo.c:69:23: warning: operation on ‘buffer->readIndex’ may be undefined [-Wsequence-point]
4
fifo.c: In function ‘readFIFO’:
5
fifo.c:89:23: warning: operation on ‘buffer->readIndex’ may be undefined [-Wsequence-point]
6
fifo.c: In function ‘main’:
7
fifo.c:109:3: warning: implicit declaration of function ‘memset’ [-Wimplicit-function-declaration]
8
fifo.c:109:3: warning: incompatible implicit declaration of built-in function ‘memset’ [enabled by default]
9
fifo.c:112:3: warning: implicit declaration of function ‘memcpy’ [-Wimplicit-function-declaration]
10
fifo.c:112:3: warning: incompatible implicit declaration of built-in function ‘memcpy’ [enabled by default]
11
fifo.c:104:7: warning: unused variable ‘ergebnis’ [-Wunused-variable]

Woher hast Du diesen Code eigentlich her?!? Die obigen Warnungen sind 
durchaus ernstzunehmen (die mit den Sequence-Points).

Beispiel Zeile 64:
1
 buffer->writeIndex = buffer->writeIndex++ % (buffer->size + 1);

buffer->writeIndex wird hier an 2 Stellen manipuliert, nämlich einmal 
links vom Gleichheitszeichen und einmal durch den Postinkrement rechts. 
Welche der beiden Operationen gewinnt, ist undefiniert und kann auf 
jedem System anders sein. Dasselbe gilt für alle anderen 
Sequence-Point-Warnings.

Die memcpy-Warnung stammt (hoffentlich) daher, dass Du hier lediglich 
bei Posten des Codes vergessen hast, das dafür notwendige Include dem 
Code voranzustellen, das Include aber in Deinem Source doch drin ist.

Fazit:
Den Code, den Du hier irgendwo geklaut hast, taugt nichts. Schreibe Dein 
eigenes FIFO-Modul. Wenn Du das nicht hinbekommst, empfehle ich Dir, 
erstmal C systematisch von der Pike auf zu lernen und Dich dann (nach 
ein paar Monaten) nochmal diesem Problem zu widmen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren