Hallo, ich bins...
Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Kann mir bitte einer sagen, was da nicht stimmt? Ich habe schon die
ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und
ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem
StackType_t * ein TCB_t bekomme.
Matthias schrieb:> Hallo, ich bins...>> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.>> Kann mir bitte einer sagen, was da nicht stimmt?
Du hast die Netiquette nicht beachtet, längere Quelltexte gehören in
den Anhang.
> Ich habe schon die> ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und> ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem> StackType_t * ein TCB_t bekomme.
Ich auch nicht. Aber für bissel CAN und Solaranlage scheint das hier
eine verdammt aufgeblähte Lösung zu sein.
Ja, mei, wie es halt immer ausartet...
Ich glaube, nach
1
portSAVE_CONTEXT();
2
portRESTORE_CONTEXT();
ist das Programm richtig weitergelaufen.
1
#define portSAVE_CONTEXT() \
2
__asm__ __volatile__ ( "push __tmp_reg__ \n\t" \
3
"in __tmp_reg__, __SREG__ \n\t" \
4
"cli \n\t" \
5
"push __tmp_reg__ \n\t" \
6
"push __zero_reg__ \n\t" \
7
"clr __zero_reg__ \n\t" \
8
"push r2 \n\t" \
9
"push r3 \n\t" \
10
"push r4 \n\t" \
11
"push r5 \n\t" \
12
"push r6 \n\t" \
13
"push r7 \n\t" \
14
"push r8 \n\t" \
15
"push r9 \n\t" \
16
"push r10 \n\t" \
17
"push r11 \n\t" \
18
"push r12 \n\t" \
19
"push r13 \n\t" \
20
"push r14 \n\t" \
21
"push r15 \n\t" \
22
"push r16 \n\t" \
23
"push r17 \n\t" \
24
"push r18 \n\t" \
25
"push r19 \n\t" \
26
"push r20 \n\t" \
27
"push r21 \n\t" \
28
"push r22 \n\t" \
29
"push r23 \n\t" \
30
"push r24 \n\t" \
31
"push r25 \n\t" \
32
"push r26 \n\t" \
33
"push r27 \n\t" \
34
"push r28 \n\t" \
35
"push r29 \n\t" \
36
"push r30 \n\t" \
37
"push r31 \n\t" \
38
"lds r26, pxCurrentTCB \n\t" \
39
"lds r27, pxCurrentTCB + 1 \n\t" \
40
"in __tmp_reg__, __SP_L__ \n\t" \
41
"st x+, __tmp_reg__ \n\t" \
42
"in __tmp_reg__, __SP_H__ \n\t" \
43
"st x+, __tmp_reg__ \n\t" \
44
);
Speichert denn die portSAVE_CONTEXT() mehr als nur die 32 Register?
Der Stack muss wegen dem uint16_t[] wahrscheinlich auf einer geraden
Adresse liegen? Also eher so?
Matthias schrieb:> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Soll das ein präemptives Multitasking System werden?
Das ist sicherlich etwas überzogen für Solar, RS485 und CAN
Das geht bestimmt auch Kooperativ!
Und wenn doch, warum nicht FreeRTOS, da weiß man dass es funktioniert.
Der Wechselrichter läuft seit einem Jahr ohne Fehler. Problem ist der
Batteriespeicher, da kommen ständig Fehlermeldungen wegen der Temperatur
und Spannung.
Ich hab da an dem BMS schon einen Monat rumgestellt und es dann
aufgegeben. Da braucht es je nach Temperatur und Jahreszeit
unterschiedliche MinSOC, MaxSOC und Ladestrom, was das BMS und WR nicht
kann.
Also Stromverbrauch-/Einspeisemesswerte lesen (RS485), BMS lesen (CAN),
Batterie-WR schreiben (Batterieladezustand CAN) (Ladeleistung RS485).
Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen
bleibt.
Die Schnipsel sind vom FreeRTOS
(https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/src/port.c),
aber wenn ich das aufspiele ist der Speicher voll.
Matthias schrieb:> Also Stromverbrauch-/Einspeisemesswerte lesen (RS485),> BMS lesen (CAN),> Batterie-WR schreiben (Batterieladezustand CAN)> (Ladeleistung RS485).>> Ohne Multitasking wird es arg kompliziert,
Also zwei Messwert(sätz)e lesen und anschließend beide ans
BMS-Schreiben? Was ist da so arg kompliziert ohne Multitasking?
Wie oft muß das überhaupt passieren, 1/s oder 1/µs?
> wenn da irgendwas hängen bleibt.
Meinst Du beim Lesen? Timeout abwarten? k.A. was die sinnvollste Aktion
ist, wenn Dir ein Eingabewert fehlt, aber dagegen hilft Dir auch
Multitasking nichts, im Gegenteil läufst Du eher Gefahr, nichts
mitzubekommen wenn einer der Lese-Tasks dauerhaft hängt und keine
Updates liefert.
Matthias schrieb:> Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen> bleibt.
Mit MT bleibt es vielleicht noch öfter hängen, wenn man da kein Profi
ist.
Ich weiß allerdings nicht genau, wo das Problem liegt.
Was soll wo hängen und warum?
Läuft doch alles mit einem Mess-/Aktionstakt > 10 Sekunden, oder?
Wenn eine CAN- oder RS-485-Funktion hängt, kann man das mit einem
Watchdog-Timer abfangen. Danach kann man dann eine Ersatzfunktion
aufrufen (z. B. das Interface zurücksetzen) und die Aktion beim nächsten
Durchlauf erneut versuchen. Bei einer Dauerstörung der Hardware hilft
dir MT auch nicht.
Arduino F. schrieb:> Und jetzt baust du dein eigenes FreeRTOS um Speicher zu sparen?
Augenscheinlich kopiert er irgendwelche Softwarefragmente aus dem Netz
zusammen, mit der Hoffnung auf ein funktionierendes Ergebnis.
Oliver
Hallo,
also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere
Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde. TCB_t
ist ein struct Datentyp der neueren Controller Serien. Ein ATmega328P
hat keine Timer des Typs TCB (oder TCA, TCD) oder dergleichen.
Michi S. schrieb:> Meinst Du beim Lesen? Timeout abwarten? k.A. was die sinnvollste Aktion> ist, wenn Dir ein Eingabewert fehlt
Soi, wie ich die Beschreibung lese, nimmt man dann einfach den
vorherigen Einlesewert. Es sind doch alles sich nur langsam verändernde
Größen.
Veit D. schrieb:> TCB_t> ist ein struct Datentyp der neueren Controller Serien. Ein ATmega328P> hat keine Timer des Typs TCB (oder TCA, TCD) oder dergleichen.
Der hat vor allem kein CAN…
@TO
Der hat auch keinen 3-Byte-PC. Vielleicht hilft das ja weiter. Wobei die
Antwort auf die Frage vermutlich „gar nicht“ lautet, und ansonsten RTFM
des unbekannten RTOS.
Oliver
Matthias schrieb:> Kann mir bitte einer sagen, was da nicht stimmt?
Ich kann sagen. Es stimmt nichts.
Hast du Datasheet für von dir gewählte Mega gelesen?
Matthias schrieb:> Ist SREG ein Teil von R0-R31? Muss ich die I/O Register beim> Taskwechsel auch speichern?
wahrscheinlich doch nicht gelesen. Sonst käme diese Frage nicht.
Veit D. schrieb:> also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere> Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.
TCB soll wohl TaskControlBlock heißen.
Hat also nix mit Timern zu tun.
oder nur um 12 Ecken.
Matthias schrieb:> Wäre ja eine Schande, wenn es nicht klappt, die paar Register aus dem> SRAM zu laden und speichern...
Was willst du erreichen?
Was willst du "wirklich" erreichen?
Und ja, dass du gerade am Ende einer Sackgasse angekommen bist, und vor
einer Wand stehst, hat hier (fast) jeder begriffen.
Die Frage ist daher, wo isser falsch abgebogen um da zu landen.
Matthias schrieb:> Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen> bleibt.
Kann man deutlich einfacher kooperativ gestalten. Das Rad "neu" in eckig
zu erfinden, weil man mal zum Bäcker fahren will, ist Unsinn.
>> Die Schnipsel sind vom FreeRTOS> (https://github.com/feilipu/Arduino_FreeRTOS_Library/blob/master/src/port.c),> aber wenn ich das aufspiele ist der Speicher voll.
Es gibt mehr als genug "Arduinos" mit tonnenweise Speicher, ESP32,
RPpico etc. Und für das bissel Klim Bim allemal.
Matthias schrieb:> Okay, ich versuche mich durch die Instruction Set der CPU zu wühlen>
(https://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf).
UM ein bisselö auf dem CAN Bus Daten zu verschicken, schnon klar . . .
> Wäre ja eine Schande, wenn es nicht klappt, die paar Register aus dem> SRAM zu laden und speichern...>> Ist SREG ein Teil von R0-R31?
Nö, das SREG liegt im IO-Bereich. Klingt komisch, ist aber so.
> Muss ich die I/O Register beim> Taskwechsel auch speichern?
Nö.
Maxim B. schrieb:> Wenn man noch nicht weiß, was SREG ist, dann ist es für RTOS noch zu> früh.
In der Tat. Vor allem klingt es hier nach Tunnelblick und Voodoo, so als
ob ein präemtives Multitasking alle Probleme löst.
Arduino F. schrieb:> Veit D. schrieb:>> also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere>> Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.>> TCB soll wohl TaskControlBlock heißen.> Hat also nix mit Timern zu tun.> oder nur um 12 Ecken.
Aha. ;-)
Veit D. schrieb:> Arduino F. schrieb:>> Veit D. schrieb:>>> also wenn ich TCB_t und ATmega328P lese, dann sagt mir meine innere>>> Stimme das was nicht zusammenpasst oder zusammengewürfelt wurde.>>>> TCB soll wohl TaskControlBlock heißen.>> Hat also nix mit Timern zu tun.>> oder nur um 12 Ecken.>> Aha. ;-)
Das könnte zwar wieder eine Abseitsdiskussion werden. Nur wenn ich so
rund um die Lib lese wurde diese auch für die neueren Controller
angepasst. Wenn TCB_t für was anderes steht, aber für die neuen
Controller in deren Headerfile für die Timer schon existiert, dieser
Name TCB_t, dann muss das doch früher oder später knallen. Vielleicht
knallt das jetzt ausgerechnet beim TO?
Wenn ich der TO wäre, ich würde erstmal die Beispiele der Lib versuchen
zu kompilieren. Das soll ja alles auch auf einem ATmega328P
funktionieren, also muss das eigentlich laufen. Danach kann man immer
noch daran rumfummeln, wenn man weiß was man tut.
Steve van de Grens schrieb:> Matthias schrieb:>> Ist SREG ein Teil von R0-R31?>> Nein>>> Muss ich die I/O Register beim Taskwechsel auch speichern?>> Das ist unmöglich.
Danke für die Hilfe! Also relevant sind SREG und R0-R31.
Hier (https://gcc.gnu.org/wiki/avr-gcc) wird beschrieben, was
_tmp_reg_ = R0 und _zero_reg_ = R1 ist.
_SP_L__ und __SP_H_ sind wahrscheinlich je ein Byte vom SP. Wobei ich
mir jetzt nicht sicher bin ob es _SP_L_, _SP_H__ oder __SP_H_,
_SP_L_ ist.
1
union{
2
uint8_t SP[2]{__SP_L__, __SP_H__};
3
uint16_t SP;
4
void *SP;
5
}
Das Funktionsargument wird scheinbar in R24, R25 übergeben.
? listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
4
? configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */
5
2 struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */
6
2 struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
7
2 void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. */
8
2 void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any). */
9
? listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
10
};
11
typedef struct xLIST_ITEM ListItem_t;
12
13
typedef struct tskTaskControlBlock
14
{
15
2 volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
16
17
#if ( portUSING_MPU_WRAPPERS == 1 )
18
? xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
19
? BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */
20
#endif
21
22
8 ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
23
8 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */
24
? UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */
25
2 StackType_t *pxStack; /*< Points to the start of the stack. */
26
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
Matthias schrieb:> Muss ich die I/O Register beim Taskwechsel auch speichern?
Schon das Lesen kann den Zustand des zugehörigen Peripheriegeräts
ungewollt verändern. Und das Zurückschreiben gespeicherter Inhalte ist
noch schlimmer.
Und das auch noch in unterschiedlichen Tasks? ουαί κι αλίμονό μου!
Das steht in keinem Datenbuch ausdrücklich drin, weil es für jeden Profi
absolut selbstverständlich ist.
Rolf schrieb:> Das steht in keinem Datenbuch ausdrücklich drin,
Aber sicher, man muss nur des sinnerfassenden Lesens mächtig sein. Bei
ALLEN IO-Registern steht, ob und wie ein Schreib- oder Lesezugriff eine
Reaktion bewirkt.
Matthias schrieb:> Wird eine lange Nacht :)
Da kann ich dir gerne einen Tipp geben:
> Wer in die falsche Richtung läuft,> braucht sich nicht zu beeilen.
Ich hab mir jetzt Microchip Studio runtergeladen und schon paar Fehler
gefunden.
Im Simulator geht das leichter...
Glaube der Stack ist uint8_t und dann stimmt glaube ich noch die
pxCurrentTCB Variable nicht.
Ist gleich fertig :)
PS Geht's schon wieder los mit der Fingermotorik...
Glaube ich habe es mehr oder weniger. Muss noch bissi testen und
schauen, wie man das mit dem Speicher macht, wenn man keine MMU hat.
Was noch wichtig ist, während man an SP rumfummelt, muss man die
Interrupt abschalten.
Matthias schrieb:> Glaube ich habe es mehr oder weniger.
Ja, wenn man nur wüsste, was eigentlich. Denn aktuell ist das klassische
xy-Problem. Du bastelst an Lösungen, die mit deinem Problem gar nichts
zu tun haben.
Oliver
Matthias,
ich habe den Eindruck, dass du deine Fähigkeiten extrem überschätzt. Du
willst ein RTOS Betriebssystem neu erfinden, ohne den Prozessor zu
kennen. Was du vor hast ist machbar, aber das wird nach meiner
Einschätzung einige Monate dauern.
100% sicher ist, dass du damit den Fokus auf die Problemursache
verlierst. Du verzettelst dich mit einem komplexen Balkon, der dein
Problem nicht löst, sondern höchstwahrscheinlich noch schwieriger
begreifbar macht. Man soll ja junge Leute nicht demotivieren, doch es
tut mir in der Seele weh, zu sehen, wie du mit Anlauf vor die Wand
läufst.
Auf dem kleinen Mikrocontroller wird ein aktive Multitasking so viel RAM
und CPU Leistung verschlucken, dass du damit nicht glücklich wirst -
falls du es überhaupt schaffst.
Einen kooperativen Lösungsansatz ohne Register-Zauber habe ich dort
beschrieben:
http://stefanfrings.de/multithreading_arduino/index.html
Aber: Finde erst mal die Fehlerursache in deinem Programm! Nur wenn man
seine eigenen Fehler erkannt und verstanden hat, kann man es danach
besser machen.
Steve van de Grens schrieb:> Einen besseren Lösungsansatz
Ihm ist nicht an kooperation interessiert.
Steve van de Grens schrieb:> wie du mit Anlauf vor die Wand läufst
Ich sehe auch keinerlei Bestreben, nach rechts oder links zu schauen, ob
der Maurer irgendwo ein Loch gelassen hat.
Wie auch immer...
Ich bin gespannt wie sein Multitasking (optimiertes FreeRTOS) ausschaut,
wenn es denn fertig ist.
Steve van de Grens schrieb:> ich habe den Eindruck, dass du deine Fähigkeiten extrem überschätzt.
Wenn er es bis hierher nicht verstanden hat dann darf man ihm
Beratungsresistenz attestieren.
Leider ist der Thread gestern, am Freitag, entstanden. Was auch
kein gutes Zeichen ist. Allein CAN und Multitasking in Einem
auf dem ATmega328P lässt mich schon ganz schwindelig werden.
Was der Matthias vielleicht noch nicht auf sich zu kommen sieht:
Wenn mehrere Threads auf gemeinsame Resourcen zugreifen (z.B. ein
Display oder der CAN Bus), dann muss man irgendwie dafür sorgen, dass
das in einer geordneten Reihenfolge passiert (Semaphoren). Das läuft oft
auf gepufferte Ein/Ausgabe hinaus, für die er aber nicht genug RAM haben
wird, da das ja schon von Registern und Stack der Threads "aufgefressen"
wurde.
Falk B. schrieb:> Rolf schrieb:>> Das steht in keinem Datenbuch ausdrücklich drin,>> Aber sicher, man muss nur des sinnerfassenden Lesens mächtig sein. Bei> ALLEN IO-Registern steht, ob und wie ein Schreib- oder Lesezugriff eine> Reaktion bewirkt.
Dann lies mal richtig. Was habe ich denn gesagt und was nicht?
Und worauf bezog sich das?
Die **allgemeine** Aussage, dass man bei I/O-Registern nicht einfach
blind lesen und schreiben darf, da es – im Gegensatz zu "normalen"
Speicherregistern – gar keine Speicher, sondern nur Adressen zum
Übermitteln von Befehlen und Stati an/von Peripheriegeräten sind, die
steht eben nicht **ausdrücklich** drin.
Matthias schrieb:> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.
Sowas ähnliches habe ich auch im Einsatz. Auf CAN und UART fahre ich das
gleiche Stringprotokoll. Der CAN-Interrupt teilt die Nachrichten in
8-Byte Pakete auf bzw. liest sie ein.
RS485 und CAN lesen einfach in getrennte Puffer. Und sobald das
Endezeichen erkannt wird, geht beides in den gemeinsamen Parser, der es
dann ausführt und die Antwort in den CAN- bzw. UART-Puffer bastelt.
Nirgends kann was hängen bleiben und Multitasking ist erst recht völlig
unnötig.
Sämtliche Parameter (ADC, I2C usw.) werden im Hintergrund permanent
eingelesen. Der Parser muß also nirgends warten, sondern schickt gleich
die Antworten.
Als Schmankerl gibt es noch eine Autosend-Funktion. Der Master schickt
dazu den Parameternamen und das gewünschte Intervall. Dann muß er nicht
jedes mal erneut anfragen, sondern bekommt zyklisch alles geschickt.
Was Deine Registerrettungsorgie mit der Fragestellung zu tun hat, ist
mir jedoch ein völliges Rätsel.
Das ist nur unnütze Verschwendung von RAM, Code und CPU-Zeit.
Matthias schrieb:> Ohne Multitasking wird es arg kompliziert, wenn da irgendwas hängen> bleibt.
Multitasking hilft aber nicht gegen Programmfehler. Im Gegenteil, es
macht die Funktionen nur unnötig kompliziert und damit Fehler
wahrscheinlicher.
Wenn man die Abläufe sauber strukturiert, kann auch nichts
"hängenbleiben".
Matthias schrieb:> Ich hab mir jetzt Microchip Studio runtergeladen und schon paar Fehler> gefunden.
Das stimmt. Besonders in Simulatoren kann man in Microchip Studio viele
Fehler finden.
Ich sehe dein Problem aber woanders: du willst Inline Assembler
benutzen, ohne AVR einigermaßen kennenzulernen.
An deiner Stelle würde ich zuerst ein paar Projekte mit C und mit
Assembler machen, dann etwas mit Inline Assembler Schritt zu Schritt,
und erst danach mit RTOS experimentieren. Nur so wirst du verstehen, was
du machst.
Frage, was passiert mit den Registern und Stack im Interrupt?
Kann ich da im Interrupt einfach einen Task starten oder Taskwechsel
machen?
Wahrscheinlich muss ich ganz am Anfang vom Interrupt die Register und
Stack des alten Task speichern?
Gibt es da ein Muster irgendwo? Ist dafür das naked Funktionsattribut,
oder muss das in ASM sein?
Scheint so. Ich habe es zwar noch nicht ganz verstanden, aber hier steht
es.
https://www.freertos.org/implementation/a00022.html
Ist denn die TIMER2_COMPA_vect bzw. alle Funktionen, definiert mit ISR()
ohne Prolog und Epilog?
Matthias schrieb:> Frage, was passiert mit den Registern und Stack im Interrupt?
Schreibe ein Programm, laß es kompilieren und öffne Disassembler. Oder
*.lss - File.
Maxim B. schrieb:> Matthias schrieb:>> Frage, was passiert mit den Registern und Stack im Interrupt?>> Schreibe ein Programm, laß es kompilieren und öffne Disassembler. Oder> *.lss - File.
Ja, danke, ich kämpfe mich schon durch!
ISR(TIMER2_COMPA_vect) ist per default nicht naked...
Verdammte kleine Mistdinger, ist doch alles komplizierter als gedacht.
Matthias schrieb:> Frage, was passiert mit den Registern und Stack im Interrupt?
Beim AVR8? So gut wie nix. Der PC wird auf den Stack gesichert und das
I-Flag in SREG gelöscht. Für alles andere ist man selbst (oder der
Compiler) verantwortlich.
> Kann ich da im Interrupt einfach einen Task starten oder Taskwechsel> machen?
Üblicherweise nicht. Üblicherweise ist so ein Multitasking-OS
sinnvollerweise so konstruiert, dass die Devicetreiber (und der
Task-Scheduler) das einzige sind, was überhaupt Interrupthandler
implementiert.
Und die Devicetreiber ihrerseits füttern oder entleeren üblicherweise
nur Queues im RAM. Maximal können sie noch dafür sorgen, dass der Task,
der auf ein entsprechendes Ereignis wartet, in der Prioritätsliste nach
oben wandert.
Fazit: ein Riesenhaufen Verwaltungs-Overhead, den niemand benötigt, der
wirklich programmieren kann...
Klar, man kann auch mit einem RTOS was zum Laufen bringen, aber das
Ergebnis wird massiv suboptimal sein. Nunja: solange die
Rechenzeit-Resourcen dafür reichen, dass es halt den Anforderungen der
Anwendung genügt, ist das egal. Aber wehe, es kommt was dazu...
Dann ist das Bein genauso dicke, als hätte man den Kram "klassisch"
implementiert, also ohne RTOS. Der Unterschied ist halt nur: das wird
bei einem RTOS-Ansatz bei gegebener Hardware viel früher passieren.
Dafür sorgt eben der Overhead des RTOS...
Ob S. schrieb:> Matthias schrieb:>>> Frage, was passiert mit den Registern und Stack im Interrupt?>> Beim AVR8? So gut wie nix. Der PC wird auf den Stack gesichert und das> I-Flag in SREG gelöscht. Für alles andere ist man selbst (oder der> Compiler) verantwortlich.
Bei mir hat der Compiler zumindest einen Teil der Register auf dem Stack
gesichert und vor reti wieder geladen.
ISR() vollzieht also sowas wie einen Taskwechsel, wenn es nicht mit
__attribute__((naked)) ist.
> Fazit: ein Riesenhaufen Verwaltungs-Overhead, den niemand benötigt, der> wirklich programmieren kann...>> Klar, man kann auch mit einem RTOS was zum Laufen bringen, aber das> Ergebnis wird massiv suboptimal sein. Nunja: solange die> Rechenzeit-Resourcen dafür reichen, dass es halt den Anforderungen der> Anwendung genügt, ist das egal. Aber wehe, es kommt was dazu...>> Dann ist das Bein genauso dicke, als hätte man den Kram "klassisch"> implementiert, also ohne RTOS. Der Unterschied ist halt nur: das wird> bei einem RTOS-Ansatz bei gegebener Hardware viel früher passieren.> Dafür sorgt eben der Overhead des RTOS...
Ja, mal schauen. Wenn es mir am Ende nicht gefällt, kann ich es immer
noch mit einem while(1){switch} neu machen.
Matthias schrieb:> ISR(TIMER2_COMPA_vect) ist per default nicht naked...
Und gut so. Naked brauchst du selten. Z.B. dort wo SREG in ISR nicht
geändert wird. Oder muß du per Hand SREG und alle benutzten Register in
Stack legen. Aber Compiler selbst macht das noch besser. Nur vergiß
nicht, Optimieren auf -Os zu stellen. Dummerweise macht Microchip Studio
für neue Projekte -Og.
Matthias schrieb:> Verdammte kleine Mistdinger, ist doch alles komplizierter als gedacht.
Aber nur, wenn man es sich absichtlich kompliziert machen will.
Die Mehrheit läßt einfach den Compiler sich um alles kümmern und pfuscht
ihm nicht mit Assembler ins Handwerk.
Was stört Dich denn an der Mainloop mit Interrupts Methode?
Hast Du überhaupt schonmal irgend was programmiert oder ist das Dein
Einsteigerprojekt?
Matthias schrieb:> Ist dafür das naked Funktionsattribut,> oder muss das in ASM sein?
Ist eh kaum ein Unterschied, weil GCC in naked Funktionen offiziell nur
Inline Asm unterstützt.
Ein RTOS zu verwenden macht übrigens auf anderen Controllern deutlich
mehr Sinn, wie z.B. Cortex-M. Die sind im Gegensatz zu den AVR extra
dafür konzipiert und können den Kontextwechsel fast automatisch und sehr
effizient. Außerdem haben die Support für Atomics, Speicherschutz (MPU)
und Privilegierung/Separierung von OS und Anwendung,
Interrupt-Prioritäten usw. Rein zufällig gibt es dafür auch schon
fertige RTOS wie eben FreeRTOS.
Maxim B. schrieb:> Nur vergiß> nicht, Optimieren auf -Os zu stellen. Dummerweise macht Microchip Studio> für neue Projekte -Og.
Für seinen Fall wäre -Og besser:
-Os: Diese Option optimiert den Code für die Größe des resultierenden
ausführbaren Programms. Der Compiler versucht, den Code so zu
optimieren, dass er weniger Speicherplatz benötigt, auch wenn dies
möglicherweise auf Kosten der Ausführungsgeschwindigkeit geht. Das ist
besonders nützlich für eingebettete Systeme oder Programme, bei denen
die Größe des Binärdatei eine Rolle spielt.
-Og: Diese Option steht für "Optimize for Debugging". Im Gegensatz zu
anderen Optimierungsstufen versucht "-Og" nicht, den Code stark zu
optimieren. Stattdessen optimiert es den Code auf eine Weise, die das
Debuggen erleichtert. Das bedeutet, dass der generierte Code lesbarer
bleibt und das Debuggen einfacher ist, da Variablenwerte leichter
nachvollziehbar sind. Diese Option ist besonders nützlich während der
Entwicklungsphase, wenn die Hauptpriorität das Debuggen und die
Fehlersuche sind.
Ja, erst sauber programmieren und dann -Os.
Schon klar, dass das danach außer mir auch noch einer lesen will.
Tut mir leid, es zieht sich etwas...
Ich packe das dann auf GitHub wenn ich fertig bin.
Vllt. will ja einer in den Sommerferien eine ATmega2560 Portierung
machen?
Stored B. schrieb:> Der Compiler versucht, den Code so zu> optimieren, dass er weniger Speicherplatz benötigt, auch wenn dies> möglicherweise auf Kosten der Ausführungsgeschwindigkeit geht.
Meine Erfahrung: mit -Os gewinnt man beides, auch
Ausführungsgeschwindigkeit. Noch interessanter: manche Sachen, die mit
-Os gut funktionieren, werden mit -Og Fehler bringen. Ein Beispiel:
1
ISR(TIMER1_COMPA_vect,ISR_NAKED){/* Timer/Counter1 Compare Match A */
2
PORTB|=1<<2;
3
reti();
4
}
Mit -Os bekommen wir:
1
SBI 0x05,2
2
RETI
Das wird funktionieren.
Mit -Og bekommen wir:
1
IN R24,0x05
2
ORI R24,0x04
3
OUT 0x05,R24
4
RETI
Scheinbar wird das auch funktionieren, nur langsamer. In Wirklichkeit
aber werden hier SREG und R24 in ISR geändert, das führt zu groben
Programmfehler.
Matthias schrieb:> Was mit errno oder C++?
Mit C++ ist alles ok!
Zumindest war es das, als ich es zum letzten Mal gesehen habe.
Welche Probleme hättest du gerne?
Naja, tendenziell machen alle globalen Variablen ohne Mutex Probleme.
Und da man zum Beispiel kein "new Serial", oder "Serial val()" sondern
"Serial.begin()" schreibt, wird es sicher irgendwo Kauderwelsch geben...
Nutzen die in den Bibliotheken pthread?
Matthias schrieb:> Nutzen die in den Bibliotheken pthread?
KA, es gibt gefühlte 20 Tausend Arduino Libs.
Sicherlich nutzen einige davon die ProtoThreads, davon musst du
ausgehen.
Und seit die Coroutinen in C++ Einzug gehalten haben, wird das Konzept
wohl in Zukunft häufiger zu finden sein.
Matthias schrieb:> irgendwo Kauderwelsch
Alles klar!
Keine Fragen mehr.
Alles klar!
Steve van de Grens schrieb:> ...
Ok!
POSIX Threads findet man unter Linux(und anderen Unix artigen).
Damit ist Arduino und sein Framework wohl aus dem Rennen.
Also muss ich meine Antwort wohl konkretisieren.
POSIX Threads: Eher Nein!
Proto Threads: Durchaus!
Arduino F. schrieb:> POSIX Threads findet man unter Linux(und anderen Unix artigen).
Nutze ich seit Jahren auch auf Windows.
Cross-Platform-fähig.
Scheinbar sind in der avr-libc auch Fragmente von POSIX zu finden
Matthias schrieb:> braucht das ja sonst noch einer??
Busy-Wait, naja, ich glaub das kommt man noch so gerade selber drauf.
Die lock Funktion sollte den Thread schlafen legen und sofort zu anderen
Threads wechseln. Inkl. Priority Boosting des aktuell den Mutex
besitzenden Threads. Und rekursiv funktioniert es auch nicht.
Steve van de Grens schrieb:> Mal sehen, ob dann überhaupt noch jemand mit AVR bastelt.
Vielleicht gibt's ja dann Multicore-AVR, dann muss das OS das können 😋
Nur mal angenommen, eine Bibliothek würde die posix pthread einbauen.
Was hätte man denn dann verloren?
Ein Zustandsautomat definiert das einfach auf nichts und der wo es
braucht, implementiert das je nach eigenen Vorstellungen.
Wenn man da die einzelnen speziellen Funktionen der unzähligen RTOS mit
# ifdef einbauen will ist man ja verloren...
Matthias schrieb:> Was hätte man denn dann verloren?
Du müsstest halt genau dieses API implementieren damit die pthread
Funktionen was aufrufen können. Aber warum POSIX Threads und nicht
Standard C bzw. C++ threading?
Matthias schrieb:> Wenn man da die einzelnen speziellen Funktionen der unzähligen RTOS mit> # ifdef einbauen will ist man ja verloren...
Genau so macht man es aber, Stichwort OSAL (OS abstraction layer).
Matthias schrieb:> Was hätte man denn dann verloren?
RAM,
CPU Takte
> Ein Zustandsautomat definiert das einfach auf nichts und der wo es> braucht, implementiert das je nach eigenen Vorstellungen.
Du meinst wohl ein Makro. Ganz so einfach ist es in der Praxis nicht.
Multi-Threading ist nicht nur ein Balkon den man wahlweise weg lassen
kann. Das ganze Programm muss strukturell darauf ausgelegt sein und das
bekommt man nicht zum Nulltarif.
Ich hätte da eine Frage, jetzt wird es bissi wild und ich verliere so
bissl die Kontrolle...
Kann der Compiler irgendwie den Stackpointer überwachen? Also
automatisch Code einfügen, der irgendwas macht, wenn der SP < x ist?
Matthias schrieb:> Also automatisch Code einfügen, der irgendwas macht, wenn der SP < x> ist?
Tja, die MPU vom Cortex-M kann das ohne Geschwindigkeitsverlust
(allerdings erst wenn auch wirklich ein Zugriff erfolgt).
Johann L. schrieb:>> Ist dafür das naked Funktionsattribut,>> oder muss das in ASM sein?>> Ist eh kaum ein Unterschied, weil GCC in naked Funktionen offiziell nur> Inline Asm unterstützt.
Na dann kann man das aber auch gleich bleiben lassen und die ISR normal
als separate Assemblerfunktion schreiben. 100x einfacher und lesbarer!
Matthias schrieb:> Das mir zu schwer.
Das wäre dann doch der ideale Zeitpunkt, das ganze RTOS selber bauen
Gedöns grundsätzlich fallen zu lassen. Und vor allem, wenn man keinerlei
Ahnung davon hat.
Nur wegen der 2 Schnittstellen muß man noch lange nicht mit Kanonen auf
Spatzen schießen.
Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt, gleiches
gilt für Atomics.
In der AVR LibC gibt es einige Funktionen, die nicht reentrant sind.
Und die gezeigten Inline Asm Schnipsel funktionieren vielleicht mit viel
Gluck, stellen aber keinen validen Code dar (inkorrekter Code darf
funktionieren, muss aber nicht).
Johann L. schrieb:> Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt,
Sind nicht im Lieferumfang.
Aber hier durchaus vorhanden:
https://github.com/modm-io/avr-libstdcpp
-> bisher nicht getestet
Mein (AVR) Arduino beschwert sich zumindest nicht über ein
Peter D. schrieb:> Das wäre dann doch der ideale Zeitpunkt, das ganze RTOS selber bauen> Gedöns grundsätzlich fallen zu lassen. Und vor allem, wenn man keinerlei> Ahnung davon hat.
Ganz genau. Wenn ein RTOS irgendeinen Sinn ergeben soll, dann doch
allenfalls, wenn man es nicht erst noch selber basteln muss.
Wenn man das nämlich kann, hat man auch keinerlei Probleme damit, eine
Anwendung ganz klassisch ohne RTOS umzusetzen.
Ob S. schrieb:> Wenn man das nämlich kann, hat man auch keinerlei Probleme damit, eine> Anwendung ganz klassisch ohne RTOS umzusetzen.
Oft ist man auf externe proprietäre Bibliotheken/Frameworks angewiesen,
welche synchron implementiert sind. Wenn man dann noch andere Dinge
parallel laufen lassen möchte, braucht man ein RTOS. Das allerdings
kompatibel zu solchen Bibliotheken zu machen könnte interessant werden.
Niklas G. schrieb:> Oft ist man auf externe proprietäre Bibliotheken/Frameworks angewiesen,> welche synchron implementiert sind.
Ist mir noch nie passiert. Hast du Beispiele?
> Wenn man dann noch andere Dinge> parallel laufen lassen möchte, braucht man ein RTOS.
Selbst dann nicht wirklich. Kommt allerdings auch ein wenig darauf an,
was genau da parallel laufen muss. Wenn das dann eine zweiter synchroner
zusammengeklauter Scheiß ist, dann könnte es tatsächlich eng werden...
Also: weniger klauen, mehr selber programmieren und gut isses.
Ob S. schrieb:> Hast du Beispiele?
Proprietär: TouchGFX, die ST USB-PD Library
OpenSource: Die STM32WL55 RF und LoRa Middleware, der ATWILC-Treiber,
FatFs, die I²C-Libraries für die alten STM32, überhaupt alle möglichen
Libraries für (I²C-)Sensoren und Peripherie-ICs
Es gibt bestimmt noch viele mehr für exotische Protokolle z.B. in der
Industrie. Die APIs der ESP32 sind größtenteils synchron, aber dort
benutzt man ja sowieso FreeRTOS.
Die OpenSource-Libraries kann man prinzipiell umbauen, aber der Aufwand
ist oft nicht gerechtfertigt. Wenn man nur ein Framework dieser Art hat
kann man sich herauslavieren indem man den Rest asynchron macht, aber
sobald es mehr als eins ist braucht man ein RTOS. Ich habe das Gefühl,
dass die ganze Embedded-Industrie das Komponentenparadigma nicht
verstanden hat - die Annahme ist immer, man nutzt exakt 1 Framework an
welchem man das ganze Projekt ausrichtet und sonst nichts.
Ob S. schrieb:> Also: weniger klauen, mehr selber programmieren und gut isses.
Und wer bezahlt das? Mal eben so ein 100kLoC-Framework nachbauen kann
sich nicht jedes Unternehmen leisten.
Arduino F. schrieb:> Johann L. schrieb:>> Soweit ich weiß werden Coroutinen in avr-g++ nicht unterstützt,> Sind nicht im Lieferumfang.>> Aber hier durchaus vorhanden:> https://github.com/modm-io/avr-libstdcpp>> -> bisher nicht getestet>> Mein (AVR) Arduino beschwert sich zumindest nicht über ein1#include> <coroutine>
Jetzt musst du nur noch die AVR-gcc toolchain mit multithreading enabled
bauen, und schon wird es auch funktionieren. Die dafür benötigten
„Kleinigkeiten“ werden dich ja nicht groß überfordern…
Oliver
Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne
entsprechenden OS Support. RTEMS+Newlib Support für AVR wurden vor X
Jahren fallen gelassen. Und pthreads gibt's auch keine.
Johann L. schrieb:> Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne> entsprechenden OS Support.
Mit endlichen Automaten. Zu old-scool?
Steve van de Grens schrieb:> Johann L. schrieb:>> Ich seh jetzt nicht wie man Threads vernünftig unterstützen kann ohne>> entsprechenden OS Support.>> Mit endlichen Automaten. Zu old-scool?
Es geht um Unterstützung im Compiler.
Johann L. schrieb:> Es geht um Unterstützung im Compiler.
Meine Erfahrung ist, es funktioniert am zuverlässigsten, wenn man dem
Compiler nicht ins Handwerk pfuscht. Die Compilerbauer verstehen schon
ihr Handwerk.
Ich hab mal in einem früheren Projekt naked Interrupts mit Assembler
benutzt, um dem AVR eine 2. Priorität beizubringen. Rückblickend würde
ich das aber nicht als Masterpiece ansehen.
Peter D. schrieb:> Johann L. schrieb:>> Es geht um Unterstützung im Compiler.>> Meine Erfahrung ist, es funktioniert am zuverlässigsten, wenn man dem> Compiler nicht ins Handwerk pfuscht. Die Compilerbauer verstehen schon> ihr Handwerk.
Das Problem ist, man programmiert halt und rechnet den Speicherbedarf
aus und dann wächst der Stack doch plötzlich da rein, wo er nicht hin
soll und das Teil stürzt unkontrolliert ab.
Wenn man jetzt bissl Luft lässt, so dass man nicht vor jedem
Stackzugriff prüfen muss, könnte man optional schon Rechenzeit gegen
Sicherheit tauschen und bei einem Überlauf den laufenden Thread beenden.
Klar kann man auch den Code manuell vor dem Compilerdurchgang mit
Stacküberlauftests durchziehen, aber...
Matthias schrieb:> Klar kann man auch den Code manuell vor dem Compilerdurchgang mit> Stacküberlauftests durchziehen, aber...
Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die
man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen
Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit
dem letzten Aufruf übrig ist.
Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2
Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller
Initialisierungen angezeigt.
Damit läßt sich bequem die maximale Auslastung während der Laufzeit
ermitteln.
Weiterhin wird noch der letzte Resetgrund ausgegeben. Ist dieser seit
dem letzen Start der Applikation 0x00, dann ab zurück zum Debuggen. Denn
dann ist ja ein wilder Pointer in den Resetvektor gelaufen, d.h. dieses
Programm darf nicht ausgeliefert werden.
Peter D. schrieb:> Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die> man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen> Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit> dem letzten Aufruf übrig ist.> Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2> Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller> Initialisierungen angezeigt.> Damit läßt sich bequem die maximale Auslastung während der Laufzeit> ermitteln.
und wie schaffst du es alle anfallenden Bedingungen zu testen?
Wie erkennst du zerpflückte nicht zusammenhängende Speicherbereiche?
Ich denke an PET2001 da gab es die garbadge collection, der Müll mußte
ab und an rausgetragen werden.
Ich denke an AtariST TOS 1.0 wo nach 128 malloc/free Aufrufe gebombt
wurde, also Absturz, was mit TOS 1.4 nur auf 1024 malloc/free Aufrufe
erweitert wurde aber das Problem nur verschob.
Ich dachte auch mal man könnte auf kleinere AVR sowas machen, aber der
Code wurde immer aufgeblähter und passte dann nicht mehr ins flash.
Meine Erfahrungen, bekannte viel genutzte Variablen nicht dynamisch
zuzuweisen sondern schon vorher zu reservieren, verringert zwar den
freien SRAM aber es kommen zur Laufzeit keine Überraschungen.
Speicher ist wie Hubraum, durch nichts zu ersetzen. Die kleinen Motoren
mit Turbo aufzublasen schaffen auch mehr Probleme als sie lösen, Golf
mit 1,4L und Turbo fällt mir da ein oder die Ford EcoBoost mit in Öl
laufenden Zahnriemen.
Peter D. schrieb:> Matthias schrieb:>> Klar kann man auch den Code manuell vor dem Compilerdurchgang mit>> Stacküberlauftests durchziehen, aber...>> Ich habe in meinen Programmen 2 kleine Prüffunktionen implementiert, die> man per Kommando aufrufen kann. Einmal wird der freie Bereich zwischen> Daten und Stackpointer mit 0x77 gefüllt und getestet, wieviel davon seit> dem letzten Aufruf übrig ist.> Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2> Durchgängen der Mainloop. Beim ersten Aufruf kriegt man die Dauer aller> Initialisierungen angezeigt.> Damit läßt sich bequem die maximale Auslastung während der Laufzeit> ermitteln.>> Weiterhin wird noch der letzte Resetgrund ausgegeben. Ist dieser seit> dem letzen Start der Applikation 0x00, dann ab zurück zum Debuggen. Denn> dann ist ja ein wilder Pointer in den Resetvektor gelaufen, d.h. dieses> Programm darf nicht ausgeliefert werden.
Hm, eine dritte ISR die den SP überwacht, das eine sehr gute Idee!!
Baue das heute Abend ein, nachdem ich die ganzen Fehler behoben habe,
die ich gestern Abend nach zwei Bier reingeschusselt hab...
Btw. ich musste leider wegen einem Namenskonflikt mit dem Repository
umziehen und das Teil in AgileRTOS umbenennen
(https://github.com/ykat-UG-haftungsbeschrankt/agilertos).
Matthias schrieb:> Ich glaube ich bin schon zu alt...>
Aus meine Sicht eher zu jung. Ein mittelprächtig anspruchsvolles
Programm mit aufwendigen Mitteln lösen zu wollen, spricht eher für
mangelnde Weitsicht. Ich kann nur Falk beipflichten:
Falk B. schrieb:> Aber für bissel CAN und Solaranlage scheint das hier> eine verdammt aufgeblähte Lösung zu sein.
Es wäre aus meiner Sicht angebracht, zwei Schritte zurückzutreten, das
Projekt neu aufzusetzen und sich zunächst mal um die einfacheren
Varianten des Multitasking zu kümmern.
Just my 2 cents
Klaus (der soundsovielte)
Klaus S. schrieb:> Multitasking
realisiert man am sinnvollsten und minimal Overhead produzierend mit
einem regelmäßigen Timerinterrupt, der ganz einfach alle regelmäßig zu
erledigenden Sachen aufruft.
J. S. schrieb:> weil alles im Interruptkontext mit vielen Einschränkungen abläuft.
Richtig designt nicht.
Jedes waschechte Multitasking kostet auf dem AVR mehr Ressourcen.
J. S. schrieb:> Das kostet auf jedem μC mehr Ressourcen,
Nicht unbedingt.
Nämlich dann nicht wenn Task/Kontext-Wechsel von der Hardware
unterstützt werden.
Steve van de Grens schrieb:> Denkst du dabei an den Z80?
Nein. Eingeschränkt aber z.B. an den Z380 :)
Z80 hab ich mal interruptgesteuertes Quasi-Multitasking realisiert.
Gerhard H. schrieb:> Eingeschränkt aber z.B. an den Z380
Oh wie cool, der hat ja noch mehr Registersätze! Ich dachte, der Z80 sei
der einzige Prozesser dieser Art.
Steve van de Grens schrieb:> Gerhard H. schrieb:>> Eingeschränkt aber z.B. an den Z380>> Oh wie cool, der hat ja noch mehr Registersätze! Ich dachte, der Z80 sei> der einzige Prozesser dieser Art.
Heute wäre die Werbung für den TMS9900 "Bis zu 2047 Registersätze!"
Wirklich schade, dass diese Architektur aus der Mode gekommen ist. Mit
1MByte On Chip RAM und 0 Wait States würde das gut funktionieren.
https://en.wikipedia.org/wiki/TMS9900
Die Register die beim Taskwechsel gerettet werden müssen sind ja nur das
eine. Man gönnt jedem Task ja seinen eigenen Stack. Wenn man da sparsam
ist dann kann es in langen Debug Sessions enden, oder man ist großzügig,
muss dann aber auch genug RAM haben.
Genug Gründe um für preemptives MT Cortex-M einzusetzen.
Matthias schrieb:> Hm, eine dritte ISR die den SP überwacht, das eine sehr gute Idee!!
Dazwischen kann aber auch sehr viel passieren...
Das testweise Markieren des Zwischenraums Daten<>Stack a'la Peter D. ist
sicher die bessere Idee. Diese Markierung performance- gesittet d.h.
stückweise zu kontrollieren wäre für besagte periodische ISR m.M. eine
sinnvollere Aufgabe.
Im allgemeinen aber sollten fehlgeleitete SRAM Zugriffe und Stackfehler-
und damit der nötige Einsatz von Kontroll- Instrumenten die absolute
Ausnahme darstellen. Kann gut sein daß man da mit Assembler besser am
Puls der Hardware hört und dran ist :)
Peter D. schrieb:> Die andere Funktion zählt die maximalen Timerticks (1ms) zwischen 2> Durchgängen der Mainloop.
Ich hab dafür (so verfügbar) einen Hardware TC-Counter mit vollem Speed
= maximaler Zeitauflösung laufen. Der kann dann nicht nur zu
verschiedenen Zeitpunkten in der Main abgefragt werden sondern auch in
Interrupts, um die Zeiten der Abarbeitung derselben zu kontrollieren.
Falk B. schrieb:> Matthias schrieb:>> Hallo, ich bins...>>>> Ich brauche für die Solaranlage eine Steuerung mit CAN und RS485.>>>> Kann mir bitte einer sagen, was da nicht stimmt?>> Du hast die Netiquette nicht beachtet, längere Quelltexte gehören in> den Anhang.>>> Ich habe schon die>> ganze Nacht gesucht. Leider sind da in dem Quelltext von dem TCB_t und>> ListItem_t so viele #ifdef dass ich nicht weiß, wie ich aus einem>> StackType_t * ein TCB_t bekomme.>> Ich auch nicht. Aber für bissel CAN und Solaranlage scheint das hier> eine verdammt aufgeblähte Lösung zu sein.
Hab dem Teil noch paar Eventhandler für Arme spendiert...
https://ykat-ug-haftungsbeschrankt.github.io/agilertos/index.html#autotoc_md2
Die Tasks (statisch und vheap) laufen noch nicht richtig und der mutex
auf dem vheap fehlt. Weiß nicht, ob ich das heute und morgen noch
schaffe.
Danach steht erst mal was anderes an...