Frage zu "Ringpuffer"

Es sei ja angeblich viel besser mit einem & zu arbeiten, was dass überlaufen anbetrifft.
Das kann man ja nicht grundsätzlich sagen. Es geht hier ja nur um eine Zeile, eine Abfrage. Es kommt auch auf die weiteren Features des RingBuffers an und auf solche Einschränkungen wie BufferSize = n^2. Hier wird die Grenze eben mal mit if abgefragt, falls überhaupt, sind das grob in der Größenordnung zwei Maschinenzyklen mehr. Das ist normalerweise extrem vernachlässigbar, wenn das zeitlich zu knapp ist, dann sollte man eine andere Mikrocontrollerfamilie verwenden, die mehr Mips hat.

Und mit der Routine lese ich immer den ältesten Eintrag aus?
Ja, und dieser wird dann auch gleich entfernt.

Mit _Peek liest du ihn, der bleibt aber im Buffer.

Aufpassen musst du hier: Ich hatte das erst mit 16Bit Buffergröße (uint16_t Index), hatte es aber nachträglich verkleinert, also die Buffergröße nicht über 8Bit einstellen.
 
Okay.

Dann kann ich da ja drauf aufsetzen, was meinen "CAN Buffer" anbelangt.
Rein Theoretisch kann ich ja das Array wo die Daten drinn gespeichert werden aufbohren oder?
Also ich müsste pro Message 9 Parameter speichern ( 1 x 16 Bit und der Rest 8 Bit )...
 
Rein Theoretisch kann ich ja das Array wo die Daten drinn gespeichert werden aufbohren oder?
Also ich müsste pro Message 9 Parameter speichern ( 1 x 16 Bit und der Rest 8 Bit )...

Hmmm, ich weiß nicht genau, was du mit "aufbohren" meinst (die Puffergröße?). Im zuvor reingestellten Sourcecode wird 128Byte Puffergröße verwendet, wenn du nicht woanders große Arrays hast, könnte das ja ausreichen. Wenn du noch mehr benötigst, versuch mal das mit dem Index auf 16Bit zu erweitern (1kB Größe zB). Ich würde aber erst einmal "klein" anfangen und es grundsätzlich zum laufen bringen. Vielleicht verwendest du kein Byte Array, sondern ein struct Array. In der struct ist dann eine 2Byte Message plus zugehörige 9 Byte Parameter.
 
Und was hat es mit dem "SREG" Register aufsich? Reicht da nicht "static" & "volatile"? Geschwindigkeit?
 
Im SREG steht drin ob Interrupts global aktiviert oder deaktiviert sind. Aber das ist halt nur ein Bit von 8, daher kopiert er den Zustand, deaktiviert die Interrupts und setzt danach SREG zurück (was gleichzeitig die Interrupts wieder aktiviert) ;)

In ASM könnte man auch CLI und SEI nehmen, das würde nur das Interrupt Bit verändern, aber sollte irgendwas Anderes dazwischen das SREG verändern (beispielsweise bei Addition und Überlauf) dann hast du da noch alte Leichen drin. Kann man machen, aber nur wenn man genau weiß was man tut.
 
Und was genau bringt mir das? Das ich ne Variable spare?
 
Denk dran dass wenn du mit Interrupts arbeitest das was grade in der Sub Main abläuft jederzeit unterbrochen wird. Dann wird die ISR ausgeführt und danach wieder zurück gesprungen wo er vorher war.

Beispiel du willst in der Main eine 16 Bit Zahl erhöhen.
Das sind aber 2 Takte für die CPU.

Addiere unteres Byte x zu Ergebnis y - ggf. Überlauf, was das SREG verändert
Jetzt kommt ein Interrupt der möglicherweise das Überlauf Bit im SREG löscht.
Addiere oberes Byte x zu Ergebnis y - Ergebnis falsch, da der Überlauf gelöscht wurde.

Daher ist man immer auf der sicheren Seite wenn man das SREG sichert. Außer man weiß genau was man tut. Sonst kann es zu den merkwürdigsten Problemen kommen die teilweise auch nicht reproduzierbar sind. Klar, das schluckt ein Byte Speicher mehr, aber das sollte man lieber akzeptieren.
 
In ASM könnte man auch CLI und SEI nehmen, das würde nur das Interrupt Bit verändern

Mach ich hier ja im Prinzip auch. Ich kann hier also wie in Assembler einfach sei() und cli() verwenden. Dies sind die Macros dafür und machen genau das selbe wie in Assembler.

Aber:

Was wäre aber, wenn zunächst Interrupts global gar nicht freigegeben wären und ich rufe meine Funktion in der ich Interrups global abschalte und wieder einschalte. Das darf ja nicht passieren, deshalb schaue ich zunächst, wie der Zusstand vom I Flag ist, dafür merke ich mir einfach das Statusregister SREG. Die Interrupts werden durch meine Funktion also nur dann wieder global aktiviert, wenn diese vor Aufruf meiner Funktion aktiviert waren.
 
Das ist natürlich auch ein Grund :)
 
Sollte ich also, wenn ich irgendwas mit Interrupts mache, das SREG jedesmal vorher sichern?
Habe ich bislang nie gemacht...
 
Also SREG muss man nicht sichern, ich schaue einfach nur ob die Interrupts vorher aktiviert waren.

Die Interurpts muss ich dann deaktivieren, wenn eine Interruptserviceroutine ebenfalls mit dem Buffer arbeiten kann (was oft der Fall ist). Während die Funktion auf den buffer zugreift könnte die ISR Index und Werte ändern.
 
Wenn du die Interrupts temporär deaktivierst wäre es besser. Häufig zwar nicht benötigt, aber wen störts? Um Dirk's Beispiel zu nehmen… Man verwendet einzelne Routinen ja öfters wieder, auch in anderen Programmen. Und dann funktioniert die Routine zwar in Programm 1 und 2, aber im Dritten nicht. Von daher lieber gleich vernünftig.

@Dirk du hast fixe Finger ^^
 
Man verwendet einzelne Routinen ja öfters wieder, auch in anderen Programmen. Und dann funktioniert die Routine zwar in Programm 1 und 2, aber im Dritten nicht. Von daher lieber gleich vernünftig.

Genau!
 
@Dirk

Ich habe mir das jetzt so gedacht für meinen "CAN Buffer"



CodeBox C
void RingBuffer_Insert(uint16_t id, uint8_t msg_lght, uint8_t data, uint8_t byte_number)
{
   switch(byte_number)
   {
     case 0: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   data & 0x000F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000] = data;}break;
     case 1: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,data & 0x000F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000] = data;}break;
     case 2: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,0x0000,data & 0x000F,0x0000,0x0000,0x0000,0x0000,0x0000] = data;}break;
     case 3: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,0x0000,0x0000,data & 0x000F,0x0000,0x0000,0x0000,0x0000] = data;}break;
     case 4: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,0x0000,0x0000,0x0000,data & 0x000F,0x0000,0x0000,0x0000] = data;}break;
     case 5: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,0x0000,0x0000,0x0000,0x0000,data & 0x000F,0x0000,0x0000] = data;}break;
     case 6: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,data & 0x000F,0x0000] = data;}break;
     case 7: {RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F,   0x0000,0x0000,0x000F,0x0000,0x0000,0x0000,0x0000,data & 0x000F] = data;}break;
   }
   
   RingBufferInfo.In++;
   
   if (RingBufferInfo.In == RingBufferInfo.Size)
   RingBufferInfo.In = 0;
   
   uint8_t int_reg = SREG;
   cli();
   
   RingBufferInfo.Count++;
   
   SREG = int_reg;
}


Nur die Routine zum auslesen... Wie mache ich das? Pointer?
 
Deinen Code innerhalb des Switch-Case Blocks verstehe ich leider komplett nicht.
 
Schließe mich an. Für mich ist das kompletter Unsinn, sorry.
Wenn da ein Sinn hinter steht dann verstehe ich den nicht. Oder du hast noch nicht wirklich verstanden wie ein Ring Puffer funktioniert. Eins von Beiden.
 
Das Problem ist, dass ich 10 Bytes pro Message bekomme. Die müssen untergebracht werden.

Hier ist ein Teil meiner CAN Empfangsroutine:



CodeBox C
  // get data of selected MOb
   for (i=0; i<recMsg.length; i++)
   {
    recMsg.data[i] = CANMSG;
   }


Die ID und die Message_Lenght fallen auch unter eine "CAN - Message"
Also muss ich für "einen" Buffereintrag 10 Einträge speichern können...
Wieso ist das "Unsinn"?
Wie kriege ich sonst die 10 Einträge unter? Gibt bestimmt eine andere Möglichkeit, desshalb frage ich ja auch hier ;)

So sollte es aussehen:


CodeBox C
 [NumberOfMessage][ID,MessageLenght,Byte0,Byte1,Byte2,Byte3,Byte4,Byte5,Byte6,Byte7]
 
Zuletzt bearbeitet:
Ich hatte mir schon gedacht, dass du einen zweidimensionalen Buffer verwenden möchtest, aber so eine Zeile verstehe ich einfach nicht ...
RingBuffer[RingBufferInfo.In][id,msg_lght & 0x000F, data & 0x000F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000] = data;

Ich hatte ja schon einmal erwähnt, dass ich wahrscheinlich ein Array einer struct verwenden würde. Leider habe ich eigentlich im Moment gar keine Zeit das zu näher zu erklären, deshalb hier nur mal ein paar Zeilen Code, vielleicht kannst du dir hier selber etwas zusammenbasteln ...




CodeBox C
// Definition
typedef struct {
   uint16_t Message;
   uint8_t DataLength;
   uint8_t   Data[9];
} tCANMSG;

tCANMSG RingBuffer[100];  // 100 x 12Byte = 1200Byte!

// Zugriff darauf
RingBuffer[4].Message = 1234;
RingBuffer[4].DataLength = 9;
for (uint8_t i=0; i<9; i++) RingBuffer[4].Data[i] = 0;


// Speichern im buffer
tCANMSG meine_can_message;  // privat definieren, in einer Funktion die CAN empfängt.
// Variable mit CAN Daten füllen
// und der Buffer_Insert Funktion übergeben

// Die Bufferfunktionen müssten natürlich angepasst werden. Im Moment wird nur ein uint8_t gespeichert, man müsste die Structure speichern.
 
Unsinn deswegen weil das kein Ringpuffer ist.

Stell es dir vor als ob du eine Ablage hast die sagen wir 20 Din A4 Seiten fassen kann. Jede A4 Seite ist ein Byte.
Jetzt bekommst du ein neues Byte vom UART und packst das auf den Stapel. Und noch eins. Und noch eins. … Irgendwann hast du genug Daten und ziehst dir Byte für Byte unten raus. Oben kommen immer neue Daten drauf. Wenn es aber mehr als die 20 Seiten sind werden die untersten zerschmettert (gelöscht bzw. überschrieben - Buffer overflow).

In dem Fall brauchst du eh nicht zwangsweise einen Ringpuffer, da du die Daten als TLV (Type - Length - Value) empfängst. Du brauchst also nur einen Puffer der groß genug für das längste Datenpaket ist. Du empfängst und sammelst. [0] ist der "Befehl", [1] die Länge, [2..n] die Daten. Beim Schreiben prüfst du ob du (Länge) Bytes an Daten empfangen hast, startest die Verarbeitung und setzt den Schreibzeiger wieder auf 0. Die nächsten Bytes überschreiben die alten Daten.

Ein Ringpuffer ist etwas anderes.
Ich mach mal als Beispiel 6 Bytes.

123456 - Init. Lesezeiger 0, Schreibzeiger 0
123456 - Schreiben. Lesezeiger 0, Schreibzeiger 2
123456 - Schreiben. Lesezeiger 0, Schreibzeiger 4
Ergibt jetzt dass Bytes 1 - 4 beschrieben sind. Jetzt wollen wir 3 Bytes lesen.
123456 - Lesen. Lesezeiger 3, Schreibzeiger 4
Bytes 1-3 sind jetzt gelesen, Byte 4 ist nach wie vor im Speicher (unverarbeitet)
123456 - Schreiben. Lesezeiger 3, Schreibzeiger 1 (jetzt waren es mal 3 Bytes)
Hier ist das erste Byte der Daten jetzt an Position 5, das 2. an 6, das Dritte wiederum an 1 und überschreibt somit die alten, bereits ausgewerteten Daten.
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)