Forum: Projekte & Code yanos


von uCler (Gast)


Angehängte Dateien:

Lesenswert?

YANOS - Yet Another Narrow Operating System

Hallo Zusammen,

die erste Frage ist vielleicht - och nee, warum denn schon wieder eins?

Das habe ich mich auch gefragt. Vorher bin ich immer mit meinen timer 
tasks und einer mehr oder weniger grossen Statusmaschine in der mainloop 
ausgekommen. Dann wurde ich bei einem Projekt gezwungen, zwei nicht 
kooperative Tasks gemeinsam laufen zu lassen. Dazu habe ich einen 
simplen Taskswitcher geschrieben. Dann kam der Wunsch auf, die 
Rechenzeit nicht mehr 50:50, sondern zur Laufzeit je nach Bedarf 
aufzuteilen. Das ging auch noch recht einfach.

Das Projekt wuchs und wuchs. Mailboxen und Messages wurden auf 
Applikationsebene implementiert. Ein dritter Task, der nur ab und an mal 
laufen sollte, wurde angedacht. Die Lockingmechanismen fuer 
konkurierende Hardwarezugriffe wurden auch immer komplizierter. Da jetzt 
noch weiter irgendwie dran rumzufrickeln machte wenig Sinn. Die Zeit war 
also reif fuer ein OS.

Kein Problem, gibt ja genug. Aber die kleinen koennen meist nicht mit 
nicht kooperativen Tasks umgehen. Die die es koennen arbeiten oft 
prioritaetsbasiert. Damit unsere beiden Tasks damit laufen, muessten sie 
die gleiche Prioritaet bekommen. Dann laufen sie aber wieder 50:50. Die 
naechst Besseren, die anhand der Prioritaet Laufzeitverteilungen 
vornehmen, sind dann allerdings schon ziemlich fett und behaebig.

So entstand das Xte OS. Da ich so einen Ansatz bislang noch nicht 
gesehen habe, stelle ich das mal ins Forum. Das ist zwar sehr auf eine 
bestimmte Anwendung optimiert, aber vielleicht kann das ja trotzdem 
jemand von Euch gebrauchen.

Gruss Udo



von hansl (Gast)


Lesenswert?

servus,

hast du vielelciht ein beispielprogramm das die
anwendung zeigt bei der hand und magst es heir hineinstellen?

danke
 hansl

von Thomas (Gast)


Lesenswert?

Für welche Prozessor ist das Ganze denn gedacht?
Habe diesbezüglich im Quelltext nichts gefunden. Und mit dem 
Assemblerschnipseln wirds wohl nicht plattformunabhängig sein.

von uCler (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Hans,

vor ca. 2 Wochen habe ich den Code auf das grosse Projekt losgelassen. 
Hat auch sehr gut funktioniert. Diesen Source darf/moechte ich aber 
nicht posten (waere auch viel zu viel).

Ich habe aber noch meinen Testcode, den ich fuer die Entwicklung von 
Yanos verwendet habe. Das kannst Du Dir gerne mal anschauen. Aber 
Achtung - das ist lediglich zum Testen und anschliessend fuer die 
Muelltonne geschrieben worden.



Hallo Thomas,

das laeuft auf einem M32. Ist wohl eher selten im Forum. Sollte aber 
egal sein, da es bis auf den Scheduler reines C ist. Portierungen eines 
Schedulers auf die hier im Forum hauptsaechlich verwendeten Prozessoren 
habe ich schon mehrere gesehen.

In einer aelteren Version hatte ich den Scheduler auf die klassische 
Weise implementiert. Da kann man den Assemblercode ja nahezu 1:1 von 
Prozessor zu Prozessor uebernehmen. Hier habe ich diese halbwegs 
vorhandene plattformunabhaengigkeit bewusst verlassen, um auf 
Geschwindigkeit zu optimieren. Mit jetzt knapp ueber 5us (ohne 
OS-overhead) habe ich die Threadwechselzeit nahezu halbiert.



Gruss Udo



BTW: Gibt hier noch andere M16/M32 Programmierer die stctx/ldctx 
verwenden? Es kommt mir so vor, als haette ich diese Befehle irgendwie 
vergewaltigt.....

von Peter D. (peda)


Lesenswert?

uCler wrote:

> Die Lockingmechanismen fuer
> konkurierende Hardwarezugriffe wurden auch immer komplizierter.

Wie hast Du denn das gelöst ?

Bei einer Mainloop sind solche Probleme ja sehr selten, da ja alles 
immer der Reihe nach abläuft.

Aber mit Deinem OS müssen ja solche Probleme alle Nase lang auftreten, 
da ja alles virtuell parallel ist.

Insbesondere auf 8-Bittern ist ja auch Datenmurx quasi vorprogrammiert, 
bei allen globalen Variablen, die mehrbytig sind (Zeitscheibe haut genau 
dazwischen, macht nen neuen Wert und man hat dann ein neues Byte + ein 
altes Byte).

Das ist es auch, was mich vor einem OS zurückschrecken läßt.

Die möglichen Deadlock und Datenmurx-Probleme sind mit einem OS ja kaum 
beherrschbar.


Die Datenzugriffe zwischen Main und Interrupts zu sichern 
(Interruptsperre), geht ja noch.
Aber wenn plötzlich jede Maintask die andere unterbrechen kann, sieht ja 
keiner mehr durch.


Ich hab z.B. mehrere Statemachines, wo zu Anfang alle Eingänge per SPI 
eingelesen werden, dann verarbeiten das die Statemachines und dann wird 
wieder alles per SPI ausgegeben. Das kann aber nur funktionieren, wenn 
die Daten während eines kompletten Zyklus konstant bleiben.

Bzw. es können auch zwischenzeitlich Fehlerstates auftreten, die 
keinesfalls ausgegeben werden dürfen.
Erst wenn der abschließende Fehlerchecker die Daten nochmal geprüft hat, 
das kein gefährlicher Zustand entstehen kann, dann dürfen sie angelegt 
werden.


Peter

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Das ist es auch, was mich vor einem OS zurückschrecken läßt.
>
> Die möglichen Deadlock und Datenmurx-Probleme sind mit einem OS ja kaum
> beherrschbar.
>
>
> Die Datenzugriffe zwischen Main und Interrupts zu sichern
> (Interruptsperre), geht ja noch.
> Aber wenn plötzlich jede Maintask die andere unterbrechen kann, sieht ja
> keiner mehr durch.

Dafür gibt es Synchronisationsmechanismen wie Semaphoren und Queues. 
Richtig angewendet ist damit der "Murx" gut beherrschbar.

> Ich hab z.B. mehrere Statemachines, wo zu Anfang alle Eingänge per SPI
> eingelesen werden, dann verarbeiten das die Statemachines und dann wird
> wieder alles per SPI ausgegeben. Das kann aber nur funktionieren, wenn
> die Daten während eines kompletten Zyklus konstant bleiben.

Wenn kein anderer Task in diesen Daten herumpfuscht (warum sollte er 
auch?), dann gibt es da keine Probleme.

von Peter D. (peda)


Lesenswert?

Andreas Schwarz wrote:

> Dafür gibt es Synchronisationsmechanismen wie Semaphoren und Queues.
> Richtig angewendet ist damit der "Murx" gut beherrschbar.


Das sind dann Notlösungen, die wieder zusätzliche Ressourcen 
verbrauchen, statt das Problem zu vermeiden.

Besonders heimtückisch sind die Queues.
Wenn man da nicht 101%-ig garantieren kann, daß der empfangende Prozess 
immer schneller als der sendende ist, läuft die Queue über.
Oder sie ist sehr groß und läuft sehr voll und dann arbeitet der 
empfangende Prozess noch völlig veraltete Daten ab und z.B. Dein 
Regelkreis schwingt.

Ich habe daher bessere Erfahrungen mit einem Datenpuffer für genau einen 
Datensatz gemacht.
Wenn dann mal der Empfänger nicht nachkommt, überschreibt einfach der 
Sender den Puffer mit den aktuelleren Daten, also z.B. ein alter 
AD-Wandler Wert geht verloren und alles läuft problemlos weiter.


Peter

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Andreas Schwarz wrote:
>
>> Dafür gibt es Synchronisationsmechanismen wie Semaphoren und Queues.
>> Richtig angewendet ist damit der "Murx" gut beherrschbar.
>
>
> Das sind dann Notlösungen, die wieder zusätzliche Ressourcen
> verbrauchen, statt das Problem zu vermeiden.

Das sind "Lösungen", keine Notlösungen.

> Besonders heimtückisch sind die Queues.
> Wenn man da nicht 101%-ig garantieren kann, daß der empfangende Prozess
> immer schneller als der sendende ist, läuft die Queue über.
> Oder sie ist sehr groß und läuft sehr voll und dann arbeitet der
> empfangende Prozess noch völlig veraltete Daten ab und z.B. Dein
> Regelkreis schwingt.
>
> Ich habe daher bessere Erfahrungen mit einem Datenpuffer für genau einen
> Datensatz gemacht.

Und was hindert dich daran das mit einem RTOS genauso zu machen? Für 
sowas einen Queue zu verwenden ist natürlich sinnlos.

> Wenn dann mal der Empfänger nicht nachkommt, überschreibt einfach der
> Sender den Puffer mit den aktuelleren Daten, also z.B. ein alter
> AD-Wandler Wert geht verloren und alles läuft problemlos weiter.

Wieso nicht gleich den Messwert im Regelungs-Task einlesen? Nur weil man 
einen Hammer (RTOS) hat darf nicht alles wie ein Nagel (Task) aussehen.

von Peter D. (peda)


Lesenswert?

Andreas Schwarz wrote:

> Das sind "Lösungen", keine Notlösungen.

Für mich setzen Lösungen immer bei der Ursache an und Notlösungen 
bekämpfen aber nur die Wirkung.

> Wieso nicht gleich den Messwert im Regelungs-Task einlesen?

Weil ich keine Zeit verschwenden will.
Der ADC-Task ist freilaufend und kann mehrere Eingänge einlesen, glätten 
und in Puffern ablegen.
Und jede Task, die einen Wert braucht, liest ihn sofort aus dem Puffer.


Ich habe sehr gute Erfahrungen damit gemacht, daß ich alle Tasks in der 
Mainloop in einer eindeutig definierten Reihenfolge ohne gegenseitige 
Unterbrechung aufrufe.
Damit ergibt sich eine sehr geringe Fehleranfälligkeit und sehr stabiles 
Arbeiten.

Natürlich dürfen die Tasks keine Zeit vergeuden, jede Task bricht sofort 
ab, wenn sie grad nichts zu tun hat.
Und Prozesse, die erst nach einer bestimmten Wartezeit ausgeführt werden 
dürfen, übergebe ich dem Scheduler. Der ist auch eine Task in der 
Mainloop, d.h. wird auch nur zu ganz eindeutigen Zeiten ausgeführt.


Es ist halt nur ne klitzekleine Umstellung in der Programmierweise 
erforderlich, Bedingungen werden nicht wartend, sondern abweisend 
programmiert.
Also nicht: warte bis Bedingung wahr, sondern: breche ab solange 
Bedingung nicht wahr.


Peter

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Andreas Schwarz wrote:
>
>> Wieso nicht gleich den Messwert im Regelungs-Task einlesen?
>
> Weil ich keine Zeit verschwenden will.
> Der ADC-Task ist freilaufend und kann mehrere Eingänge einlesen, glätten
> und in Puffern ablegen.
> Und jede Task, die einen Wert braucht, liest ihn sofort aus dem Puffer.

Wenn du kooperatives (also kein preemtives Scheduling verwendest), dann 
gibt es damit grundsätzlich kein Problem, weil der Kontextwechsel erst 
stattfindet wenn der ADC-Task fertig ist und sich schlafen legt.

Wenn du preemtives Scheduling verwendest (was in deinem Fall wenig Sinn 
macht), dann kannst du eine critical section verwenden um 
sicherzustellen dass der ADC-Task beim Schreiben der globalen Variablen 
nicht preemtiv unterbrochen werden kann:

taskENTER_CRITICAL();
globaler_adcwert = adcwert;
taskEXIT_CRITICAL();

> Natürlich dürfen die Tasks keine Zeit vergeuden, jede Task bricht sofort
> ab, wenn sie grad nichts zu tun hat.
> Und Prozesse, die erst nach einer bestimmten Wartezeit ausgeführt werden
> dürfen, übergebe ich dem Scheduler. Der ist auch eine Task in der
> Mainloop, d.h. wird auch nur zu ganz eindeutigen Zeiten ausgeführt.
>
>
> Es ist halt nur ne klitzekleine Umstellung in der Programmierweise
> erforderlich, Bedingungen werden nicht wartend, sondern abweisend
> programmiert.
> Also nicht: warte bis Bedingung wahr, sondern: breche ab solange
> Bedingung nicht wahr.

Damit machst du ja all das von Hand was dir ein kooperatives OS abnehmen 
kann. Statt dem Scheduler zu sagen wann die Funktion das nächste Mal 
aufgerufen werden möchte und zu returnen, hast du bei einem OS für jeden 
Task eine eigene Endlosschleife, und wenn es nichts zu tun gibt weil du 
z.B. auf den nächsten Abtastzeitpunkt für den ADC oder die Regelung 
wartest, rufst du sleep_until(t + 100) auf. Und zusätzlich hast du z.B. 
eine komfortable Möglichkeit über Queues Nachrichten zu verschicken, 
ohne dass du in jedem Empfängertask if(!neue_daten_vorhanden) return; 
machen musst, usw.

von Joerg W. (joergwolfram)


Lesenswert?

Meine Meinung ist, dass ein multitaskingfähiges OS in einem ROM ein 
totaler Overhead ist. Es sind ja alle Prozesse und Funktionen bekannt, 
ein OS zu verwenden ist eigentlich nur ein Grund, ineffizient zu 
programmieren. Anders sieht es aus, wenn zum Erstellungszeitpunkt 
"unbekannte" Prozesse später auch geladen und entladen werden sollen. 
Dann ist ein OS eine saubere Schnittstelle, gegen die auch nichts 
spricht. Zum Probieren kann man das auch im ROM machen...

Jörg

von uCler (Gast)


Lesenswert?

> Die Lockingmechanismen fuer
> konkurierende Hardwarezugriffe wurden auch immer komplizierter.

Wie hast Du denn das gelöst ?

Hallo Peter,

kleines Vorher/Nachher Beispiel aus der Praxis. Als NVRam setzen wir 
FRam ein. Das haengt ebenso am IIC wie die RTC und ein 
Temperaturfuehler. Zur Vermeidung von Konflikten musste der IIC-Code an 
eine gemeinsame Stelle.

Um das System besser zu verstehen - Neben den OS-Tasks laufen noch 3 
harte Realtime-Tasks (Timer Interrupts).  Im 1ms Task laufen nur 
SW-Timer - Laufzeit vernachlaessigbar. Im 10ms Task laeuft im 
Wesentlichen das PID - in diesem Fall ein Touchscreen. Wenn man mit 8 
Fingern drauf rumtrommelt steigt die Rechenzeit auf ca. 1ms, also ca. 
10%. Im 100ms Task laeuft neben einer SW-Uhr im Wesentlichen die IIC 
Kommunikation. Die Gehaeuseinnentemperatur brauchen wir seit der 
Umstellung von STN auf TFT eigentlich nicht mehr. Sie wurde ohnehin nur 
alle paar Minuten gelesen. Auf die RTC wird nur beim Uhr stellen 
schreibend zugegriffen. Um die IIC Zugriffe zu minimieren wird im 
Betrieb aus der SW-Uhr gelesen. Bleibt das FRam.

Grosse Datenmengen werden auf CF oder MMC gehalten. Das ist aber relativ 
lahm und unsicher bei power fail. Fuer Statusbytes und Parameterbloecke 
ist das NVRam da. Das habe ich segmentiert in Bytes, Worte, Longs und 
unterschiedlich grosse Bloecke. Frage war, wie gross darf ich den 
groessten Block machen, um Echtzeit zu garantieren.

Aus dem Bauch raus habe ich mal maximal 50% fuer die harte Echtzeit 
angenommen. Datentransfer auf den beiden CAN-Bussen und der andere Kram, 
den ich oben nicht genannt habe, machen etwa 10% aus. Bleiben also grobe 
Kante 30ms fuer die groessten Bloecke. Schreibt also eine Applikation 
einen grossen Block ins Shadow-RAM ist kurz darauf der 100ms Task fuer 
maximal 30ms beschaeftigt - und 30 mal kommt der OS_Timer_Tick nicht 
durch.

Das fuehrte dann zu folgenden, lustigen Fehlern. Normalerweise antwortet 
ein Modul am CAN-Bus innerhalb von 5ms. Der timeout wurde auf 20ms 
gesetzt. Das geht auch 100000 Mal gut. Aber wir hatte alle paar Tage mal 
einen timeout. Immer dann, wenn ein Task auf eine Antwort wartete, 
waerend der andere vorsichtshalber mal den kompletten Geraetestatus 
abspeicherte, um im Fall des Falles nach einem Powerfail evtl. an der 
gleichen Stelle weitermachen zu koennen (schreibt sich jetzt schnell - 
die Suche war es nicht).

So - was tun? Timeout verlaengern? Bloecke verkuerzen? Retry 
Mechanismus? Anderswie zurechtfrickeln? Oder eben ein OS anstelle des 
Taskswitchers einsetzen (siehe meinen Ausgangspost).

Jetzt ist alles ganz einfach. Einzelne Bytes oder Worte werden direkt 
aus der Applikation heraus geschrieben. Bloecke gehen nach wie vor 
uebers Shadow-Ram. Der ganze IIC-Code ist in einem OS Task gekapselt. 
Ueber Signale bekommt der mitgeteilt, ob er die Uhr stellen, einen Block 
ins FRam schreiben oder sonstwas auf dem IIC-Bus anstellen soll. Liegt 
nichts an, ist dieser Task tot.

An dieser Stelle sieht man dann auch, warum ich den OS_Timer_Tick 
unbedingt bei 1ms lassen wollte. Der 100ms Task ist jetzt praktisch leer 
- die SW-Uhr braucht so gut wie keine Rechenzeit. Ueber den CAN-Bus hat 
das Board als Master volle Kontrolle, und der Touch ist im Normalbetrieb 
in Ruhe. So stehen fuer die OS-Tasks knapp 98% an Rechenleistung zur 
Verfuegung, und so im 5ms-Bereich kann man jetzt sogar bei den OS-Tasks 
von weicher Echtzeit reden.

Puuh - viel Text. Ein weiteres Beispiel nur noch in Stichworten. Es ist 
jetzt relativ einfach, gleichzeitig mehrere Files zu oeffnen, und quasi 
gleichzeitig zu lesen oder zu schreiben.

Gruss Udo

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Joerg Wolfram wrote:
> Meine Meinung ist, dass ein multitaskingfähiges OS in einem ROM ein
> totaler Overhead ist. Es sind ja alle Prozesse und Funktionen bekannt,
> ein OS zu verwenden ist eigentlich nur ein Grund, ineffizient zu
> programmieren. Anders sieht es aus, wenn zum Erstellungszeitpunkt
> "unbekannte" Prozesse später auch geladen und entladen werden sollen.

Ich verstehe nicht wieso das ein Kriterium sein soll - die Vorteile 
eines RTOS, nämlich dass es einem abnimmt was Peter und viele andere von 
Hand machen, haben nichts damit zu tun ob Prozesse zur Laufzeit 
hinzugefügt/entfernt werden sollen. Das würde ja auch die 
Echtzeitfähigkeit und damit das "RT" in RTOS kaputtmachen.

von uCler (Gast)


Lesenswert?

Hallo Joerg,

ich habe hier 'nur' zwei Tasks. Und die sind mir auch seit Monaten 
bekannt. Aber die sind nicht kooperativ. Wie soll ich die denn laufen 
lassen? Wenn Du etwas effizienteres kennst wie diese Minimalversion 
eines OS, dann wuerde ich mich freuen, wenn Du mir das mitteilst.

Gruss Udo

von Falk (Gast)


Lesenswert?

@uCler

>ich habe hier 'nur' zwei Tasks. Und die sind mir auch seit Monaten
>bekannt. Aber die sind nicht kooperativ. Wie soll ich die denn laufen
>lassen?

Wieso nicht kooperativ? Schlecht programmiert?

MfG
Falk

von Peter D. (peda)


Lesenswert?

uCler wrote:
...
> Der ganze IIC-Code ist in einem OS Task gekapselt.
...

Ich verstehe ehrlich gesagt überhaupt nicht, wo da das OS hilft.

Was bedeutet "I2C ist ein OS-Task" praktisch gesehen ?

Ich hätte I2C in seinen Interrupthandler gepackt und gut is.

Dann noch ein Struct definieren, in dem die Slaveadresse, Datenpointer 
und Datenlänge abgelegt werden und los geht der Interrupt.

Die Tasks, die dann I2C machen wollen, gucken nach, ob dieser Struct 
frei ist und starten dann I2C.
Oder man legt ein Array an (für jede Task ein Eintrag), das der 
I2C-Interrupt abklappert.


> Puuh - viel Text. Ein weiteres Beispiel nur noch in Stichworten. Es ist
> jetzt relativ einfach, gleichzeitig mehrere Files zu oeffnen, und quasi
> gleichzeitig zu lesen oder zu schreiben.

Hmm, Files öffnet man doch per Filehandler.
Auch in nem Single-Task-DOS kann ich mehrere Files öffnen (soviel, wie 
Handler frei sind).


Peter


P.S.:
Ein Kollege von mir, der den CAN-Bus programmiert, wollte auch gerne 
eine maximale Latenzzeit von 2ms haben.
Ich wollte aber einen 1-Wire Temperatursensor benutzen, was länger 
gedauert hätte.
Ich hab ihm dann einfach nen Timerinterrupt geschrieben, der dann 
bitweise das 1-Wire gemacht hat und dann gings wieder.
In nem Struct wurde abgelegt, wieviel Bytes nach dem 1-Wire-Reset zu 
senden sind, wieviel zu empfangen und wenn beide Zähler 0 waren, hat 
sich der Interrupt selber disabled.
Ich arbeite sehr gerne mit Interrupts.

von Joerg W. (joergwolfram)


Lesenswert?

Auch wenn ich jetzt alle Zusammenhänge nicht kenne, versuche ich mal zu 
schreiben, wie ich an die Sache herangehen würde.
Das erste Problem sind die nichtkooperativen Tasks. Sowas sollte es 
eigentlich nicht geben, ausser sie wurden von einem anderen System mehr 
oder weniger übernommen. Da es jetzt ja funktioniert, scheinen sie ja 
vorher jede Menge Zeit nutzlos verbraten zu haben. Da muß ich Falk voll 
recht geben, so etwas kann nicht besonders gut programmiert sein oder 
stammt bereits aus einem Kontext wo das nichts ausmachte.
Manchmal werden auch Dinge in Interruptroutinen verfrachtet, die dort 
nichts zu suchen haben. Muß zum Beispiel die Routine für das Touchpanel 
unbedingt im Interrupt laufen oder werden bloß über AD-Wandler die 
Koordinaten abgefragt und dann berechnet. In dem Fall könnte man 
vielleicht den ADC im 1ms-Interrupt abfragen und die Ergebnisse in den 
Speicher schreiben. Die eigentliche Berechnung der Koordinaten kann dann 
im Hauptprogramm erfolgen. Meiner Meinung nach ist es besser, über ein 
Zählregister kleinere Aufgaben im schnelleren Interrupt mit zu machen 
und dafür eine Interruptquelle weniger zu haben.
Ich programmiere viel in C, aber auf den 8-Bit Controllern bin ich damit 
überhaupt nicht warm geworden. Hier halte ich einen guten Makroassembler 
und ein paar passende Bibliotheken für die bessere Wahl. Ich will damit 
jetzt keinen Glaubenskrieg auslösen wegen Portabilität und so weiter, 
aber bis jetzt ist bei mir eigentlich bei jedem notwendigen 
Systemwechsel (warum auch immer) nur die grundsätzliche Funktionalität 
des Programms geblieben, weil man viele Dinge schon lange anders machen 
wollte...

Gruß Jörg

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Ein Kollege von mir, der den CAN-Bus programmiert, wollte auch gerne
> eine maximale Latenzzeit von 2ms haben.
> Ich wollte aber einen 1-Wire Temperatursensor benutzen, was länger
> gedauert hätte.
> Ich hab ihm dann einfach nen Timerinterrupt geschrieben, der dann
> bitweise das 1-Wire gemacht hat und dann gings wieder.

Es gibt immer eine Möglichkeit etwas in kleine Zeitscheibchen zur 
Ausführung in Hauptschleife/Interrupt zu zerteilen, aber MANCHMAL ist 
der Aufwand einfach größer als wenn man dafür gleich ein RTOS verwendet. 
Wenn man allerdings eine ideologische Abneigung gegen RTOS mit 
Vorurteilen wie "langsam/großer Overhead/Notlösung" hat...

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Andreas Schwarz wrote:

> Es gibt immer eine Möglichkeit etwas in kleine Zeitscheibchen zur
> Ausführung in Hauptschleife/Interrupt zu zerteilen, aber MANCHMAL ist
> der Aufwand einfach größer als wenn man dafür gleich ein RTOS verwendet.
> Wenn man allerdings eine ideologische Abneigung gegen RTOS mit
> Vorurteilen wie "langsam/großer Overhead/Notlösung" hat...

Ich habe leider bisher nirgends ein Beispiel gefunden, woran man die 
Vorteile eine RTOS aufm MC sehen konnte.

Das 1-Wire ist ja gerade nicht für ein RTOS geeignet.

Eine Bitzeit muß ja zwischen 60..120µs lang sein, d.h. man muß 
garantieren, daß eine zusätzliche Verzögerung höchstens 60µs betragen 
darf.

Auf dem 8051 war das ganz einfach, der T0 wurde so eingestellt, daß nach 
60µs der nächste Interrupt auftritt und ihm wurde Priorität 3 
zugewiesen, d.h. er konnte sämtliche anderen Interrupts unterbrechen.
Zusätzliche Latenzen enstehen nur dort, wo atomare Zugriffe auf 
Mehrbytevariablen erfolgen und die sind ja nur wenige µs lang.

Ein RTOS mit nur max 60µs Latenz wäre dagegen auf dem 8051 unmöglich.

Anbei mal der komplette 1-Wire Code.


Peter

von Stefan (Gast)


Lesenswert?

Frage an die RTOS-Experten:
Könnt ihr einige Bücher / Fachartikel (vorzugsweise in deutscher 
Sprache, aber auch gerne in englisch) nennen, in denen die prinzipiellen 
Funktionsweisen eines RTOS und auch die Vorteile/Nachteile der 
verschiedenen Systeme (kooperativ, preemtiv usw.) erläutert werden?
(sowohl für Einsteiger als auch für Fortgeschrittene)
Vielen Dank.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Auf http://www.embedded.com gibt es viele Artikel zu dem Thema.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Z.B. zu den Nachteilen von preemtiven Systemen: 
http://www.embedded.com/showArticle.jhtml?articleID=192701173

von Peter D. (peda)


Lesenswert?

Andreas Schwarz wrote:
> Z.B. zu den Nachteilen von preemtiven Systemen:
> http://www.embedded.com/showArticle.jhtml?articleID=192701173


Da steht leider nichts neues für mich drin.

Hast Du denn keinen Artikel pro RTOS ?


Ich geb natürlich zu, daß ich mit Assembler angefangen hab (8051, AVR).
Dadurch kann ich ziemlich gut einschätzen, wie teuer eine Task ist und 
wo ich sie dann einordnen muß (Interrupt, Mainloop, Scheduler).


Peter

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Erstmal musst du lernen zwischen preemtiven und kooperativen OS zu 
unterscheiden. Das was du von Hand machst ist exakt das was ein 
kooperatives OS macht.

von Peter D. (peda)


Lesenswert?

Andreas Schwarz wrote:

> Das was du von Hand machst ist exakt das was ein
> kooperatives OS macht.


Bloß mit dem großen Unterschied, daß ich genau bestimmen kann, in 
welcher Reihenfolge sie ausgeführt werden.

Nur bei den Tasks, die ich dem Scheduler übergebe, weiß ich die 
Reihenfolge nicht mehr, aber bei denen ist es in der Regel auch nicht 
kritisch.
Und nur diese Tasks haben dann auch den Scheduler-Overhead.


Peter

von Joerg W. (joergwolfram)


Lesenswert?

Vielleicht reden wir auch aneinander vorbei, weil jeder eine andere 
Definition von "OS" hat. Eine Kombination aus Taskmanager, Scheduler 
etc. die ich an meine Tasks anpassen muß, ist für mich kein OS. Beim uC 
wäre das (für mich) ein monolithischer Kernel, dem ich die zu 
bearbeitenden Tasks als Tabelle vorgebe (Einsprungadresse, Intervall, 
Priorität). Die Schnittstellen sind definiert und alle Tasks (auch noch 
zu schreibende ;-) müssen sich daran halten. Der Overhead entsteht bei 
der Prozessumschaltung und im Task selbst, da zumindest beim AVR zur 
Laufzeit nur Resourcen im RAM (über Pointer) zugewiesen werden können.
Richtig preemptives Multitasking geht meiner Meinung nach sowieso nur, 
wenn ein unkooperativer Task es nicht verhindern kann. Wenn aber jeder 
Task einfach die Interrupts abschalten kann, dann wird da wohl eher nix 
daraus. Oder es ist eben doch kein OS (nach meinem Verständnis)

Gruß Jörg

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Joerg Wolfram wrote:
> Vielleicht reden wir auch aneinander vorbei, weil jeder eine andere
> Definition von "OS" hat.

Ein OS ist etwas, das Hardwareressourcen (=Rechenzeit) verwaltet und 
zuteilt.

> Eine Kombination aus Taskmanager, Scheduler
> etc. die ich an meine Tasks anpassen muß, ist für mich kein OS.

Dass man den Scheduler an seine Tasks anpasst wäre so ungefähr Peters 
von-Hand-Modell.

> Richtig preemptives Multitasking geht meiner Meinung nach sowieso nur,
> wenn ein unkooperativer Task es nicht verhindern kann. Wenn aber jeder
> Task einfach die Interrupts abschalten kann, dann wird da wohl eher nix
> daraus.

Anders geht es nicht, oder wie willst du sonst Hardwarezugriffe oder IPC 
realisieren, wenn überall der Scheduler dazwischenfunken kann?

von Joerg W. (joergwolfram)


Lesenswert?

Andreas Schwarz wrote:

> Ein OS ist etwas, das Hardwareressourcen (=Rechenzeit) verwaltet und
> zuteilt.

Zu den Resourcen die verwaltet und verteilt werden müssen, gehören aber 
auch Speicher und Zugriff auf die Peripherie. Bei einem Controller ohne 
umschaltbare Registerbänke kann man den Tasks viele Register zur 
Verfügung stellen, die dann natürlich auch während der Taskumschaltung 
gerettet und restauriert werden müssen (=>braucht Zeit und Speicher). 
Oder man beschränkt sich auf wenige Register und der Task muss häufiger 
auf den Speicher zugreifen.

> Anders geht es nicht, oder wie willst du sonst Hardwarezugriffe oder IPC
> realisieren, wenn überall der Scheduler dazwischenfunken kann?

Für Hardwarezugriffe gibt es OS-Routinen (z.B. BIOS). Und ein Task 
sollte die auch nutzen, anstelle selbst auf die Hardware zuzugreifen.

Ich will auch nicht den Sinn eines OS in Frage stellen, aber um das 
Timing von quasiparallel ablaufenden Funktionen in einem Mikrocontroller 
zu verbessern, halte ich es für eine schlechte Wahl.

Gruß Jörg


von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Joerg Wolfram wrote:
> Andreas Schwarz wrote:
>
>> Ein OS ist etwas, das Hardwareressourcen (=Rechenzeit) verwaltet und
>> zuteilt.
>
> Zu den Resourcen die verwaltet und verteilt werden müssen, gehören aber
> auch Speicher und Zugriff auf die Peripherie.
...
> Für Hardwarezugriffe gibt es OS-Routinen (z.B. BIOS). Und ein Task
> sollte die auch nutzen, anstelle selbst auf die Hardware zuzugreifen.

Die Unterscheidung zwischen Hardwaretreibern und normalen Tasks, wie man 
sie bei größeren Systemen (Linux, Windows) kennt, gibt es bei den 
kleinen Mikrocontroller-OSen nicht. Sie bestehen aus Scheduler, Timer, 
Synchronisationsmechanismen. Es geht nicht darum Hardware zu 
abstrahieren, sondern nur darum Rechenzeit zuzuteilen.

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.