Hallo,
in diesem Thread (Beitrag "Can Interruppt") ging es
um die Frage, ob man einen std. fifo in c schreibt und für "jeden CAN
Bus Wert" sprich ID, Nachrichten, Nachrichten Längen einen eigenen fifo
erstellt oder das ganze in einer einzigen Struktur speichert.
Guido war damals fest davon überzeugt, eine Lösung für alles zusammen
ist die bessere. Ich habe inzwischen immer mal wieder drüber nachgedacht
und tendiere weiterhin zu der Variante für jeden Typ einen eigenen fifo
anzulegen.
Habe mal etwas gegoogelt und entweder ich bin zu doof oder es macht
sonst keiner in der "eine Struktur" Variante.
Ich denke man spart einiges an Speicherplatz. Konsistent sollte das
ganze ja bleiben, indem man ein paar Abfragen hinzufügt.
Ich seh mich schon da sitzen und das umschreiben.. aber vorher wollte
ich mal die Allgemeinheit zu ihrer Meinung fragen :)
fifo schrieb:> für "jeden CAN Bus Wert" sprich ID, Nachrichten, Nachrichten Längen> einen eigenen fifo
Macht das sinn?
Wie stellst du dann die beziehungen zwischen den daten her, wenn alles
fragmentiert in irgendwelchen fifos liegt.. Also, welche id gehört zu
welcher nachricht..?
Denke, du wirst präzisieren müssen..
fifo schrieb:> Ich denke man spart einiges an Speicherplatz. Konsistent sollte das> ganze ja bleiben, indem man ein paar Abfragen hinzufügt.
Aus was für Gründen sollte man den Speicherplatz sparen, wenn man genau
das gleiche speichert?
Angenommen 2 Fifos:
in 1) speicher ich x,y,z
in 2) speicher ich a,b
bei einer Fifo speicher ich halt dann
x,y,z,a,b
bei einer Fifo hat man sogar einen gewaltigen Vorteil:
die chronologische Reihenfolge bleibt erhalten...
fifo schrieb:> Guido war damals fest davon überzeugt, eine Lösung für alles zusammen> ist die bessere.
ist er auch immernoch ;)
fifo schrieb:> Ich denke man spart einiges an Speicherplatz.
Das solltest du mal näher erläutern, vielleicht hast du ja eine gute
Idee!
Ich will ja nicht behaupten, die allein seeligmachende Lösung zu kennen,
aber mit dem CAN Bus, Fifos, Interrupts, Treiberschnittstellen habe ich
mich jahrelang befassen dürfen. Es gibt verschiedene Ansätze, je nach
Anforderung.
Aber Informationen, die zusammen im Interrupt aufschlagen und dann auch
zusammen weiterverarbeitet werden müssen, sollten m.E. nach in eine
Datenstruktur geschrieben und in einem Ringspeicher verwaltet werden.
Wenn du (ich wiederhole mein Argument) drei Fifos benutzen willst,
musst du die Fifos konsistent halten. D.h. du musst an der Stelle, wo du
die Fifos liest, dafür sorgen, dass dir kein Interrupt dazwischen haut.
Das bedeutet, du musst den Interrupt sperren und dann alle Fifos lesen
und dann den Interrupt wieder freigeben. Aber das wäre widersinnig. Man
benutzt ja einen Ringspeicher um den Interrupt eben genau nicht sperren
zu müssen.
...aber es kann auch sein, dass ich deine Argumente einfach nicht
verstehe. Ich will nicht ausschließen, dass dein Ansatz in deinem
konkreten Fall die bessere Lösung ist!
ui schrieb:> Aus was für Gründen sollte man den Speicherplatz sparen, wenn man genau> das gleiche speichert?
So wie ich das sehe, müssen zumindest die Fifo-Verwaltungsstrukturen
3x angelegt werden - also mind. 3x Read-Pointer, 3x Write-Pointer zzgl.
weitere Daten je nach Ringbuffer-Implementierung
Was soll denn bitte der Vorteil bei dreifach so großem
Verwaltungsaufwand und der Schwierigkeit der Synchronität sein? Bisher
jedenfalls hab ich hier kein Argument (nichtmal nicht überzeugende)
dafür lesen können.
Guido schrieb:> fifo schrieb:>> Ich denke man spart einiges an Speicherplatz.> Das solltest du mal näher erläutern, vielleicht hast du ja eine gute> Idee!
Mit Speicherplatz meine ich Flashspeicher des Programms. Wenn man alles
in einer Struktur verwaltet braucht man mehr pointer, muss alle Fktion
erweitern usw. Man hat ja max 4x8Bit für die CAN ID, zwischen 0 und
8x8Bit für die Daten und einmal 8Bit für dlc + ggf. weitere Parameter.
Das muss ja alles programmiert werden. Legt man für jedes einen FIFO an,
spart man das und muss dafür immer gucken, wie der aktuelle Stand aller
FIFOs ist.
fifo schrieb:> Guido schrieb:> fifo schrieb:> Ich denke man spart einiges an Speicherplatz.>> Das solltest du mal näher erläutern, vielleicht hast du ja eine gute> Idee!>> Mit Speicherplatz meine ich Flashspeicher des Programms. Wenn man alles> in einer Struktur verwaltet braucht man mehr pointer, muss alle Fktion> erweitern usw. Man hat ja max 4x8Bit für die CAN ID, zwischen 0 und> 8x8Bit für die Daten und einmal 8Bit für dlc + ggf. weitere Parameter.> Das muss ja alles programmiert werden. Legt man für jedes einen FIFO an,> spart man das und muss dafür immer gucken, wie der aktuelle Stand aller> FIFOs ist.
Häh? Warum braucht man mehr Pointer? Du mit deinen tausend Fifos
brauchst mehr pointer in jedem Fall. Die struct-Lösung braucht je nach
Fifo-Implementierung genau 2.
fifo schrieb:> Mit Speicherplatz meine ich Flashspeicher des Programms.
Die Daten müssen doch zur Laufzeit geändert werden. Die
liegen daher im RAM. Oder was meinst du jetzt?
fifo schrieb:> zwischen 0 und> 8x8Bit für die Daten und einmal 8Bit für dlc
Ist deine Sorge, dass du immer 8 Bytes für die CAN-Daten verbrauchst,
auch wenn der DLC bspw. nur 1 ist - also 7 Bytes verschwendet?
Falls ja, nimmst du einfach eine Ringspeicherimplementierung, die mit
Objekten verschiedener Größe klarkommt.
Ne, das ist nicht meine Sorge.
Aber mal anderes: Warum sollte man eigentlich nicht ein Fifo anlegen mit
der Lib. aus dem andern Thread und da alles drin speichern. (Sprich ein
ganz normales fifo wie mans auch für UART nutzt)
Man könnte:
ID | ID | ID | ID | MSG 0 - 8 | DLC
Als erstes liest man den DLC Wert aus, weiß dann wie viele Nachrichten
man gespeichert hat, liest die Nachrichten aus und dann die 32 Bit CAN
ID usw.
Man spart bei der Variante auch das Zusammenschieben der CAN ID zu einer
32 Bit Variable, was man dann ggf. später in der Hauptschleife tun
könnte.
Hab ich nen Denkfehler?
fifo schrieb:> Man spart bei der Variante auch das Zusammenschieben der CAN ID zu einer> 32 Bit Variable, was man dann ggf. später in der Hauptschleife tun> könnte.>> Hab ich nen Denkfehler?
Naja:
1.
DLC vorne ist schonmal ok, aber ich würde dann MSG 8 - 0 reinschreiben,
um beim Auslesen gleich die richtige Reihenfolge zu haben. Also nach DLC
erstmal MSG-0, MSG-1 usw
2.
Bevor du im Interrupt in den Fifo schreibst, musst du abfragen,
ob im Fifo genug Platz für die gesamte Botschaft ist.
Wenn du nicht weißt, wie ein Fifo genau funktioniert, wird dir das
Probleme machen. Und wenn du es weißt, kannst du genauso gut einen
Fifo schreiben, der komplette CAN Objekte aufnehmen kann ;)
3.
Wenn du das so umsetzt, machst du dir warscheinlich eine Wrapper
Funktion, mit der du die CAN-Daten byteweise in den Fifo schreibst bzw.
liest. Aber dann hast du eigentlich genau das gemacht, was
ich schon die ganze Zeit propagiere ;)
ringBufferWrite(uint len, char* bytes);
CANObj data;
//schreiben: Länge=DLC + CAN_ID + RTR
ringBufferWrite(data.dlc+sizeof(uint32)+sizeof(char), (char*)&data);
Guido schrieb:> ringBufferWrite(data.dlc+sizeof(uint32)+sizeof(char), (char*)&data);
Korrektur bzw besser:
ringBufferWrite(data.dlc+sizeof(data.CanId)+sizeof(data.rtr),(char*)&dat
a);
Der macht dann nichts weiter, als ab Adresse &data eine Anzahl
Bytes zu nehmen und in den Ringbuffer zu kopieren.
Man muss aber mit dem Alignment aufpassen! Datenstrukturen am besten
so aufbauen, dass der Compiler keine Alignmentbytes einbaut.
Hallo nochmal,
https://www.mikrocontroller.net/articles/FIFO#FIFO_als_Bibliothek
Mit dieser Bib hat man doch genau die Möglichkeit, die du oben
beschreibst (also fast) Ich weiß nicht, ob du das Archiv überhaupt
gesehen hast, oder über die Beispiele schreibst... ich meine auf jeden
Fall immer das Archiv.
z.B. zum schreiben wird dieses Beispiel angeführt:
1
block_size=7;
2
wrap_size=fifo_get_write_wrap(&fifo);
3
if(fifo_get_free(&fifo)>=block_size){
4
if(block_size>wrap_size){
5
// split action into two blocks due to pointer wrap around
Mich würde interessieren, wie das funktioniert. Ich hab z.b. jetzt die
CAN ID und die Nachrichten sowie die Anzahl der Nachrichten. Wie bekomme
ich diese mit dem Code oben in den fifo in einem rutsch?
Wenn ich mir memset() angucke:
1
memset(void*dest,
2
intval,
3
size_tlen
4
)
Das Ziel ist klar, auch die Länge, aber warum nutz man hier "A" ? A
sollte doch nur 2 Byte groß sein und nicht 7? Und wie würde ich z.b.
jetzt ein Array aus CAN ID + MSG + Länge übergeben?
Auf dieses Beispiel hatte ich mich nicht bezogen.
"A" ist hier anscheinend ein char und somit 1Byte groß.
Der Code stellt wohl beispielhaft dar, wie man 7x "A" in den
Fifo schreibt, wenn ich das richtig verstehe.
Du musst also einfach memcpy nehmen und deinen CAN-struct in den
Fifo schreiben.
Kleine Kritik an dieser Implementierung:
Die Behandlung der zwei Fälle
1. Lesepointer vor Schreibpointer
2. Lesepointer hinter Screibpointer
sollte man nicht von Hand bedienen müssen.
Aus meiner Sicht müsste das innnerhalb der Funktion fifo_write_bursted
bzw. fifo_read_bursted behandelt werden.
Für mich müsste das so aussehen:
fifo_write_bursted(&fifo, *byte data, int len);
Theoretisch müsste ja dann als erstes 1, dann 2 usw. aus dem fifo
"kommen", wenn man einzeln abruft. Ich erhalte allerdings 2,3,4,1 nach
ein paar Durchläufen.
Mit Durchlauf meine ich array in fifo schreiben und direkt wieder
ausgeben.
Beim ersten Durchlauf erhalte ich:
1,2 (4,3)
Zweiter Durchlauf:
3,4,1 (6,5,4)
Dritter Druchlauf:
2,3,4,1 (7,6,5,4)
Vierter Durchlauf wie Dritter usw.
Was mache ich hier falsch?
Vergessen zu erwähnen:
Die Werte in Klammern sind das aktuelle level im fifo.
z.b.
1,2 (4,3) heißt, dass wenn er die 1 aus dem fifo holt das level 4 ist.
Wenn die 2 aus dem fifo genommen wurde ist das level 3
Ich verstehe es nicht...
fifo schrieb:> Was mache ich hier falsch?
Hast du die Fifo-Implementierung und das von dir gezeigte
Code-Beispiel verstanden?
Speziell wozu fifo_get_free da ist?
Weißt du, was ich mit "Schreibpointer vor Lesepointer" und "Lesepointer
vor Schreibpointer" meine?
Und noch ein Tip:
Du hast array[5] nicht komplett initialisiert.
Du hast da was falsch abgeschrieben.
> Hast du die Fifo-Implementierung und das von dir gezeigte> Code-Beispiel verstanden?
Denke ja
> Speziell wozu fifo_get_free da ist?
Gibt die noch freien Plätze im fifo zurück.
> Weißt du, was ich mit "Schreibpointer vor Lesepointer" und "Lesepointer> vor Schreibpointer" meine?
Nein. Mein Plan war es erstmal das ganze zum laufen zu bekommen. Die
fifo_write_bursted Fkt. zu erweitern würde ich dann später machen.
> Und noch ein Tip:> Du hast array[5] nicht komplett initialisiert.> Du hast da was falsch abgeschrieben.
Habe mit verschiedenen Blockgrößen getestet. Im Grunde ists aber egal,
da ich die Größe in memcpy vorgebe. (Später nat. wichtig)
An der Größe des fifos kanns nicht liegen... oder worauf willst du
hinaus?
Wenn ich 5 Elemente in den Fifo kopiere, dann die Elemente einzeln
abrufe erhalte ich wenn das letzte Element noch im fifo ist ein level
von 5
Wenn ich 4 Elemente in den Fifo kopiere, .... ist das level von 4
OK, linear... das freut mich. verstehe nur nicht, warum das level
konstant 4 am ende ist. wo werden die ersten 4 Plätze am Anfang belegt?
fifo schrieb:>> Weißt du, was ich mit "Schreibpointer vor Lesepointer" und "Lesepointer>> vor Schreibpointer" meine?> Nein. Mein Plan war es erstmal das ganze zum laufen zu bekommen. Die> fifo_write_bursted Fkt. zu erweitern würde ich dann später machen.
Entschuldige bitte, aber ab diesem Punkt kann ich dir nicht
weiterhelfen.
Hier wird erst fifo_get_write_wrap() aufgerufen. Dabei wird die
Differenz zwischen der Größe und dem Schreibtpointer plus eins addiert.
Ist das fifo 200 groß und der Schreibpointer gerade auf dem Element 198
erhalte ich also 3.
Nun wird geguckt, ob die freien Plätze im Fifo ausreichend sind um die
neue Blockgröße dh. X Byte aufzunehmen. Wenn ja, wird geguckt, ob die
Block Größe größer ist, als die wrap größe. Ist die Wrap Größe wie oben
berechnet 3 und die Block Größe 7 springt das Programm in die If um dort
memset auszuführen. Hierbei wird A also 3x ab der Adresse des
Schreibpointers geschrieben. Insg. nimmt dies einen Speicher von 3 Byte
ein. Weiter gehts mit fifo_write_bursted() (sieht unten)
Die restlichen 4 Byte (Dh. 7 - 3 = 4) werden anschließend verarbeitet.
Nun springt man in die Fktion fifo_write_bursted()
Hier wird ein temporärer Pointer angelegt. In diesen Pointer wird die
Adresse geschrieben an der der Schreibpointer plus die hinzugefügte
block Größe liegt. Daraufhin wird geguckt, ob der temp Pointer größer
als der oberste Wert des fifos ist. Ist dem so, wird dem lese Pointer
der Start des Fifos zugewiesen ansonsten entspricht der lesepointer dem
tempörären pointer.
Anschließend wird nocheinmal die aktuelle Füllstandsgröße abgerufen.
Diese sollte 7 sein.
Hierbei wird also nur der Lesepointer verändert, ansonsten versteh ichs
nicht. Oder meinst du, dass erst der Schreibpointer behandelt wird und
dann der Lesepointer? Ich wüsste aber keinen Weg es anders zu
machen...!?