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
|
6 | memset((uint8_t*)fifo.write_p, 'A', wrap_size * sizeof(fifo_data_t)); |
7 | fifo_write_bursted(&fifo, wrap_size); |
8 | block_size -= wrap_size; |
9 | }
|
10 | // no pointer wrap around in block or second half of block operation
|
11 | memset((uint8_t*)fifo.write_p, 'A', block_size * sizeof(fifo_data_t)); |
12 | fifo_write_bursted(&fifo, block_size); |
13 | }
|
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 | int val, |
3 | size_t len |
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);
Mit memcpy() also so: (Unabhänige von CAN)
1 | uint8_t array[5]; |
2 | array[0] = 1; |
3 | array[1] = 2; |
4 | array[2] = 3; |
5 | array[3] = 4; |
6 | |
7 | block_size = 4; |
8 | |
9 | memcpy((uint8_t*)fifo.write_p, &array, block_size * sizeof(fifo_data_t)); |
10 | fifo_write_bursted(&fifo, block_size); |
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?
1 | fifo_t fifo; |
2 | fifo_data_t tmp_a[200]; |
3 | fifo_init(&fifo, tmp_a, sizeof(tmp_a) / sizeof (fifo_data_t)); |
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.
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
|
6 | memset((uint8_t*)fifo.write_p, 'A', wrap_size * sizeof(fifo_data_t)); |
7 | fifo_write_bursted(&fifo, wrap_size); |
8 | block_size -= wrap_size; |
9 | }
|
10 | // no pointer wrap around in block or second half of block operation
|
11 | memset((uint8_t*)fifo.write_p, 'A', block_size * sizeof(fifo_data_t)); |
12 | fifo_write_bursted(&fifo, block_size); |
13 | }
|
14 | level = fifo_get_level(&fifo); |
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...!?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.