Forum: Mikrocontroller und Digitale Elektronik Verständnisproblem mit Multitasking in uC


von SemiTech (Gast)


Lesenswert?

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)

von holger (Gast)


Lesenswert?

>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.

von Timo N. (tnn85)


Lesenswert?

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.

von Mario E. (Firma: privat) (marioeduardo)


Lesenswert?

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

von Olaf (Gast)


Lesenswert?

> 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

von M. K. (sylaina)


Lesenswert?

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 ;)

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

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.

von Mehmet K. (mkmk)


Lesenswert?

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.

von Niklas Gürtler (Gast)


Lesenswert?

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...

von Falk B. (falk)


Lesenswert?

Siehe Multitasking

von Sascha R. (srt2018)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Anselm (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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)"

von Vincent H. (vinci)


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von M. K. (sylaina)


Lesenswert?

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.

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Olaf (Gast)


Lesenswert?

> 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

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von W.S. (Gast)


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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 (int i=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
void executeCommand(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.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

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.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

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.

von Stefan F. (Gast)


Lesenswert?

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.

von The A. (the_a343)


Lesenswert?

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.

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.