Forum: Mikrocontroller und Digitale Elektronik FIFO Buffer in C


von Klaus (Gast)


Lesenswert?

Wie implementier ich einen FIFO Buffer in C? Hat jemand ein Beispiel 
dazu?

Thx

von ARM-Fan (Gast)


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.

von Peter D. (peda)


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

von Andreas S. (andreas12)


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;

von ARM-Fan (Gast)


Lesenswert?

@Andreas Schoepf: Yup! genauso hab ichs gemeint :-)

von Klaus (Gast)


Lesenswert?

Wo werden denn hier die Pointer definiert? Welches ist der Pointer?

von Stefan E. (sternst)


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?

von Karl H. (kbuchegg)


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.

von Peter D. (peda)


Lesenswert?

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

Ja.
1
#if((CON_OUT_BUF_SIZE|CON_OUT_MASK) != (CON_OUT_BUF_SIZE+CON_OUT_MASK))
2
#error bad CON_OUT_BUF_SIZE !!!
3
#endif


Peter

von spess53 (Gast)


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

von Stefan E. (sternst)


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.

von Schwurbl (Gast)


Lesenswert?

Ne, dann wärs ein LIFO oder auch Stack.

von Schwurbl (Gast)


Lesenswert?

Mist :-)

von Peter D. (peda)


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

von Stefan Salewski (Gast)


Lesenswert?


von krase (Gast)


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)

von Ulrich (Gast)


Lesenswert?

seit Jahren verwende ich immer das hier:

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

von Martin L. (Gast)


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.

von let (Gast)


Lesenswert?

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

von Martin L. (Gast)


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.

von let (Gast)


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.

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.