Hm.
Welcher Anfänger hat den Artikel "FIFO" verbrochen ?
uint8_t BufferIn(uint8_t byte)
{
//if (buffer.write >= BUFFER_SIZE)
// buffer.write = 0; // erhöht sicherheit
if ( ( buffer.write + 1 == buffer.read ) ||
( buffer.read == 0 && buffer.write + 1 == BUFFER_SIZE ) )
return BUFFER_FAIL; // voll
Hoffentlich hat noch niemand diesen Unfug gelesen ?
Man stelle sich das mal vor, und setze im Geiste BUFFER_SIZE=2 und
versuche zwei Elemente einzufügen, dann wirds offensichtlicher..
Setzen. sechs.
Und das auskommentierte: Was bitte erhöht da die Sicherheit ?
Das kaschiert allerhöchstens einen BUG der woanders gemacht wurde.
Oder soll das für den Fall da sein, daß sich die CPU aus versehen mal
verrechnet ?
Frank schrieb:> Man stelle sich das mal vor, und setze im Geiste BUFFER_SIZE=2 und> versuche zwei Elemente einzufügen, dann wirds offensichtlicher..
Du willst also in einen Ringbuffer der Größe 2 zwei Elemente einfügen.
Dann steht der Schreibindex unweigerlich auf dem Leseindex, und das ist
die Abfrage-Bedingung für "Buffer ist leer" beim Lesen. Dir ist schon
klar, wie ein Ringbuffer überhaupt funktioniert, oder?
> Und das auskommentierte: Was bitte erhöht da die Sicherheit ?
Das nennt man "defensive Programmierung", obwohl man in dem Fall
natürlich besser stattdessen mit einem Fehlercode abbrechen sollte.
Frank schrieb:> Verrate mir mal, warum man in ein Array daß zwei Elementen Platz> bietet, keine zwei Elemente schreiben kann...??
OK, Du weißt also, weas ein Array ist. Das ist schön. Dann befasse Dich
auch mal damit, was ein RINGBUFFER ist und wie der funktioniert, bevor
Du noch mehr Unsinn erzählst.
Deine Frage ist unsinnig gestellt. Die Frage ist, wieso man in einen
Ringbuffer der Größe N nicht N Elemente schreiben kann, und den Grund
habe ich Dir bereits in meinem Vorposting verraten.
und wenn Du schon von "intellektuellen Schwierigkeiten" schreibst.. ja,
die sind auf Deiner Seite. Wegen des Dunning-Kruger-Effektes. Du hast
dermaßen keine Ahnung, daß Du nichtmal merkst, daß Du keine hast. Sorry,
so sieht es aus.
Bei einem Ringpuffer MUSS man also grundsätzlich ein Element
verschwenden, wenn es nach dir geht.
Guck, so kann man feststellen ob im Puffer noch Platz ist:
(Ich mach mir jetzt nicht die Mühe die Namen des "Beispiels" zu
verwenden:
int free = (head >= tail) ? (SIZE_OF_BUFFER - 1 - head + tail) : (tail -
head - 1);
Das habe ich mir übrigens nicht selbst ausgedacht, sondern ist Standard.
Wenn free > 0 kannst du einfügen.
Und, oh Wunder, plötzlich muss man kein Element mehr verschwenden.
Es kommt vor, daß so ein Element mehrere KB groß ist. Aber wenns nach
Dir geht, ist man gezwungen die zu verschwenden ?
Frank schrieb:> int free = (head >= tail)
Dann gehen wir das mal durch unter der Annahme SIZE_OF_BUFFER==2, und zu
Anfang seien head und tail beide auf 0. Der Buffer sei leer. Das erste
Einfügen ist trivial, also ist head jetzt 1.
Jetzt soll nochmal eingefügt werden.
head>=tail
1>=0 ist TRUE, also ist free damit
SIZE_OF_BUFFER - 1 - head + tail
2 - 1 - 1 + 0
0
> Wenn free > 0 kannst du einfügen
Mithin kannst Du nach dem Einfügen eines Elementes kein zweites
einfügen.
Du bist am Zug.
Da ein Mod beschlossen hat, das zu verschieben, daß Gäste nicht mehr auf
den Beitrag antworten können, ist die Diskussion damit für mich leider
beendet. Vielen Dank, liebe Moderation.
Nop schrieb:> Da ein Mod beschlossen hat, das zu verschieben, daß Gäste nicht mehr auf> den Beitrag antworten können, ist die Diskussion damit für mich leider> beendet. Vielen Dank, liebe Moderation.
War sowieso überflüssig, hätte auch gleich kpl. in den Papierkorb
verschoben werden können.
Nop schrieb:> Da ein Mod beschlossen hat, das zu verschieben, daß Gäste nicht mehr auf> den Beitrag antworten können, ist die Diskussion damit für mich leider> beendet. Vielen Dank, liebe Moderation.
Es hat mit "Projekte und Code" einfach gar nichts zu tun. Da war es
ursprünglich hingerotzt worden.
Wie man das in Software macht weiß ich nicht, aber in Hardware gibt es
drei Fälle:
- Im gleichen Takt wird aus dem FIFO gelesen und geschrieben. Das ist OK
und da kann der FIFO auch gerne voll sein.
- Es wird nur gelesen. FIFO darf nicht leer sein.
- Es wird nur geschrieben. FIFO darf nicht voll sein.
Man muss jedenfalls keinen Speicherplatz verschwenden.
Wenn hier etwas hingerotzt ist, dann der Artikel .)
Gustl, danke.
Ok, ich gebe zu, das int free... reicht nicht aus. Im Gegensatz zu
anderen hier habe ich kein Problem damit Fehler zuzugeben :)
Aber so geht es tatsächlich, ohne ein Element zu verschwenden:
#define BUFFER_FAIL 0
#define BUFFER_SUCCESS 1
#define BUFFER_SIZE 2
struct Buffer {
uint8_t data[BUFFER_SIZE];
uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
uint8_t write;
uint8_t count; // zähler <!--- NEU
} buffer = {{}, 0, 0};
//
// Gibt an wieviel Platz im Puffer ist
//
//
uint8_t BufferAvailable(void) {
return BUFFER_SIZE - buffer.count;
}
//
// Stellt 1 Byte in den Ringbuffer
//
// Returns:
// BUFFER_FAIL der Ringbuffer ist voll. Es kann kein weiteres
Byte gespeichert werden
// BUFFER_SUCCESS das Byte wurde gespeichert
//
uint8_t BufferIn(uint8_t byte)
{
if (BufferAvailable() < 1) return BUFFER_FAIL; //Voll
buffer.data[buffer.write] = byte;
buffer.write++;
if (buffer.write >= BUFFER_SIZE)
buffer.write = 0;
buffer.count++;
return BUFFER_SUCCESS;
}
//
// Holt 1 Byte aus dem Ringbuffer, sofern mindestens eines abholbereit
ist
//
// Returns:
// BUFFER_FAIL der Ringbuffer ist leer. Es kann kein Byte
geliefert werden.
// BUFFER_SUCCESS 1 Byte wurde geliefert
//
uint8_t BufferOut(uint8_t *pByte)
{
if (buffer.count == 0)
return BUFFER_FAIL;
*pByte = buffer.data[buffer.read];
buffer.read++;
if (buffer.read >= BUFFER_SIZE)
buffer.read = 0;
buffer.count--;
return BUFFER_SUCCESS;
}
Und bevor jetzt jemand schreit, daß der Zähler auch Platz braucht:
Stimmt!
Aber Ringpuffer werden auch für größere Elemente als Bytes verwendet.
Bitte tut euch selbst den Gefallen und korrigiert den Artikel, oder fügt
zumindest eine Info hinzu.
Vor allem dieser oben erwähnte wirklich fürchterliche Kommentar sollte
raus.
> Bitte tut euch selbst den Gefallen und korrigiert den Artikel, oder fügt> zumindest eine Info hinzu. Vor allem dieser oben erwähnte wirklich> fürchterliche Kommentar sollte raus.
Der steht im Wiki - was hindert Dich daran, das selbst in Ordnung zu
bringen?
Du hast Deine "Kritik" in "Projekte & Code" abgesetzt, da hat sie
schlichtweg nichts verloren. Hättest Du sie in "Smarthome" abgesetzt,
oder in "Analoge Elektronik", sähe das nicht anders aus.
"Wiki":War mir nicht bekannt. Ich überlasse das trotzdem lieber euch.
Bitte nenne mir eine Rubrik die besser passt, dann poste ich das nächste
mal dort. Das "Offtopic" der richtige Ort ist - darauf muss man erstmal
kommen.
Frank schrieb:> Welcher Anfänger hat den Artikel "FIFO" verbrochen ?
1. du plenkst. https://de.wikipedia.org/wiki/Plenk
Bitte stell das ab.
2. ein Wiki ist ein Wiki ist ein Wiki. Artikel werden nicht dadurch
besser, daß jemand (s)einen Rant ins Forum kotzt, sondern dadurch
daß sie korrigiert werden. Klick dir einen Account (hast du wohl
mittlerweile?) und korrigiere den Artikel. Fertig.
Damit ist allen Beteiligten besser gedient.
PS: falls es Diskussionsbedarf zu einem Artikel im Wiki gibt: dafür gibt
es extra den Link "Diskussion" im linken Menu unter "Dieser Artikel"
...mich verstört auch die Tatsache, dass die Implementierung mit sperren
der Interrupts empfohlen wird.
Bei geschickter Programmierung ist das überhaupt nicht notwendig, da man
das Update der Pointer atomar mit einer Zuweisung am Ende machen kann.
Die Variante mit dem Counter ist dann allerdings nicht möglich, da die
"++" Operation nicht zwingend atomar ist.
Markus M. schrieb:> ...mich verstört auch die Tatsache, dass die Implementierung mit sperren> der Interrupts empfohlen wird.>> Bei geschickter Programmierung ist das überhaupt nicht notwendig, da man> das Update der Pointer atomar mit einer Zuweisung am Ende machen kann.
Das will ich sehen!
Markus M. schrieb:> da man das Update der Pointer atomar mit einer Zuweisung am Ende machen> kann.
Atomare 16-Bit-Operationen auf einem 8-Bit-µC?
Das ginge allenfalls, wenn nicht mit Pointern, sondern Array-Indices
gearbeitet würde, und diese nur 8 Bit groß sind, das Fifo also maximal
256 Einträge enthalten dürfte.
Oder der Compiler müsste wissen, daß er die Pointer zwingend in einem
16-Bit-Indexregister des µCs vorzuhalten hat, damit er sie atomar
speichern kann. Welcher Compiler aber weiß etwas von atomaren
Operationen und den interessanten Auswirkungen von Interrupts?
Frank schrieb:> Verrate mir mal, warum man in ein Array daß zwei Elementen Platz> bietet,> keine zwei Elemente schreiben kann...??
Aus Performancegründen wird lediglich mit Head und Tail Indizes
gearbeiten. Dafür nimmt man gerne den einen verschwendeten Spot in Kauf.
Siehe bspw. die Implementierung von boost::lockfree::spsc_queue.
Rufus Τ. F. schrieb:> Markus M. schrieb:>> da man das Update der Pointer atomar mit einer Zuweisung am Ende machen>> kann.>> Atomare 16-Bit-Operationen auf einem 8-Bit-µC?>> Das ginge allenfalls, wenn nicht mit Pointern, sondern Array-Indices> gearbeitet würde, und diese nur 8 Bit groß sind, das Fifo also maximal> 256 Einträge enthalten dürfte.
Ja, genauso tut es doch der Code hier im Beispiel. Es wird uint8_t
verwendet. Ich nahm jetzt mal diese Implementierung als Ausgangspunkt,
auch wenn Pointer ggf. effizienter sind.
Auf einem 32 Bit Controller sollte das ja kein Problem sein.
Wenn man beim Schreiben so vorgeht:
- Wert in das aktuell referenzierte Byte im FIFO schreiben
- FIFO Schreibpointer updaten (Voraussetzung: atomar)
Und beim Lesen so:
- Wert aus dem aktuell refrenzierten Byte aus dem FIFO lesen
- FIFO Lesepointer updaten (Voraussetzung: atomar)
Müssen KEINE Interrupts gesperrt werden.