Multitasking kernel für ATtinys in ASM

OP #230503
Lesenswert?

Ein immer wieder auftretendes Problem bei den ATtinys ist das
gleichzeitige Abhandeln mehrerer Aktionen.

Ich habe mir die Mühe gemacht ein kleines cooperatives Multitasking
Systemchen in ASM zu stricken, weil ich für den beengten Speicher der
ATtinys noch nichts derartiges gefunden habe.


Die Eckpunkte:
Speicherverbrauch:
1 byte für Timer
4 byte für Taskhandling
+ 4 byte pro reserviertem Task

CPU-Belastung
ca 70 Taktzyklen für Taskwechsel
ca 70 Taktzyklen für TaskTick-handling
70 CPU-cycles klingt auf den ersten Blick viel sind aber in
Wirklichkeit grade mal 3% der CPU Last, ergo 97% frei für
Userprogramme.

Anwendung:
Das Hauptprogramm initialisiert alle IO und ruft den MosInit auf.
Anschließend werden mit AddTask die einzelnen Tasks eingetragen und das
Multitasking mit einem rjmp mosStartScheduler gestartet.

Jeder Task erledigt die notwendigen Teile, und gibt anschließend mit
rcall MosNextTask die CPU an den nächsten Task ab. Alternativ kann sich
ein Task mit rcall MosSleep (Sleep Wert in MosTicks in R26/R27) eine
gewisse Zeit lang warten. Ein MosTick beträgt standardmäßig 2048
Taktcyklen, also bei 8MHz sind das 256µS. Ein MosSleep(4) wartet also
1ms. Ein MosSleep(0xfffe) wartet also knapp 17 Sekunden Mit
MosSleep(0xffff) kann man den Task anhalten bis er von einem anderen
Task mit MosNotify wieder 'aufgeweckt' wird.
Die MosTicks werden mit dem Timer0 Overflow int (prescaler=8=>256*8)
erzeugt, näheres siehe Beschreibung in den Sourcen.

Eine Tastenentprellung würde also zB folgendermaßen aussehen
(Pseudocode):
lies Taste
wenn Taste gedrückt
MosSleep(8)
Taste noch immer gedrückt? dann kein Tastenprellen
etc...
rjmp zurück auf lies Taste

Und zwischen den beiden Abfragen können alle anderen Tasks machen was
sie wollen...

Das task-switching funktioniert übrigens indem ich mir die beim Call
vom Aufrufer abgelegte Adresse vom Stack hole und in der Taskliste
zwischenspeichere. Dann wird zum nächsten Task geschalten und die
vormals abgelegte Adresse des neuen Tasks auf den Stack gepusht und ein
ret ausgeführt.

Da ich den AVR erst seit einigen Wochen verwende, gibt es sicher einige
Dinge die man noch verbessern kann. Ich hoffe also auf eure Hilfe und
Verbesserungsvorschläge.

LieGrü,
strub
Angehängte Dateien:
Gast #230507
Lesenswert?

Hallo.

Mir ist nicht so ganz klar, wozu Task Scheduler bei AVRs gut sind.
(Wozu sie bei riesigen Betriebssystemen gut sind, verstehe ich schon.)
Ist doch ein sehr starres Prinzip. Wenn ich meine Software um
Interrupts herum aufbaue, kriegt jeder "Task" sofort das Zepter in
die Hand, wenn er das braucht und gerade kein anderer Int mit höherer
Priorität ansteht. Den Overhead spare ich mir, und nach spätestens 10
us ist der entsprechende Task dran.

mfg
gerd
Gast #230509
Lesenswert?

@Gerd

"Mir ist nicht so ganz klar, wozu Task Scheduler bei AVRs gut sind."


Man kann damit Wartezeiten vermeiden, besonders, wenn viel Sachen
gleichzeitig zu machen sind.

Der Scheduler ist aber nur eine Task in der Mainloop, d.h. Sachen, die
ihn nicht brauchen, laufen direkt in der Mainloop, wie sonst auch.

Man könnte ihn auch in einen Timerinterrupt setzen, muß dann aber
darauf achten, daß alle ihm übergebenen Funktionen als Interrupt laufen
(nichtatomare Parameterzugriffe unter Interruptsperre usw.).


Allerdings programmiere ich sowas lieber in C:

http://www.mikrocontroller.net/forum/read-4-49709.html#new


Peter
OP #431889
Lesenswert?

Hallo Peter!

Bin zufällig wieder über meinen eigenen Beitrag gestolpert. Der Vorteil 
meines kleinen schedulers liegt im minimalen Ressourceverbrauch. Der 
Code ist grade mal ein paar dutzend Byte groß und sogar mit einem tiny13 
mit minimalem SRAM kommt man locker über die Runden.
Wenn man das ganze in C sauber lösen wollte, dann würde man alleine für 
das swappen der registers für jeden task 32 byte brauchen.

LieGrü,
strub

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren