mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik FIFO Buffer in C


Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie implementier ich einen FIFO Buffer in C? Hat jemand ein Beispiel 
dazu?

Thx

Autor: ARM-Fan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du legst ein Array vom Typ der zu speichernden Daten an.
Du definierst zwei Zeiger. Einen für die Stelle, an die du
Daten schreibst, einen für die Stelle, wo du die Daten wieder ausliest.
Nach jeder Schreib- oder Leseoperation erhöhst du den jeweiligen
Zeiger. Wenn ein Zeiger über das Ende des Arrays hinausgeht, setzt
du ihn wieder auf Null.

Soweit das mal ganz grob umrissen.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus wrote:
> Wie implementier ich einen FIFO Buffer in C? Hat jemand ein Beispiel
> dazu?

Ja.

Beitrag "LCD über nur einen IO-Pin ansteuern"

Anhang im 12. Beitrag.


Peter

Autor: Andreas Schoepf (andreas12)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Source Schnippsel:
////////////////////////////////////
#define CON_OUT_BUF_SIZE           64

/* Buffer masks */
#define CON_OUT_MASK               (CON_OUT_BUF_SIZE-1ul)

/* Buffer read / write macros */
#define CON_BUF_RESET(Fifo)      (Fifo->rd_idx = Fifo->wr_idx = 0)
#define CON_BUF_WR(Fifo, dataIn) (Fifo->data[CON_OUT_MASK & 
Fifo->wr_idx++] = (dataIn))
#define CON_BUF_RD(Fifo)         (Fifo->data[CON_OUT_MASK & 
Fifo->rd_idx++])
#define CON_BUF_EMPTY(Fifo)      ((CON_OUT_MASK & Fifo->rd_idx) == 
(CON_OUT_MASK & Fifo->wr_idx))
#define CON_BUF_FULL(Fifo)       ((CON_OUT_MASK & Fifo->rd_idx) == 
(CON_OUT_MASK & Fifo->wr_idx+1))
#define CON_BUF_COUNT(Fifo)      ((CON_OUT_MASK & Fifo.wr_idx) - 
(CON_OUT_MASK & Fifo.rd_idx))

// Serial output buffer
typedef struct {
  unsigned char data[CON_OUT_BUF_SIZE];
  unsigned int wr_idx;
  unsigned int rd_idx;
} CON_Fifo_t;

Autor: ARM-Fan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Andreas Schoepf: Yup! genauso hab ichs gemeint :-)

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wo werden denn hier die Pointer definiert? Welches ist der Pointer?

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht sollte man noch dazu schreiben, dass CON_OUT_BUF_SIZE 
zwingend eine Zweierpotenz sein muss.

> #define CON_BUF_COUNT(Fifo)      ((CON_OUT_MASK & Fifo.wr_idx) -
> (CON_OUT_MASK & Fifo.rd_idx))

Und wenn wr_idx < rd_idx ist?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus wrote:
> Wo werden denn hier die Pointer definiert? Welches ist der Pointer?

Wozu brauchst du einen Pointer?
Andread arbeitet auf einem ganz normalen Array und nimmt
Inidizes um in das Array zuzugreifen.
Ist doch völlig ausreichend.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stefan Ernst wrote:
> Vielleicht sollte man noch dazu schreiben, dass CON_OUT_BUF_SIZE
> zwingend eine Zweierpotenz sein muss.

Ja.

#if((CON_OUT_BUF_SIZE|CON_OUT_MASK) != (CON_OUT_BUF_SIZE+CON_OUT_MASK))
#error bad CON_OUT_BUF_SIZE !!!
#endif



Peter

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

>Du legst ein Array vom Typ der zu speichernden Daten an.
>Du definierst zwei Zeiger. Einen für die Stelle, an die du
>Daten schreibst, einen für die Stelle, wo du die Daten wieder ausliest.
>Nach jeder Schreib- oder Leseoperation erhöhst du den jeweiligen...

Das ist ein Ringpuffer und kein FIFO. Da reicht ein Zeiger, der nach dem 
Schreiben um 1 erhöht und vor dem Lesen um 1 erniedrigt wird.

MfG Spess

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das ist ein Ringpuffer und kein FIFO. Da reicht ein Zeiger, der nach dem
> Schreiben um 1 erhöht und vor dem Lesen um 1 erniedrigt wird.

Ein Ringpuffer ist ein FIFO.
Deins ist ein Stack, oder auch LIFO.

Autor: Schwurbl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne, dann wärs ein LIFO oder auch Stack.

Autor: Schwurbl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mist :-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab das mal mit Maske probiert, spart tatsächlich einige Bytes Code.

Blöd ist nur, daß auch der SRAM in 2-er Potenzen organisiert ist.

Wenn ich also nen Puffer beim ATtiny45 einrichte und 18 Byte für Stack 
und Variablen reserviere, kann ich nur 64 Byte Puffer einrichten.

Ich bleibe daher beim Vergleichen und 0 setzen, dann kann ich sogar 110 
Byte Puffer nehmen, also fast das doppelte!


Peter

Autor: Stefan Salewski (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: krase (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> #define CON_BUF_COUNT(Fifo)      ((CON_OUT_MASK & Fifo.wr_idx) -
> (CON_OUT_MASK & Fifo.rd_idx))

So funktioniert es auch wenn wr_idx < rd_idx ist:

#define CON_BUF_COUNT(Fifo)  ((Fifo.wr_idx - Fifo.rd_idx) & 
CON_OUT_MASK)

Autor: Ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
seit Jahren verwende ich immer das hier:

http://www.roboternetz.de/wissen/index.php/FIFO_mit_avr-gcc

Autor: Martin L. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man könnte ja anstatt

CON_OUT_MASK & Fifo->wr_idx++
auch
(Fifo->wr_idx++) % CON_OUT_BUF_SIZE

verwenden und hätte damit das Problem der auf Zweierpotenzen 
eingeschränkten Puffergröße umgangen. Sollte auch nicht mehr
Platz im .text Segment brauchen und auch nicht langsamer sein.

Viele Grüße,
 Martin L.

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
^ Ich denke schon das eine 16Bit Division sowohl größer als auch
langsamer ist als ein 'logical and'.

Autor: Martin Laabs (mla)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist ja nur ein 8-Bit Modulo notwendig. Aber stimmt - der Atmel hat 
keinen "mod"-Befehl. (Übrigens brauchen bessere Prozessoren bei 16 oder 
32bit Berechnungen deren höherwertigen Bits null sind nicht länger als 
mit entsprechend kleineren Registern.)

Viele Grüße,
 Martin L.

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur wenige Controller haben einen div- oder mod Befehl. Mir fällt
da nur der Cortex M3 ein. Das traurige am C Standard ist das
solche Berechnungen immer mit mindestens 16Bit durchgeführt werden.
Vielleicht optimiert der AVR-GCC das in diesem Fall und rechnet
tatsächlich nur mit 8 Bits. Bei einer Multiplikation macht er das
jedenfalls nicht. Da werden 8Bit Operanden auf 16Bit aufgebohrt und
das Ergebnis wieder auf 8Bit zurückgestutzt.

>(Übrigens brauchen bessere Prozessoren bei 16 oder
>32bit Berechnungen deren höherwertigen Bits null sind nicht länger als
>mit entsprechend kleineren Registern.)

Ich nehme an du meinst 16/32 Bit Prozessoren?
Interessanterweise dauert es auf solchen Prozessoren mitunter sogar
länger wenn mit kleinen Datentypen gerechnet werden soll.
Da werden nämlich Ergebnisse die ja in z.B. 32Bit Registern stehen
erst mit Masken verknüpft um die oberen Bits auszublenden.
Deshalb gibt es in der <stdint.h> die 'fast' Typen.
Also z.B. uint_fast8_t der bei einem ARM7 als 'unsigned long'
definiert ist.
Ergo: Die kleinsten Datentypen sind nicht immer die Besten.

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.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

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