Forum: Mikrocontroller und Digitale Elektronik avr co-operative scheduler/multitasking


von Jens H. (jens_h791)


Angehängte Dateien:

Lesenswert?

co-operative multitasking
scheduler für avr ohne irq plus framework für TOS

Supported AVR CPUs: m328p, m644, ...

kompilieren: make
flash      : make isp

Anpassen:
CPU und Programmer wird in "makefile" eingestellt
Anzahl Tasks werden in "config.h" definiert


Das Programm eignet sich gut für mehrere parallele Aufgaben.
Er hilft ausufernde state-machines zu vermeiden und eignet
sich sehr gut für Kommunikations-funktionen.
Der scheduler muss explizit aufgerufen werden,
dadurch bewahrt man sich die volle kontrolle über das timing
im Programm. Zudem wird das debuggen möglich.
Zum Testen am besten einen Arduino verwenden. In config.h wird
der PIN für eine LED definiert. Wenn ein anderes Testboard
verwendung findet, sollte dies angepasst werden.


scheduler: wechseln zwischen den tasks
timer2   : millisekunden zähler (bestimmte CPUs!)
xitoa    : elm-chan version von printf und co.
config.h : alle Konfigurationen
master   : das Demo Programm
cpu.h    : viele nützliche macros zb: "cfg_lo(D4); cfg_in(D5)"
serx.h   : zur generierung von code für mehrere serielle ports

BUGS: nur wenige AVR CPUs mit einer USART in serx.h unterstützt,
      timer2 prescaler Berechnung nur eingeschränkt universell


THANKS:
elm-chan : xitoa (he is the KING)
günter greschenz: gos (the scheduler)
avr-freaks: id8 - force 8 bit alu operations in gcc
atmel : please, create seriel bus without usb nonsense

************************************

you are the best ;-)

https://www.mikrocontroller.net

************************************

KEYWORDS: scheduler task tasks arduino avrdude makefile xitoa xatoi 
printf preemptive framework timer ctc-mode milliseconds  wiring avr-libc 
serial communication state-machine multitasking

KISS ;-)

von Codix (Gast)


Lesenswert?

Das Ganz ist ziemlich Quick & Dirty programmiert.

Wenn schon bei task_create nicht die Limits, hier NUM_TASKS, abgefragt 
wird, dann ist das nicht schön und neigt zu Fehlern/Fehlverhalten, wenn 
man bei der Programmierung vergisst NUM_TASK seinen Bedürfnissen 
anzupassen.
Der TCB sieht etwas mager aus. Da fehlt mir zuviel, Priorität, Mailbox, 
usw..

Und mal ehrlich, das Beispiel überzeugt nicht wirklich. Das bekomme ich 
mit weniger Code auch hin. Und ohne Overhead für das bissel Taskwechsel.


Multitasking sieht anders aus.
Jens H. schrieb:
> Das Programm eignet sich gut für mehrere parallele Aufgaben.
Wie soll das Deiner Meinung nach funktionieren? Parallel sieht anders 
aus.
Das kann dieser Scheduler nicht leisten.

Das ist ein netter Versuch und das macht auch bestimmt Spass sich in die 
Materie einzuarbeiten.
Aber sinnvoll und professionell einsetzbar ist das nicht.
Da musst Du noch einiges dafür tun.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Jens H. schrieb:
> Das Programm eignet sich gut für mehrere parallele Aufgaben.
> Er hilft ausufernde state-machines zu vermeiden und eignet
> sich sehr gut für Kommunikations-funktionen.

 Will nicht meckern aber das sieht irgendwie unordentlich und
 zusammengekleistert aus.

 Tasks können nicht ausgetragen bzw. gelöscht werden, wenn ein
 Task blockiert, sind alle blockiert und vor allem - da sind keine
 parallelen Aufgaben möglich.
 Du hast es zwar richtig angeführt - kooperativ, aber kooperativ und
 parallel gehen eben nicht zusammen und deswegen eignet sich dein
 Beispiel nicht für irgendwelche Kommunikations-funktionen.

 P.S.
 Und mal ehrlich - das Ganze kann genausogut in einem while(1) loop
 in main() laufen - absolut kein Unterschied...

: Bearbeitet durch User
von dünnwandiger Trog (Gast)


Lesenswert?

Naja, Zielgruppe ist auch eher die Arduino Community.

von Jens H. (jens_h791)


Lesenswert?

Marc V. schrieb:
> Tasks können nicht ausgetragen bzw. gelöscht werden,
dies ist ein Beispiel, also auf das notwendigste reduziert.
Wer in der Lage ist einen scheduler zu benötigen, kann solche Funktionen 
sicherlich selber hinzufügen.

>  Task blockiert, sind alle blockiert und vor allem - da sind keine
>  parallelen Aufgaben möglich.
Wie du erkannt hast, kooperativ!

>  Du hast es zwar richtig angeführt - kooperativ, aber kooperativ und
>  parallel gehen eben nicht zusammen und deswegen eignet sich dein
>  Beispiel nicht für irgendwelche Kommunikations-funktionen.
Aber sicher doch, oder läuft das Programm bei dir nicht ;-) ?


Wenn ein Task blockiert, z.B. mit "while(PIND&1);" kann dir dieser 
scheduler nicht helfen. Das geht nur mit preemptive multitasking!
Wie ich versucht habe, auf ganz einfache weise zu Demonstrieren in 
master.c:comm(), schreibt man solche Warteschleifen um in "while(PIND&1) 
schedule();" und schon läuft es.

>
>  P.S.
>  Und mal ehrlich - das Ganze kann genausogut in einem while(1) loop
>  in main() laufen - absolut kein Unterschied...
Doch ein wesentlicher Unterschied: state-machine.
Es ist mir vollkommen klar, das du mit einer State-Machine dieses 
minimale Beispiel nachprogrammieren kannst, aber es ist nicht das 
gleiche! Angenommen du hast Peripherie per i2c angebunden und musst ein 
Protokoll implementieren bei dem jede Aktion wieder in einzelne 
send/recv Schritte unterteilt ist, dann benötigt jede Function eine 
eigene State-Machine, die wiederum in einer weiteren State-Machine läuft 
usw.usf., mit einem scheduler kann jede dieser State-Machines so 
aussehen wie ich es in master.c:comm() gezeigt haben. Die gleiche 
Funktionalität, aber einfacher und kürzer in der Implementation.
Fazit: jedes aktive warten auf einen Stimulus wird nach dem Muster:
"while( nicht_fertig() ) schedule();" geschrieben, anstelle von:
switch(state) { case 0: aktion(); state=1; break; case 1: 
if(nicht_fertig) return; else state=2;" usw..

Gruß,
Jens

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Jens H. schrieb:
> Wer in der Lage ist einen scheduler zu benötigen, kann solche Funktionen
> sicherlich selber hinzufügen.

 Wenn er in der Lage ist solche Funktionen selber hinzuzufügen, dann
 kann er auch gleich alles neu schreiben und seinen Bedürfnissen
 anpassen.


> Fazit: jedes aktive warten auf einen Stimulus wird nach dem Muster:
> "while( nicht_fertig() ) schedule();" geschrieben, anstelle von:
> switch(state) { case 0: aktion(); state=1; break; case 1:
> if(nicht_fertig) return; else state=2;" usw..

 Das sind (in deinem Fall) rein kosmetische Unterschiede.
 Ausserdem ist Statemachine (in meisten Fällen) weitaus effizienter
 als dein Scheduler, alleine schon wegen der PUSH/POP Orgie.
 Auf diese Weise werden andere Tasks zwar nicht blockiert, dafür aber
 solange einfach hintereinander durchlaufen, bis der blockierende Task
 wieder weitergeht.
 Da du nicht mit Timeslices arbeitest, wird z. B. bei 3 blockierenden
 Tasks (von 4) nur der vierte Task immer wieder durchlaufen aber du
 (bzw. dein Programm) hat keine Ahnung davon, dass 3 Tasks blockieren.

 Ehrlich gesagt, ich habe noch nie eine sinnvolle Anwendung mit
 kooperativem Multitasking ohne Timer gesehen.
 Selbst eine einfache Ampelsteuerung geht nicht ohne Timer...


 Schaue mal hier:
 Beitrag "Wartezeiten effektiv (Scheduler)"

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
Noch kein Account? Hier anmelden.