Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller: Ringpuffer für UART-Kommunikation


von leo (Gast)


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?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Welcher µC?

von leo (Gast)


Lesenswert?

Es handelt sich hierbei um einen XMC4700 Mikrocontroller von Infineon

von Patrick B. (p51d)


Lesenswert?

https://github.com/andygock/avr-uart/blob/master/uart.c

vielleicht so was? Musst halt das Prinzip portieren
2. Treffer auf google

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?


von S. R. (svenska)


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.

von Hauspapa (Gast)


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

von leo (Gast)


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.

von leo (Gast)


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.

von Cyblord -. (cyblord)


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

von Theor (Gast)


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.

von Sebastian S. (amateur)


Lesenswert?

Hier im Forum, in der Wikipedia und im Netz wirst Du an vielen Stellen 
den vollständigen Code für einen Ringpuffer finden.
Also: "Suchet, so werdet Ihr finden".

von kkuuvvhh (Gast)


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.

von kkuuvvhh (Gast)


Lesenswert?

kleiner Fehler, besser:

6) Ist vor dem Schreiben der Schreibzeiger gleich dem Lesezeiger, dann
wird der Puffer überlaufen oder er war leer.

von A. S. (Gast)


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.

von chris (Gast)


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;
 }

von lui (Gast)


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.

von c-hater (Gast)


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.

von Checker (Gast)


Lesenswert?

Hallo,

ich kann dir nur empfehlen, nimm die uart lib von Peter Fleury und passe 
sie auf deinen Controller an. In der Lib ist alles enthalten.

von leo (Gast)


Lesenswert?

Hallo ich bin dabei die folgende Implementierung auf dieser Seite
https://www.google.de/url?sa=t&rct=j&q=&esrc=s&sou... umzusetzen.
Ich habe nun die Speicherreservierung statisch gestaltet. Allerdings 
sehe ich im Debug Mode, dass die Variablen von der Struktur 
ringbuffer_handler_t nicht initialisiert werden.

von leo (Gast)


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
}

von leo (Gast)


Lesenswert?

Was mache ich da falsch?

von TestX (Gast)


Lesenswert?

Kopier den code erstmal richtig...da fehlt einiges...

von leo (Gast)


Lesenswert?

Das ist ja quasi nur ein Ausschnitt.

von leo (Gast)


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
}

von Mike R. (thesealion)


Lesenswert?

Abgesehen davon ,das dein Beispiel immer noch nicht komplett ist:

In deiner createFIFO() Funktion vermischt du den eigentlichen Handler 
für den Buffer mit dem Datenspeicher.

Ich kann mit nicht vorstellen, das das ganze im Original mit malloc auch 
so aussah.

von Mike R. (thesealion)


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.

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Ich habe nochmals nachgeschaut ich sehe keine Vermischung

von leo (Gast)


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
}

von leo (Gast)


Lesenswert?

In der Funktion createFIFO habe ich ein "return buffer" vergessen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

leo schrieb:
> buffer->fifo[400* size];

statement has no effect.

von leo (Gast)


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.

von Mike R. (thesealion)


Lesenswert?

Dann solltest du dir noch einmal ansehen, was du hier machst
1
 buffer->fifo = (userdata_t *)&Fifo;
und nicht nur raten. (Es hilft auch die Warnungen und Errors des 
Compilers zu lesen und nicht einfach alles passend zu casten).

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Der Compiler zeigt bei mir keine Warnung/Fehler an.

Es wird hier der Speicher Fifo auf die Struktur userdata_t gecastet.

von Mike R. (thesealion)


Lesenswert?

Dann legt doch Fifo gleich als
1
userdata_t Fifo[10]; //wenn du 10 Elemente haben möchtest
an und schau, was der compiler dazu sagt (dann bitte ohne cast).

von leo (Gast)


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;

von leo (Gast)


Lesenswert?

Der Controller stürtzt dann ab wenn diese Zeile ausgeführt wird:
1
buffer->fifo[buffer->writeIndex] = data;

von leo (Gast)


Lesenswert?

Das fifo Element habe ich doch mit einer festen Größe angegeben und 
trotzdem funktioniert das hinzufügen von Elementen nicht.

von Mike R. (thesealion)


Lesenswert?

Natürlich funktioniert das nicht, weil dein *buffer nicht dort hin 
zeigt, wo du denkst.

http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/012_c_zeiger_007.htm

Vorher war der FiFo Pointer ebenfalls nicht korrekt aber das hast du ja 
scheinbar korrigiert, auch wenn du immer noch nicht weißt wie ;-)

von leo (Gast)


Lesenswert?

Stehe voll auf dem Schlauch.

von leo (Gast)


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
}

von J. F. (Firma: Père Lachaise) (rect)


Lesenswert?

Wieso wirfst du nicht mal einen Debugger an und überprüfst deine Zeiger 
zur Laufzeit ob diese auch wirklich dahin zeigen wo du denkst?

von Mike R. (thesealion)


Lesenswert?

Lies dir einfach den Link von mir durch. Insbesondere, wie man einen 
Pointer auf ein Array verwendet (was du in der Funktion createFIFO() 
Code 2 mal versuchst)

von leo (Gast)


Lesenswert?

Ok die Zeiger sind falsch.

Die Adresse von buffer in der create FIFO Funktion ist nicht gleich mit 
der Adresse von buffer in der appendFIFO Funktion. Mir fällt keine 
Lösung ein.

von Mike R. (thesealion)


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"

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Ok dann müsste die Codezeile so aussehen (ohne Adressoperator):
1
ringbuffer_handler_t *buffer = (ringbuffer_handler_t *)Memory;

von leo (Gast)


Lesenswert?

Nochmals vielen Dank für eure Hilfe.

von leo (Gast)


Lesenswert?

Ich bekomme das Problem nicht gelöst.

von AndererGast (Gast)


Lesenswert?

wie könntest Du das gelernte jetzt auf die Zeile

leo schrieb:
> buffer->fifo = (userdata_t *)&Fifo;

anwenden?

von leo (Gast)


Lesenswert?

Ich komme nicht drauf! Sorry!

von Falk B. (falk)


Lesenswert?

@ leo (Gast)

>Ich bekomme das Problem nicht gelöst.

Was nicht verwunderlich ist, wenn man diese ganzen hektischen Unsinn 
hier sieht. Zum Programmieren braucht es Ruhe und Zeit.

von leo (Gast)


Lesenswert?

Ich drehe noch durch grrrrrrrrrrrrrrrr

von leo (Gast)


Lesenswert?

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

von Vincent H. (vinci)


Lesenswert?

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

von leo (Gast)


Lesenswert?

Könnt ihr mir da nicht noch eine weitere Hilfestellung geben?

von Falk B. (falk)


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

von leo (Gast)


Lesenswert?

Bin hier quasi alleine.

von leo (Gast)


Lesenswert?

Im Netz habe ich bereits schon recherchiert. Diese Lösung würde zu 
meinem Problem passen. Ich benötige einen Ringpuffer der Nachrichten in 
variabler Länge Speichert und wieder löscht.

von leo (Gast)


Lesenswert?

Werde nun aufgeben. Vielen Dank für eure Unterstützung!

von Der Andere (Gast)


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?

von Falk B. (falk)


Lesenswert?

Was für ein Troll!

von X4U (Gast)


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.

von X4U (Gast)


Lesenswert?

X4U schrieb:
> Wenn die queue voll ist schalte ich das ganze einfach um
>
> pRcvBuffer = &RightBuffer;
> pDataBuffer = &LeftBuffer;

Sorry da fehlt noch Daten links -> rechts :
1
pRcvBuffer = &LeftBuffer;
2
pDataBuffer = &RightBuffer;

von Jonas B. (jibi)


Lesenswert?

>Deshalb habe ich den "Ringbuffer" durchgeschnitten und zwei Queues draus
>gemacht.

https://de.wikipedia.org/wiki/Doppelpufferung

Gruß J

von leo (Gast)


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 ?

von Frank M. (ukw) (Moderator) Benutzerseite


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.

: Bearbeitet durch Moderator
von Eric B. (beric)


Lesenswert?

leo schrieb:
> 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
>

Das wird spassig sobald du mehr als 1 FIFO anlegen willst...
(auch wenn Memory static ist).

von leo (Gast)


Lesenswert?

Guten Morgen Frank M.,

trotz Änderung funktioniert der FIFO nicht auf dem Mikrocontroller.

von leo (Gast)


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]

von leo (Gast)


Lesenswert?

Ich sehe in dem Code keinen Fehler. Wie gesagt auf dem PC mit Visual 
Studio funktioniert der Code prima.

von Felix F. (wiesel8)


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

: Bearbeitet durch User
von leo (Gast)


Lesenswert?

Ok. Und warum funktioniert der Code in Visual Studio?

von leo (Gast)


Lesenswert?

In der createFIFO Funktion wird size nicht auf 0 gesetzt. Somit kackt 
der Controller in der appendFIFO Funktion ab.

von leo (Gast)


Lesenswert?

Des Weiteren habe ich der Funktion createFIFO einen flaschen Wert 
übergeben. Ich brauche ja nutr ein FIFO somit ist der Wert 1.

von leo (Gast)


Lesenswert?

Also müsste buffer->size auf 1 gesetzt werden. Wird aber nicht gemacht.
Warum????

von batman (Gast)


Lesenswert?

Such dir ein anderes Hobby.

von Frank M. (ukw) (Moderator) Benutzerseite


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.

: Bearbeitet durch Moderator
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.