Ich beschäftige mich gerade mit Betriebssystemen in Mikrocontrollern.
Das wichtigste Merkmal vom OS scheint wohl das Multitasking bzw. die
Prozessverwaltung zu sein.
So wie ich es verstehe, werden dabei mehrere Prozesse (Programme)
"gleichzeitig" abgearbeitet.
Es wird z.B. ein Timer gesetzt über dem jede Millisekunde zum nächsten
Prozess geschaltet werden kann.
Davor werden aber alle Variablen im Stack zwischengespeichert und der
Prozessverwaltung mitgeteilt, wie mit den Daten umgegangen werden soll,
sobald wider in dieses Prozess gesprungen wird.
Ich denke mal, dass es bei den meisten "kleineren" Anwendungen, die z.B.
mit einem Atmega realisiert werden, keinen Sinn machen würde, so einen
Aufwand zu betreiben, da es nur unnötig mehr Arbeitszeit und Speicher
kosten würde.
Ich frage mich aber, ab wann so etwas Sinn machen würde.
Vielleicht kann mir jemand dazu ein gutes Beispiel geben!
Der Grund ist einfach, dass ich so ein Multitasking System gerne auf
einem Atmega328p nachbilden würde, aber ich sehe hier keinen Grund dazu
Multitasking zu betreiben.
Einfach nachbilden und dabei unnötig mehr Rechenzeit und Speicher zu
verbrauchen macht mir auch keine Freude, weil da der Sinn fehlt(z.B. I/O
Eingänge prüfen und gleichzeitig etwas berechnen).
Wahrscheinlich liegt das aber eher daran, dass ich noch nicht so viele
Projekte mit einem uC realisiert habe.
Und die 2. Frage die ich mir stelle ist folgende:
Bei zeitkritischen Prozessen, wo z.B. innerhalb von 10 Taktzyklen ein
Byte über die Serielle Schnittstelle übertragen werden soll, weil es
sonst zu Komplikationen führen würde, da wäre es doch verheerend mitten
im Prozess rauszuspringen.
Wie löst man das in diesem Fall?
Kann man da einfach für die 10 Taktzyklen die Interrupts kurz
ausschalten? Was wäre aber, wenn genau in diesem Moment ein wichtiges
Interrupt stattfinden sollte, wie z.B. beim Timer.
Wie ließe sich das Problem lösen?
(Bei evtl. Codebeispielen bitte möglicht in Assembler, da nur geringe C
Kenntnisse vorhanden sind)
>So wie ich es verstehe, werden dabei mehrere Prozesse (Programme)>"gleichzeitig" abgearbeitet.
"Gleichzeitig" geht auf einem Atmega nicht. Da liegst du schon mal voll
daneben. Das ist kein Multicore.
>Es wird z.B. ein Timer gesetzt über dem jede Millisekunde zum nächsten>Prozess geschaltet werden kann.
Auf einem Atmega? Völliger Quatsch.
>Bei evtl. Codebeispielen bitte möglicht in Assembler
Sonst hast du keine Wünsche zu Weihnachten?
Schau dir ein RTOS an, z.B. FreeRtos und nimm dazu einen
schnellen ARM Controller mit >50MHz. So macht das Sinn.
holger schrieb:>>So wie ich es verstehe, werden dabei mehrere Prozesse (Programme)>>"gleichzeitig" abgearbeitet.>> "Gleichzeitig" geht auf einem Atmega nicht. Da liegst du schon mal voll> daneben. Das ist kein Multicore.
Das weiß er doch selbst. Deswegen die Anführungszeichen.
>>Es wird z.B. ein Timer gesetzt über dem jede Millisekunde zum nächsten>>Prozess geschaltet werden kann.>> Auf einem Atmega? Völliger Quatsch.
Warum Quatsch? Genau so könnte man es in der Theorie bewerkstelligen. Ob
es Sinn ergibt so etwas zu auf einem ATmega zu realisieren ist eine
andere Frage.
>>Bei evtl. Codebeispielen bitte möglicht in Assembler>> Sonst hast du keine Wünsche zu Weihnachten?
Er hat darum gebeten. Wenn du nichts beizutragen hast, dann schreib
nicht. Warum immer diese unfreundlichen Antworten?
> Schau dir ein RTOS an, z.B. FreeRtos und nimm dazu einen> schnellen ARM Controller mit >50MHz. So macht das Sinn.
RTOS ist ein Realtime OS. Das hat nur bedingt etwas mit Multitasking zu
tun. RTOS wird da verwendet, wo Determinismus gefragt ist. Multitasking
erfordert keine Echtzeit.
Ich fange mal mit der Antwort bei meiner Applikation und ein wenig
Theorie an:
Ich steuere eine Kaffeemaschine, ob eine SAECO oder wie bei mir einen
2-kreiser (www.kaffeewiki.de) ist egal. Im Kern ist das eher eine
langsame, gemütliche Sache,aber die Menge an Aufgaben macht den Einsatz
eines Mutitasking sinnvoll, da man einfach "überblickbarer" und
"modular" programmieren kann. Ein Auszug, aus den Modulen:
Messung der Temperatur an 3 Stellen auf ca 0.3 Grad genau, Regelung der
Temperatur, Steuerung des Bezuges, Tests beim Einschalten (Leitungsdruck
da, funktioniert die Kesselsonde), evtl Timer für eine eine Mühle
steuern.
Ein "preemptives Multitasking" scheidet bei einem AtMega für mich hier
aus, da zu aufwendig, weil: um bei einem IRQ alle Zustände zu sichern
und wieder herzustellen, mußt du du grob gerechnet 40 register / Bytes
sichern und wieder herstellen, bis du dann bei deinem eigentlich Code
bist, der dann den eigentlichen Job tut, vergeht noch ein wenig Zeit. 40
Byte ins RAM schreiben sind 80 Taktzyklen, plus "Kleinkram" sind 100
Taktzyklen. Bei 16 MHz sind das etwa knapp 7ys. Das ganze am Ende in
umgekehrter Reihenfolge nochmal sind 15ys bei jedem IRQ, unabhängig
davon ob das eine Serielle oder ein Timer oder sonst was ist.
Jetzt muß du zusammenzählen, wer aller in deiner Aufgabenstellung einen
IRQ auslöst. Also z.b. I2C, UART, Timer, ... und die Last dadurch
abschätzen.
Dann weißt du, was dir für die eigentliche Bearbeitung dessen, was hier
über IRQs an Daten gekommen ist, übrig bleibt.
Mit einer groben Abschätzung geht es weiter: Wenn du alle 100ys einen
IRQ hast (z.B. I2C mit 100KHz sind 10Kbyte/sec) geht rund ein sechstel
der Zeit nur dafür verloren, daß du darauf überhaupt reagieren kannst.
Dann kommt noch der eigentliche Code für den Auslöser des IRQ dazu. Ich
hab selbst kein preemptives Multitasking imlementiert, aber um eine
Zeitscheibe von mind 5 - 10 ms wirst du nicht herumkommen. Zu beachten
ist ferner, daß C bei komplexen Strukturzugriffen einiges an Code
erzeugt.
Wenn du sagst, daß du in einigen Taktzyklen ragieren mußt, so geht das -
wenn du das wirklich so wörtlich meinst - über FPGA o.ä. Bei einem yP in
wenigen 50ns reagieren, ist schon heftigst.
Zur Theorie der Betriebssysteme gibt es grob (wir lassen mal MultiCore
aus) preemptives Multitasking (mit den Unterarten "Echtzeit" und "nicht
Echtzeit" wie Windows und LINUX. Und dann wie das "gute alte Windows
3.1", ein "kooperatives Multitasking". Das beruht darauf, daß ein
Prozess freiwillig (mittels Return from Subroutine) die Kontrolle an das
OS zurückgibt, und seinerseits dann in einer riesigen Schleife auf
Ereignisse (Informationen das Betriebssystems) wartet.
Ich habe diese Überlegung so weitergesponnen, daß ich eine Aufgabe in
ihre einzelnen Abschnitte, Verarbeitungsschritte zerlegt habe. Das ist
dann eine Sammlung von einigen Unterprogrammen, die in der passenden
Reihenfolge den gewünschten Job tun.
Jetzt habe ich das Ganze um die Überlegung erweitert, daß ich in sehr
vielen Fällen "irgendwann" "irgendwas" mache. Das führt zur
Basisstruktur
Zeitverzögerung und Pointer auf eine Funktion, die nach Ablauf der
Zeitverzögerung durchzuführen ist. Falls jetzt ein obiger
Verarbeitungsschritt aus 5 Unterprogrammen bestünde, gäbe das ein "array
of struct", das 5 Einträge groß ist.
Jetzt hab ich über das Ganze einen Überbau, der mehrere solcher Aufgaben
= Liste von UNterprogrammen = Prozess abarbeitet. So mal im Groben
geschildert.
Vorteil dieser Methode : Bei einer Zeitscheibe von 10ms, stehen dann
10ms minus IRQ Last für alle Unterprogramme in einem Durchgang zur
Verfügung. D.H. EIN MAL 15ys Overhead für alle "Teilaufgaben" = aktuell
durchzuführende Prozeduren aller Prozesse. Und nicht 15ys für jeden
Prozess.
Nachteil: Gibt ein Prozess die Kontrolle nicht ab, steht alles. Dieses
Argument zählt bei einem ATMEGA u.ä. nicht, da diese Prozessoren keine
Sicherheitsmechanismen kennen. Jeder Prozess kann prinzipiell in Kernel
Bereiche schreiben = zerstören.
Jetzt lasse ich mal Luft für Kommentare deinerseits.
lg Mario
> Ich frage mich aber, ab wann so etwas Sinn machen würde.> Vielleicht kann mir jemand dazu ein gutes Beispiel geben!
Es bringt dann Vorteile wenn ein Projekt so gross das mehrere Leute
daran arbeiten weil es dann einfacher ist ihre Aufgaben voneinander zu
trennen.
Bei kleineren Sachen gibt es einen graubereich wo man sowohl
herkoemmlich (Statemachine, Timer, IRQ) wie auch mit so einem
Betriebsystem in etwa dasselbe erreichen kann. Da ist es dann wichtiger
was der Programmierer so gewohnt ist.
Bei sehr kleinen Controllern (1k Ram oder weniger) ist es dann meistens
Quatsch oder gar unmoeglich.
Allerdings verschieben sich die Grenzen auch durch das Problem das man
loesen moechte und durch die Hardware die man zur Verfuegung hat.
Letztlich ist das also eine Entscheidung wo Erfahrung sinnvoll ist.
Olaf
holger schrieb:> "Gleichzeitig" geht auf einem Atmega nicht. Da liegst du schon mal voll> daneben. Das ist kein Multicore.
Multitask != Multicore
Eine der Stärken z.B. des Amigas war das Multitasking, mir wäre es aber
neu, dass der MC68000, oder seine Nachfolger, mehrere Cores hat. Der TE
hat ja nicht grundlos "" benutzt ;)
Ein OS mit mehreren Tasks verhält sich nicht anders wie ein normales
Programm mit Interrupts.
Das normale Programm ist quasi die Task niedrigster Priorität. Jede
Interrupt-funktion ist eine Task höherer Priorität, die aufgrund von
Events gestartet wird: Timer, SIO Byte reingekommen, ADC-wandlung
fertig.
Dazu parallel ist die Frage, ob Tasks sich unterbrechen können, analog
geschachtelte Interrupts.
Der wesentliche Punkt ist aber, dass Interrupts sich immer beenden
müssen und neu gestartet werden. Das gibt es zwar auch bei OS, z.b.
Autosar, Basic Tasks. Verbreitet ist aber, an jeder Stelle Rechenzeit
abgeben zu können mit sleep oder wait. Das erfordert dann einen
Scheduler und ein wenig Aufwand, es gibt aber genügend RTOSe mit wenigen
KB Rom und RAM unter 1k.
Schau Dir mal Protothreads von Adam Dunkels an. Dort kannst Du
- ohne ein ausgewachsenes RTOS aufsetzen zu müssen - sehr gut
nachvollziehen, wie ein kooperatives Multitasking so in etwa
funktioniert.
http://dunkels.com/adam/pt/
Bei kleinen Projekten setze ich Protothreads sehr oft ein. Aber man muss
schon aufpassen, wann es an der Zeit ist, die Reissleine zu ziehen. Denn
manche Projekte bleiben nicht wie geplant klein, sondern wachsen.
Und je weiter das Projekt waechst, desto unhandlicher und verworrener
wird es mit Protothreads.
Aber für den Einstieg und für kleine Projekte ist es sehr
empfehlenswert.
Was man bei der Entscheidung Pro/Kontra präemptives Multithreading immer
beachten sollte ist die Synchronisation. Wenn mehrere Threads auf die
gleichen Daten zugreifen, muss man dies mit Mutexen, Semaphoren,
Condition Variables usw. absichern um Race Conditions zu vermeiden. Die
Implementation derer ist nicht ganz einfach, aber die Nutzung auch
nicht: Tatsächlich ist es sehr schwierig, ein wirklich 100% korrektes
Multithreading-Programm damit zu erstellen. Man kann sich sehr leicht
Fehler einbauen, die erst nach Monaten im Betrieb auftreten. Besonders
gemein wird es bei Multicore-systemen mit Caches; das ist bei
Mikrocontrollern zum Glück nicht so relevant.
Wenn man statt Mutexen einfach die Interrupts komplett sperrt handelt
man sich neue Probleme ein; man verliert die Echtzeit-Fähigkeit und kann
ein so implementiertes Programm nur mit großem Aufwand auf echtes
Multithreading portieren.
Ein weiteres aber nicht alleine ausreichendes Mittel zur Synchronisation
sind Atomics; diese werden z.B. von ARM unterstützt, von AVR aber nicht,
weshalb Multithreading da auch weniger Sinn macht. Allgemein sind die
ARMs explizit für Multithreading gemacht (sowohl Cortex-A als auch -M),
die AVRs aber nicht. Auf ARM ist es also sowohl einfacher als auch
effizienter...
SemiTech schrieb:> Und die 2. Frage die ich mir stelle ist folgende:> Bei zeitkritischen Prozessen, wo z.B. innerhalb von 10 Taktzyklen ein> Byte über die Serielle Schnittstelle übertragen werden soll, weil es> sonst zu Komplikationen führen würde, da wäre es doch verheerend mitten> im Prozess rauszuspringen. Wie löst man das in diesem Fall? Kann man da> einfach für die 10 Taktzyklen die Interrupts kurz ausschalten? Was wäre> aber, wenn genau in diesem Moment ein wichtiges Interrupt stattfinden> sollte, wie z.B. beim Timer.> Wie ließe sich das Problem lösen?
Solchen Zugriff sollte dann ein präemptives Betriebssystem selbst
erledigen, und das mittels geeigneter Schnittstellen bereitstellen. Dann
kann es selbst Einfluss auf den Task-Scheduler-Timer nehmen.
Um zB. auch zu verhindern, dass verschiedene Tasks gleichzeitig auf die
gleichen Ressourcen zugreifen. Der AVR hat wohl aber keine Mittel, um
Tasks den Zugriff etwa auf Ports zu verbieten.
Multitasking braucht man eigentlich immer, selbst bei den kleinsten
Applikationen. Z.B. eine Weckuhr hat schon mindestens 5 Tasks, die
gleichzeitig ausgeführt werden und sich nicht gegenseitig behindern
dürfen:
- Anzeige
- Tasteneingabe
- Uhrzeit zählen
- Weckzeitvergleich
- Buzzer pulsen
Multitasking muß nicht hochkomplex und Ressourcen verschlingend sein.
Eine einfache Möglichkeit sind mehrere Statemaschines, die jeweils nur
eine Aktion ausführen, sich den nächsten State mehrken und zu Mainloop
zurück kehren. Die Mainloop ruft sie der Reihe nach auf, aber da sie nur
wenige µs lange Aktionen ausführen, wirkt es für den Benutzer, als
würden sie parallel ausgeführt.
Z.B. Protothread arbeitet nach diesem Prinzip. Die Macros sind
allerdings nicht so leicht zu verstehen und können Seiteneffekte haben.
https://de.wikipedia.org/wiki/Protothread
Man kann solche Statemaschines aber auch direkt hinschreiben mit
sichtbaren Returnpunkten.
Ein Kollege hat so eine coole Funktion geschrieben:
RunDelayedFunction(FUNKTIONSNAME, 5) // führt nach 5s die Funktion auf.
in der mainloop steht dann nurnoch:
ExecuteDelayedFunction();
Hier wird der eigentliche Scheduler ausgeführt.
die ExecuteDelayedFunction() wird auch immer dann ausgeführt wenn ich
auf irgendwas warten muss (Anstatt einer while(true)(für ADC-Wandler
oder sonstiges))
Gruß
Anselm
Anselm schrieb:> Ein Kollege hat so eine coole Funktion geschrieben:> RunDelayedFunction(FUNKTIONSNAME, 5) // führt nach 5s die Funktion auf.
Ich finde so einen Scheduler auch recht nützlich. Die auslösende Task
braucht sich um nichts mehr zu kümmern.
Beitrag "Wartezeiten effektiv (Scheduler)"
SemiTech schrieb:> Und die 2. Frage die ich mir stelle ist folgende:> Bei zeitkritischen Prozessen, wo z.B. innerhalb von 10 Taktzyklen ein> Byte über die Serielle Schnittstelle übertragen werden soll, weil es> sonst zu Komplikationen führen würde, da wäre es doch verheerend mitten> im Prozess rauszuspringen.> Wie löst man das in diesem Fall?> Kann man da einfach für die 10 Taktzyklen die Interrupts kurz> ausschalten? Was wäre aber, wenn genau in diesem Moment ein wichtiges> Interrupt stattfinden sollte, wie z.B. beim Timer.> Wie ließe sich das Problem lösen?>> (Bei evtl. Codebeispielen bitte möglicht in Assembler, da nur geringe C> Kenntnisse vorhanden sind)
Aus diesem Grund besitzen RTOS ihre Primitiven in doppelter Ausführung.
Also gibt es beispielswiese neben "RingbufferSend" noch ein
"RingbufferSend_fromISR". Damit muss man trotz Threads nicht auf
Hardware Interrupts verzichten und kann das Byte von der seriellen
Schnittstelle zeitgerecht einlesen.
Das man ohne preemptives Multitasking weit kommen kann beweisen Windows
3.x und frühere Versionen von Android.
Beide Betriebssysteme setzen auf Event Queues. Das Betriebssystem legt
Ereignisse (Tastendruck, Touch, Timer, Datenpakete übermittelt) in
Warteschlangen. Es führt die main Loops der Anwendungsprogramme
abwechselnd aus, bis das Programm freiwillig die Kontrolle wieder
abgibt.
Der Haken dabei ist: Wenn ein Programm die Kontrolle eben nicht mehr
abgibt, hängt der ganze Rechner. Das ist bei Servern sehr lästig, aber
auch bei Desktop PC wenn z.B. ein größerer Druckauftrag deswegen hängen
bleibt oder wenn man gerade gemachte Arbeiten noch nicht gespeichert
hat.
Preemptives Multitasking unterbricht die Programme (threads) aktiv, so
das ein einzelnes Programm nicht mehr so einfach das ganze System zum
Stillstand bringen kann.
Jetzt frage dich: Wie wichtig ist dieses Feature auf deinem
Mikrocontroller? Lässt du darauf mehrere Programme laufen, denen du
nicht traust und die sich nicht gegenseitig blockieren dürfen?
Wohl kaum.
Es gibt aber noch einen Zweiten Vorteil: Solange die Programme so tun
können, als wären sie alleine auf dieser Welt (kein Datenaustausch
untereinander und keine gemeinsam genutzten Schnittstellen), ist deren
Programmierung sehr vie einfacher, wenn das Betriebssystem sich um das
Umschalten kümmert. Wie andere schon weiter oben schrieben, endet der
Spaß jedoch wieder schnell, sobald die Programme gemeinsam auf irgend
etwas zugreifen.
Also ist mein Fazit: Preemptives Multitasking ist eine feine Sache, aber
nicht auf Mikrocontrollern eher nicht.
Stefanus F. schrieb:> Also ist mein Fazit: Preemptives Multitasking ist eine feine Sache, aber> nicht auf Mikrocontrollern eher nicht.
Im Prinzip hat man das ja immer auf Mikrocontrollern. Ich denke aber,
die meisten hier, die Mikrocontroller benutzen, haben immer nur ein
Programm auf dem Mikrocontroller laufen.
Die Frage ist auch, was man als Programm definiert. Ich denke, je
nachdem wie man es definiert, haben hier viele doch schon eine Art
Multitasking auf nem AVR oder ähnliches benutzt. Wenn ich mein Netzteil
mal so anschaue, das fragt Potis ab, misst Spannung und Strom,
Temperatur und, ganz unabhängig davon, quatscht das Netzteil via
serieller Schnittstelle mit dem Rest der Welt. Ich könnte also schon
zumindest einen Teilbereich als Netzteil-Programm definieren und ein
Teilbereich als Kommunikations-Programm und beide Teile laufen
unabhängig voneinander und zwar nebeneinander. Das zeigt mir eigentlich
nur: Wenn man mal genauer drüber nachdenkt sind die
Single-Task-Programme eher die Ausnahme. Wenn man lernt und erst
einsteigt in die µC-Welt sind Single-Task-Programme noch häufig, ja die
Regel, aber wenn man konkrete Aufgaben hat wirds ganz schnell eng nur
ein Programm auf dem µC zu haben. Ich sag mal, das ist Multitasking
eigentlich die Regel und nicht die Ausnahme.
Stefanus F. schrieb:> Wohl kaum.
Schön wärs :-) Oft hat man doch alle möglichen Libraries und Treiber,
welche eben nicht event-basiert arbeiten. Da stehen dann diverse
Warteschleifen drin, welche auf externe Hardware warten. In dieser Zeit
könnte man präemptiv in andere Threads wechseln und diese bearbeiten.
Diese Libraries komplett umzubauen ist auch nicht immer realistisch.
> Schön wärs :-) Oft hat man doch alle möglichen Libraries und Treiber,> welche eben nicht event-basiert arbeiten. Da stehen dann diverse> Warteschleifen drin, welche auf externe Hardware warten.
Wer sowas verwendet disqualifiziert sich doch selbst aus der auch nur
halbwegs professionellen Softwareentwicklung raus und dann brauch man
auch kein Multitasking.
Aber mal ein Beispiel wo es ganz nett ist:
Du hast eine Steuerung die dir wichtig ist. Zum Beispiel weil sie dein
Seewasseraquarium regelt und dir schnell 10kEuro schaden entstehen wenn
da was schief geht. Dann waere vielleicht eine Task in deinem
Betriebssystem ganz nett die immer kontrolliert ob alle anderen Tasks
laufen, ob deren Rechenzeit im erlaubten Bereich ist, ob Werte plausibel
sind, ob der Stackpointer brauchbar aussieht. Und nur wenn alles stimmt
wird der Watchdog zurueckgesetzt.
Olaf
Olaf schrieb:> Wer sowas verwendet disqualifiziert sich doch selbst aus der auch nur> halbwegs professionellen Softwareentwicklung raus und dann brauch man> auch kein Multitasking.
Dann nenne mir doch mal einen professionellen Weg wie man z.B. ein
WLAN-Modul oder eine SD-Karte anbindet.
Niklas G. schrieb:> Dann nenne mir doch mal einen professionellen Weg wie man z.B. ein> WLAN-Modul oder eine SD-Karte anbindet.
Zum Beispiel (da hast du WLAN und SD Karte zusammen):
http://stefanfrings.de/net_io/index.html
Das war eins der wenigen Mikrocontroller-Programme, die ich für die
Industrie geschrieben habe. Das Multitasking basiert auf einer
Main-Loop, welche die Unterprogramme nacheinander aufruft. Die
Unterprogramme sind wiederum Zustandsautomaten.
Warteschleifen kommen dort nicht vor - würden auch nicht funktionieren.
In Android Anwendungen durfte man bis vor Kurzem auch keine
Warteschleifen verwenden, weil sonst die gesamte GUI hing (da
single-threaded).
Während Android auf einem Linux Kern basiert und nur die GUI single
Threaded war, war das ganze Windows 3.x single threaded. Wenn da eine
GUI hing, reagierte die Maus nicht mehr und der Drucker blieb stehen.
Trotzdem war Windows 3.11 Netzwerkfähig.
Was ich relativ häufig sehe ist, dass für die Netzwerk-Kommunikation ein
separater Mikrocontroller verwendet wird, der von der Haupt-Steuerung
des Gerätes losgelöst ist. Zum Beispiel in Druckern, Messgeräten und
Telefonanlagen. Das ESP-01 Modul wurde für solche Anwendungsfälle
gemacht, ebenso die Produkte der Firma Wiznet.
SemiTech schrieb:> Ich beschäftige mich gerade mit Betriebssystemen in Mikrocontrollern.> Das wichtigste Merkmal vom OS scheint wohl das Multitasking bzw. die> Prozessverwaltung zu sein.> ...> Davor werden aber alle Variablen im Stack zwischengespeichert und der> Prozessverwaltung mitgeteilt,...
So, du beschäftigst dich. Also hast du keinen realen Anwendungsfall vor
der Nase, der gelöst werden soll.
Nun, für preemptives Multitasking werden Prozesse oder Threads
definiert, wobei jeder Prozess seinen eigenen Stack hat, wo im
Unterbrechungsfalle die CPU-Register gespeichert werden, damit man sie
bei Wiederbeleben des Prozesses wiederherstellen kann.
Das Ganze funktioniert aus Sicht eines Prozesses also wie das Pausieren
des Ablaufes durch einen Interrupt. Aber ein gewöhnlicher Interrupt
steckt nicht dahinter, sondern es ist eine Verwaltung, die anhand
diverser Dinge entscheidet, mit welchem Prozeß es denn weitergehen soll.
Das ist alles kompliziert und schluckt deshalb Platz und Zeit und man
kann sich in jedem Prozeß zwar blockierend wie beim Abarbeiten eines PAP
benehmen, muß aber trotzdem auf den Rest der Welt Rücksicht nehmen, z.B.
indem poplige Warte-Trampelschleifen einen "Sleep"-Aufruf des OS
enthalten, um nicht benötigte Rechenzeit zurückzugeben.
Ich halte derartige Firmware-Konstrukte für µC in den allermeisten
Fällen für nicht zweckmäßig. Stattdessen ist es dort weitaus besser, mit
Events und kooperativem Multitasking zu arbeiten.
W.S.
Stefanus F. schrieb:> Zum Beispiel (da hast du WLAN und SD Karte zusammen):
Der SD-Karten-Zugriff sieht mir doch sehr synchron-blockierend aus:
1
MMC_SPI.DATA=byte;//Sendet ein Byte
2
loop_until_bit_is_set(MMC_SPI.STATUS,SPI_IF_bp);
und
1
for(inti=0;i<5;i++){
2
if(mmc_init()==1){
Beim WLAN-Modul schreibst du sogar im Kommentar dass es dauern kann:
1
// This function usually takes only some few ms, but it may take longer
2
// when the WLAN module is busy.
3
voidexecuteCommand(char*command)
W.S. schrieb:> Nun, für preemptives Multitasking werden Prozesse oder Threads> definiert, wobei jeder Prozess seinen eigenen Stack hat
Jeder Thread hat einen eigenen Stack, jeder Prozess hat min. 1 Thread.
Wenn man überhaupt Prozesse implementiert.
Niklas G. schrieb:> Der SD-Karten-Zugriff sieht mir doch sehr synchron-blockierend
Korrekt erkannt. Das hätte ich dort noch besser machen können. Hier wird
maximal 8 SPI Takte lang blockiert. An dieser Stelle habe ich die
Library einfach so verwendet, wie sie der Autor geliefert hat.
Es ist aber nicht so blockierend, dass Netzwerk-Kommunikation und
SD-Karten Zugriff sich gegenseitig ausschließen. Du kannst Files von der
SD Karte downloaden, gleichzeitig eine andere Webseite benutzen, I/O
Pins kontrollieren und die DCHP Adresse aktualisieren.
> Beim WLAN-Modul schreibst du sogar im Kommentar dass es dauern kann
Ich wollte Dir eigentlich nur die die Ethernet Variante als Beispiel
zeigen. Die WLAN variante ist billig zusammen gefrickelt. Die WLAN
Variante passt hier nicht zum Thema, denn da befindet sich der ganze IP
Stack auf einem separaten Mikrocontroller.
Ich weiß, ich bin selbst an der Irritiation Schuld, weil du nach WLAN
gefragt hattest und ich habe mit der Ethernet Variante geantwortet.
Sorry, da habe ich gepennt.
Stefanus F. schrieb:> Es ist aber nicht so blockieren, dass Netzwerk-Kommunikation und> SD-Karten Zugriff sich gegenseitig ausschließen.
Manche SD-Karten-Operationen können 1-2 Sekunden dauern; deine
Anforderungen an "nicht-blockierend" scheint ja sehr gutmütig zu sein.
Stefanus F. schrieb:> Ich wollte Dir eigentlich nur die die Ethernet Variante als Beispiel> zeigen
Ethernet ist ja auch vergleichsweise easy. Es ging mir daher schon um
WLAN.
Stefanus F. schrieb:> Die WLAN Variante passt hier nicht zum Thema, denn da befindet> sich der ganze IP Stack auf einem separaten Mikrocontroller.
Kommt aufs Modul an. Der IP-Stack ist sowieso nicht so sehr das Problem;
lwIP z.B. ist vorbildlich asynchron programmiert. Die Low-Level-Treiber
hingegen gerne mal nicht so.
Niklas G. schrieb:> Manche SD-Karten-Operationen können 1-2 Sekunden dauern; deine> Anforderungen an "nicht-blockierend" scheint ja sehr gutmütig zu sein.
Ja, wie gesagt habe ich es mir an dieser Stelle einfach gemacht.
> lwIP z.B. ist vorbildlich asynchron programmiert. Die Low-Level-Treiber> hingegen gerne mal nicht so.
Ja, ebenso das µIP vom selben Autor, auf dem meine verlinkte Firmware
basiert, die ich als Beispiel nannte.
Hallo,
ich wollte nur noch etwas Futter liefern:
wie bereits oben beschrieben, haben die meisten RTOS pro Task einen
eigenen Stack Bereich. Hier muss man sehr genau den Stack-(Heap) Bedarf
kalkulieren. Sonst knallts oder der speicher reicht nicht.
Lösungen sind hier kooperative RTOS mit Stichwort: SINGLE STACK RTOS
auch gibt es ein Patterns namens ACTIVE OBJECT, das das
Aufgabenhandling abstrahiert.
hier mal noch einen Link den ich auch sehr interessant finde:
http://www.state-machine.com/doc/concepts
Grüße, Adib.