Hallo
Ich wollte mal Allgemein fragen wann sich ein RTOS wirklich lohnt.
Hintergrund ist das ich schon recht lange Mikrokontroller programmiere
und mir meinen parallelen Betrieb sozusagen selber baue indem ich ein
Scheduler zeitlich endsprechende Funktionen ablaufen lassen. Also
ultraeinfach durch zeitliche Interrups oder mitlaufende Handler in der
main. (Spezialbegriffe hierfür sind mir jetzt nicht so geläufig, hab es
mir selber über die Jahre beigebracht.
Bücher wie z.B. "Echtzeitbetriebssysteme-Brinkschulte" haben mein
Interesse geweckt und ich habe hier schon ein paar Beiträge gelesen.
Sofern Programme im Ablauf geschildert wurden habe ich nicht immer den
Sinn in einem Rtos gesehen, benötigt schließlich einiges an Flash und
Ram.
Bitte schildert mir doch mal in ein paar Sätzen wann ihr sagt das man
ein Softwareproblem nur mit RTOS lösen kann bzw. sollte. Auf letzteres
lege ich besonderen Wert da es die Erfahrung zeigt, denke ich.
Ich arbeite mit verschiedenen Schnittstellen wie meistens Can, Uarts,
I2C alles mit Ringpuffer und Protokollen. Flashbedarf ist optimiert ca.
50K bis 70K (da pendeln sich meine Projekte im Moment ein). FreeRtos
steht im Raum, da ich mich freuen wurde alles nicht immer auf einander
abstimmen zu müssen und es danach eben nur statisch läuft. Ebenfalls
würde mich auch eine Art Dateisystem interessieren wo man Files als
Programme ausführen kann, bei SD Karten. Natürlich einfachste Basis,
soll ja mit STM32 laufen.
Dazu bei Interesse mehr.
Zu dem Thema gibts hier im Forum viele und lange Diskussionen, die Suche
zb nach FreeRTOS liefert dir Lesestoff für die ganze Nacht.
Ich spiele auch gerade mit FreeRTOS auf einem lpcxpresso (LPC1769) und
es gefällt mir sehr gut. Vorteile sehe ich in sauberer Aufteilung der
Apps in mehrere Tasks, verschiedene Prios, fertige Queues, ISR Support.
Im Org FreeRTOS Download sind auch viele Beispiele für STM32 drin, damit
kriegt man den Einstieg gut hin.
Flashbedarf ist bei FreeRTOS zb nicht sehr groß, lässt sich auch noch
per defines in einer config Datei durch weglassen nicht benötigter
Features skalieren. RAM Bedarf ist bei OS höher weil jede Task einen
eigenen Stack bekommt. Da muss man natürlich vermeiden große Datenmengen
in Stackvariablen zu packen.
Für nachladbare Apps brauchst du einen Proz mit ext Speicherinterface.
Ich habe vor einen STM32F205 oder 207 zu nehmen, für einen Cortex M3
haben die wohl die meiste Power. Hae mal einen Vergleich gesehen zum
ARM9. Außer der MMU hatte der Cortes mehr Power als ein Arm9 bei 250
Mhz, aber das nur am Rande.
Die haben auch ein Speicherinterface.
>Ich habe vor einen STM32F205 oder 207 zu nehmen, für einen Cortex M3>haben die wohl die meiste Power. Hae mal einen Vergleich gesehen zum>ARM9. Außer der MMU hatte der Cortes mehr Power als ein Arm9 bei 250>Mhz, aber das nur am Rande.
Da musst du dir aber eine mickrigen arm9 angesehen haben (vermutlich den
von ST). in der regel hat ein arm9 code und data cache und damit bringt
der arm9 ca. 200 bis 400 mips. die wirst du mit einem cortex m3/4 nie
erreichen.
gruss
gerhard
Ohh, da habe ich aber einen in seiner Ehre verletzt.
Die Daten stammen aber von "ARM" selber. Wer letztlich wievil Mips hat
sagt ehe nicht so wirklich viel aus und spielt auch für mein Problem
keine Rolle.
>Ohh, da habe ich aber einen in seiner Ehre verletzt.
nein, aber du hast eine aussage getroffen die so nicht stimmt.
>Die Daten stammen aber von "ARM" selber.
welche "daten" sollen das sein?
von welchem arm9 (arm926 oder arm966) sprichst du?
gruss
gerhard
Freddy schrieb:> Ich arbeite mit verschiedenen Schnittstellen wie meistens Can, Uarts,> I2C alles mit Ringpuffer und Protokollen.
Das dürfte alles prima mit Interrupts (Datenverkehr) und Mainloop
(Auswertung) zu lösen sein. Es läuft ja alles schön sequentiell ab. Ein
RTOS kann da nicht richtig punkten.
Peter
Super Grobi schrieb:> Da will ich mich mal an Freddys Frage anhängen: Wo und wann punktet den> nun ein RTOS?
Der übliche Ansatz ist es auf ein RTOS zu verzichten und alles mit einer
Hauptschleifen, Koroutinen und Interrupts zu erledigen. Das läuft dann
meist auf so etwas wie ein kooperatives Roundrobin-Scheduling hinaus.
Jedenfalls für die Koroutinen. Wenn man aber viel zu viele Aufgaben zu
erledigen hat, die auch noch unterschiedlich priorisiet ablaufen müssen,
dann läuft das mit dem Ansatz nicht mehr so ohne Weiteres. An dieser
Stelle ist es dann IMHO sinnvoll ein RTOS einzusetzen.
Gruß Oliver
> Da will ich mich mal an Freddys Frage anhängen: Wo und wann punktet den> nun ein RTOS?
Das Ganze ist ein gleitender Uebergang.
Man beginnt bei einer Mainloop mit einer odere mehreren
Zusatndsmaschinen drin. So kann man gut verschiedene Timings von
verschiedenen unabhaengigen Prozessen abbilden. Irgendwo haben diese
Prozesse vielleicht eine Abhaengigkeit. Mit zunehmender abhaengigkeit
dieser Prozesse muessen mehr Daten ausgetauscht werden. Dann wird die
Zustandsmaschine unuebersichtlich.
Das Wichtigste dabei : Es wird nirgendwo ausser an einem Ort im Main
gewartet. Keine Delays, nichts dergleichen.
Das naechste ist ein Realtime Kernel. Eine zulinkbare Library, die einen
Scheduler, Tasks/Prozesse und pro Task/ Prozess unabhaengigen Stack zur
Verfuegung stellt. Sowie alles was zur Intertask kommunikation noetig
ist. Das waeren dann Events, Semaphore, Mailboxen, Queues. Es gibt dann
zwei Ausfuehrungen. Einen kooperativen Scheduler und einen praeemptiven
Scheduler. Der Erste, schaltet die Tasks/Prozesse um wenn die auf ein
Wait laufen. Das bedeutet die Tasks muessen so geschrieben sein, dass
sie hinreichend oft die Rechenzeit abgeben. Ein Task/Prozess laeuft
solange wie er auf ein Wait laeuft. Der zweite Scheduler, der
Praeemptive unterbricht zusaetzlich die Task/Prozesse noch zu
festgelegten Zeitscheiben. Wenn man definierte, harte Antwortzeiten des
Systems haben muss ist ein praeemptiver Scheduler einfacher. Dafuer muss
man mit den Variablen besser aufpassen, das die ja zwischendurch
veraendert werden koennen. Das kann man dem System ueberlassen und sie
mit Semaphoren schuetzen, was das System langsamer macht. Ein
kooperatives System ist daher schneller.
Interrupts haben gegenueber allem natuerlich Prioritaet. Ein Interrupt
loest ueblicherweise (irgendwann) einen Event aus. Man kann zB ein UART
bei jedem Byte einen Event ausloesen lassen, oder nach empfangener
Nachricht. Der EmpfangsTask/Prozess, wartet auf diesen Event.
Ein Programm mit einem zugelinkten Realtime Kernel besteht also aus
mehreren Prozeduren, die jeweils einen eigenen Stack haben. Erst werden
diese Task oder Prozess genannten Prozeduren initialisiert, und laufen
dann los. Das gesammte Programm laeuft nie auf ein End-statement, ist
eine While(Forever) Schleife.
Der Vorteil gegenueber der Zustandsmaschine ist eine erhoehter
Uebersichtlichkeit Ein Task ist viel leichter lesbar wie eine komplexe
Zustandsmaschine. Der Preis ist der Realtime Kernel.
Ein RTOS ist ein Realtime Kernel plus Betriebssystem Funktionalitaet.
Man kann also Programme laden, was ein Realtime Kernel nicht macht.
Super Grobi schrieb:> Da will ich mich mal an Freddys Frage anhängen: Wo und wann punktet den> nun ein RTOS?
Ein normaler Scheduler entspricht im Verhalten grob einem RTOS mit
cooperative scheduling. Die Latenzen von Code, der nicht direkt in der
ISR sitzt, sind abhängig von der Laufzeit der vom Scheduler aufgerufenen
Aktionen, da die im Gänsemarsch ablaufen. Ein RTOS mit preemptive
scheduling kann jedoch als Reaktion auf einen Interrupt höher
priorisierte Aktionen sofort anstossen, indem der laufende Code
zeitweise verdrängt wird. Generell wird Priorisierung von Aktivitäten
besser abgebildet.
Ein RTOS / Realtime Kernel bietet meist auch Mechanismen für sowas wie
Queuing von Daten und/oder Messages, für die Kommunikation der
verschiedenen Abläufe (Threads) untereinander.
Ein weiterer deutlicher Unterschied liegt in der Übersichtlichkeit des
Ablaufs. In einem RTOS ist ein Ablauf mit diversen Wartepunkten
zwischendrin ein sequentieller Ablauf im Quellcode. Mit einer
State-Machine ist das ein im Quellcode unzusammenhängendes Sammelsurium
von Codestückchen.
>Ein weiterer deutlicher Unterschied liegt in der Übersichtlichkeit des>Ablaufs. In einem RTOS ist ein Ablauf mit diversen Wartepunkten>zwischendrin ein sequentieller Ablauf im Quellcode. Mit einer>State-Machine ist das ein im Quellcode unzusammenhängendes Sammelsurium>von Codestückchen.
Das verstehe ich jetzt nicht.
Wenn in meiner main() die einzelnen Funktionen nacheinander aufgerufen
werden wenn ein Flag in der ISR gesetzt wurde (z.B. Flag.Taste1 oder
Flag.DatenEmpfangen) habe ich keine Priorisierung weil wie Du schriebst
alles im Gänsemarsch abläuft, aber die einzelnen Funktionen sind IMHO
nicht unübersichtlicher als bei einem RTOS mit diversen Tasks die
jeweils eine eigene "while(1)" enthalten.
Das Problem der Unübersichtlichkeit der gemeinsamen Datenbasis (aka
Variablen) die von mehreren Funktionen oder Tasks benötigt werden bleibt
bei beiden Ansätzen gleich, oder irre ich da?
Super Grobi schrieb:> Das verstehe ich jetzt nicht.
RTOS Quellcode:
Startup
Aktion 1
while irgendwas
Aktion 2
Abschluss
=> Der Ablauf steht direkt im Quellcode.
Scheduler / State Machine Quellcode:
Init: Status = 1
wenn Status = 3, dann Funktion 3:
Aktion 2
if irgendwas
then Status = 3
else Status = 4
wenn Status = 1, dann Funktion 1:
Startup
Status = 2
wenn Status = 2, dann Funktion 2:
Aktion 1
Status = 3
...
=> Den realen Ablauf muss man sich aus der Abfolge der Stati mühsam
zusammenklamüsern. Wenn hinreichend komplex und nicht gut dokumentiert,
dann sitzt man eine Weile mit Bleistift und Papier da und verbindet
Kreise.
> Das Problem der Unübersichtlichkeit der gemeinsamen Datenbasis (aka> Variablen) die von mehreren Funktionen oder Tasks benötigt werden bleibt> bei beiden Ansätzen gleich, oder irre ich da?Wenn du dafür globale Variablen verwendest. Im Idealfalls sind Threads
hinsichtlich der Daten abgeschlossen und korrespondieren über RTOS
Mechanismen wie Queues, Mailboxes, Monitore, Rendevous etc.
Wenn ich das richtig sehe habe ich dann sowas wie ein Rtos längst mit
eigenen Mitteln gebaut. Gut werschiedene Tasks sind noch etwas anderes,
aber mit threads ist es wohl vergleichbar.
Meine üblichen Systeme:
Schnittstellen sind Interrupt oder DMA gesteuert und regieren auf jede
bzw. je nach Hardwarebuffer schnell genug auf ankommende Messages ->
Echtzeit.
Die Nachrichten werden in einen Software Ringpuffer gelegt der je nach
Auslastung entsprechende Strukturen in einem Array besitzt.
In der Main(loop) habe ich dann die Protokollverwaltung. Ich nenne sie
Handler. Die Funktionen werden zwar alle angesprungen aber die erste
Abfrage nennt sich in der Regel: Wenn Ringpuffer neue Daten hat,
zuordnen, und Anweisungen starten.
Bei schnellen Befehlen (Auf Frage gibt es eine direkte Antwort) werden
wiederum Antwort Ringpuffer bedient.
Langsame Befehle (Befehle die zunächst weitere Aktionen erfordern,
werden vorsortiert (z.B. Anlalogwandlung wird gestartet, aber auf deren
Ende wird hier nicht gewartet))
Der Sinn liegt im wesendlichen darin, das so nahezu der gesamte
Ringpuffer abgearbeitet werden kann in einer mainloop. Dieser kann aber
trotzdem bei ankommenden Nachrichtenwieder aufgefüllt werden. Haben alle
Schnittstellen Nachrichten kann man aber schonmal ins Schleudern kommen
wer jetzt wichtiger ist. Wenn ich Pech habe kann eine mainloop schon
sehr lange dauern, ist in der Regel aber nie zeitlich definierbar.
Dieses Verfahren setze ich so ein und bin in Sachen Multitasking
eigentlich zufrieden. Allerdinks ist es doch manchmal schwierig die
Dynamik von diesem System noch in Echtzeit zu beurteilen. Da ja alle
Schnittstellen befeuert werden (Wir arbeiten immer in
Multiprozessorkommunikation). Beim Hardwaretrace stellt man eben fest
das so manche Protokollbehandlung lieber etwas warten könnte, damit
nichts verloren geht. Aber die Ringpuffer zu erhöhen stößt nicht immer
auf Gegenliebe.
Daher meine Frage ob man "mein" Verfahren besser Koordinieren kann mit
einem Rtos. Wenn ein Betriebssystem auch laufende Funktionen oder da
eben Tasks unterbrechen kann ist das teilweise hilfreich.
Ich hoffe das jetzt einigermaßen verständlich erklärt zu haben, sorry
für die vielen Worte.
Nein, Du hast eben kein RTOS, auch keinen Realtime Kernel. Du hast eine
Zustandsmaschine. Und die werden eben etwas unuebersichtlich.
Ein Realtime Kernel saugt auch etwas an Resourcen ab, das sollte man
nicht vergessen. Resourcen an RAM, an Code und an Rechenzeit.
Wenn's denn so einen Realtime Kernel zum Controller und Compiler passend
gibt waere das eine Option, die man anschauen sollte. Die
Einarbeitungszeit kann schon einen Monat betragen. DasDebuggen ist auch
etwas Anderes, denn man gibt die definierte Reihenfolge, die man sich
gewohnt ist auf. Die Task laufen wenn sie laufen, manchmal laufen sie
eben nicht.
Falls du bei der Zustandsmaschine bleiben willst, zumindest kurzfristig:
Wenn der Mainloop teilweise unueberschaubar lange dauert, muss man die
Funktionalitaet eben zerscheibeln. Man muss ja nicht ein Longword-to-BCD
in einem Durchgang rechnen, speziell weil das meist mit Ein-/Ausgabe
zusammenhaengt, sondern kann das auf eine Ziffer pro Durchgang
zerhacken. Ein LCD wird auch nicht in einem Durchgang beschrieben,
sondern nur mit einem Character pro Durchgang.
Dadurch wird die Zustandsmaschine nochmals etwas komplizierter.
Delta Oschi schrieb:> Wenn's denn so einen Realtime Kernel zum Controller und Compiler passend> gibt waere das eine Option, die man anschauen sollte.
Wobei man der Cortex-M Architektur in Form des NVIC ansieht, dass sich
ARM über das Thema RTOS / Realtime-Kernel Gedanken gemacht hat. Das
integriert sich recht gut, besser als bei den älteren ARM Architekturen.
Die saubere Prioritätskontrolle erlaubt hohe verzögerungsarme
Prioritäten für ISRs ohne Nutzung des Kernels, was bei den älteren ARMs
abgesehen vom FIQ oft problematisch ist. Und es gibt einen eigenen Hook
für einen Task Switch als Resultat von Aktivitäten in möglicherweise
verschachtelten ISRs, was den Overhead der ISRs reduziert.