Gibt es beim FreeRtos auf dem stm32 die Möglichkeit einen Task zu
starten, nur einmal auszuführen und diesen wieder zu stoppen?
Jeder Task hat da irgendwie eine for(;;) (Endlosschleife) drin, was ja
bedeuten würde, dass dieser eigentlich immer läuft, auch wenn dieser
nicht benötigt wird.
Oder verstehe ich etwas falsch?
Ich möchte lediglich einen Befehl einmal ausführen.
Geht das denn irgendwie?
Gehen tut das natürlich schon, wobei ich behaupten würde, dass das für
ein Embedded-System eher untypisch ist - hier hat man eher
wiederkehrende Aufgaben (was nicht heißen soll, dass es nicht vorkommen
kann).
Es gibt ja auch Alternativen dazu hierfür eine Task anzulegen und direkt
wieder zu beenden (es gibt nämlich durchaus auch einige RTOS die kein
Anlegen von Task zur Laufzeit erlauben).
Bernie schrieb:> Oder verstehe ich etwas falsch?> Ich möchte lediglich einen Befehl einmal ausführen.
Aus Interesse: Was möchtest du denn genau ein mal machen?
Danke euch
Ich möchte das einfach nur testen und mich da mal einarbeiten.
Ich hätte jetzt einfach mal nur mal eine Led im Task eingeschaltet, um
zu sehen, ob das so funktioniert wie ich das möchte.
Wo gibt es denn eine Art Anleitung wo das ein Bisschen beschreibt? Im
Reference Manual oder dem Datenblatt finde ich das ja nicht.
Ich weiss so ja auch nicht, welche Befehle es wie zB xTaskDelete() gibt?
Wo steht denn das alles?
Bernie schrieb:> Wo gibt es denn eine Art Anleitung wo das ein Bisschen beschreibt? Im> Reference Manual oder dem Datenblatt finde ich das ja nicht.
Das mit dem Task nur einmal ausführen? Gute Frage... die Beispiele
werden wie von dir schon gesagt fast alle eine Endlos-Loop nutzen, da
das wie gesagt deutlich gebräuchlicher ist.
Bernie schrieb:> Ich weiss so ja auch nicht, welche Befehle es wie zB xTaskDelete() gibt?> Wo steht denn das alles?
Sowas findest du in der API reference
[http://www.freertos.org/a00106.html].
Bernie schrieb:> Ich möchte das einfach nur testen und mich da mal einarbeiten.> Ich hätte jetzt einfach mal nur mal eine Led im Task eingeschaltet, um> zu sehen, ob das so funktioniert wie ich das möchte.
Gehen wird das natürlich schon :)
Wie gesagt wird man aber in der Realität kaum Aufgaben haben die
wirklich nur ein einziges mal laufen (irgendwann wird man die LED z.B.
auch wieder abschalten wollen).
Die LED-Task könnte dann z.B. auf eine Semaphore warten, so lange bis
wieder ein Zustandswechsel ansteht.
ok, andersrum gefragt:
Was ist wenn zB eine Anweisung in einem Interrupt durchgeführt wird und
die Anweisungen aber nacheinander zu lange benötigen würden. Ich meine
also, der nächste Interruptaufruf steht schon vor der Tür, bevor dieser
im vorigen Schritt fertig war. Das geht dann immer weiter so bis zu
einem Absturz.
Das sind dann auch Anweisungen, die nicht immer durchgeführt werden
müssen.
Da ist doch so ein Task genau das was man brauchen kann. Einmal starten
und fertig. Dann kann der Interrupt sogar mehrmals kommen und man müsste
ja mit einer globalen Variable nur immer abfragen, ob der Task fertig
ist oder nicht.. super
Aber mit einer Endlosschleife??
Wie macht man es dann?
Das wäre mal sicher ein Fall, der nicht immer durchgeführt werden muss.
Hallo,
kommt etwas drauf an, um was für einen Interrupt es sich handelt und
welche Informationen du haben möchtest.
Für die viele Interrupts kann man z.B. ne Queue verwenden (
http://www.freertos.org/a00018.html ) um Daten zwischen Interrupt und
einem Thread hin und her zu schaufeln. Für ein Beispiel schau mal
http://www.freertos.org/a00118.html .
Als Beispiel evt. UART: Der UART-RX Interrupt wird aufgerufen. Das
empfangene Byte wird in die Queue geschrieben. Das kann eventuell öfter
hintereinander passieren. Irgendwann kommt dann der Lesethread dazu die
Daten aus der Queue wieder auszulesen und weiter zu verarbeiten.
Wenn du nur einen Thread informieren möchtest, dass ein Interrupt
stattgefunden hat (z.B. GPIO Interrupt wird durch einen Tastendruck
ausgelöst) kannst du einen Binary Semaphore verwenden:
http://www.freertos.org/a00113.html
Gruss,
Jay
Bernie schrieb:> Aber mit einer Endlosschleife??> Wie macht man es dann?
Du solltest dich mal in die Mittel zur Task-Synchronisation und
-Kommunikation einlesen (Semaphoren, Mutexe, Events, Queues/Mailboxes).
Alle deine Beispiele werden dadurch eigentlich abgedeckt.
Das Prinzip ist immer ählich. Die "Endlosschleife" wartet am
Schleifenbeginn auf ein Signal. So lange ist der Thread blockiert und
wird nicht ge-scheduled (erzeugt also keine CPU-Last).
Sobald das Signal kommt läuft die Schleife ein mal durch und wartet dann
wieder am Schleifenanfang. Es ist also keine "echte" Schleife im Sinne
davon, dass sie dauernd im Ring läuft.
Pseudocode:
1
voidTaskLoop()
2
{
3
for(;;)
4
{
5
waitForSignal();// this blocks the task
6
7
DoSomething();
8
}
9
}
10
11
voidIrqHandler()
12
{
13
sendSignal();// tell the task to run one loop cycle
14
}
So kann der Interrupt auch "mehrmals" bzw "zu oft" kommen. So lange das
"DoSomething" noch durchläuft passiert eben nix.
Bernie schrieb:> Das wäre mal sicher ein Fall, der nicht immer durchgeführt werden muss
Mag sein. Trotzdem kommen die Anweisungen zyklisch und immer wieder.
Hier jedes mal einen neuen Task zu erzeugen generiert einen riesen
Overhead.
moep schrieb:> Bernie schrieb:> Aber mit einer Endlosschleife??> Wie macht man es dann?>> Du solltest dich mal in die Mittel zur Task-Synchronisation und> -Kommunikation einlesen (Semaphoren, Mutexe, Events, Queues/Mailboxes).> Alle deine Beispiele werden dadurch eigentlich
Danke vielmals
Kennt da jemand eine zusammenfassende Seite, eine empfehlenswerte.
Einfach mal auf die freertos Website die API Referenz anschauen. Die ist
sehr überschaubar und sind immer Beispiele mit dabei.
Beim stm-port musst nur aufpassen mit den prios und timeouts.
moep schrieb:> Hier jedes mal einen neuen Task zu erzeugen generiert einen riesen> Overhead.
Nicht nur das. Es wird auch jedes Mal der Stack für den Task neu
alloziert und wieder beim Löschen freigegeben. Dadurch kann zur Laufzeit
eine Fragmentierung des RAM entstehen und man bekommt evtl irgendwann
keinen Speicher mehr.
Auf Embedded Systemen ist man gut beraten ein möglichst statisches
Memorymap im RAM zu haben. Z.b. beim Start alles allozieren was man
braucht und dann bleibt das so. Am besten auf dynamische
Speicherverwaltung verzichten.
Fehler, die irgendwann nach Wochen zur Laufzeit auftreten sind übel zu
debuggen.
Moin,
guest schrieb:> Nicht nur das. Es wird auch jedes Mal der Stack für den Task neu> alloziert und wieder beim Löschen freigegeben.
Ist das bei freertos wirklich so?
Das freertos kenne ich bisher nicht, aber das waere ja (aus meiner
nicht objektiven Sicht) ein KO Kriterium.
Bisher kannte ich das immer so, das (fuer embedded) alle task fest
konfiguriert sind. Natuerlich kann man die nach belieben starten,
terminieren und neu starten. Aber da ist nix mit dynamischer
Speicherverwaltung. Alles ist statisch allokiert.
Ist das bei freertos generell anders, oder ist das nur eine
Konfigurationsmoeglichkeit unter anderen?
MfG,
Darth
Darth Moan schrieb:> Moin,>> guest schrieb:>> Nicht nur das. Es wird auch jedes Mal der Stack für den Task neu>> alloziert und wieder beim Löschen freigegeben.>
Ab FreeRTOS 9 kann man Speicher für Objekte (z.B. Stack) präalloziiert
übergeben (sh. http://www.freertos.org/xTaskCreateStatic.html). Default
ist dass FreeRTOS es für einen tut.
Darth Moan schrieb:> Ist das bei freertos wirklich so?
Das ist sicherlich bei jedem System so, das dynamisch zur Laufzeit Tasks
neu anlegen und wieder löschen kann. Wenn die Task selbst ein dynamisch
erzeugtes Objekt ist, wie kann da der Stack dazu statisch sein?
Daß man es bei einem mickrigen µC damit nicht allzusehr übertreiben
sollte, sollte allerdings auch klar sein.
Da ist es sicher besser (wie ja schon geschrieben wurde), die Tasks beim
Programmstart fest an und (wenn man sie gerade nicht braucht)
zwischendurch schlafen zu legen.
Moin,
Markus F. schrieb:> Das ist sicherlich bei jedem System so, das dynamisch zur Laufzeit Tasks> neu anlegen und wieder löschen kann. Wenn die Task selbst ein dynamisch> erzeugtes Objekt ist, wie kann da der Stack dazu statisch sein?
Naja, wie ich schon schrieb, wird die Task Konfiguration als const
Datenstruktur gelinkt. Die Task IDs sind somit feste IDs, die ggf. in
entsprechenden header Files exportiert werden. Das heisst, man kann
dann eben nicht beliebeige Tasks selbst mit zur Laufzeit ermittelten
StartAdressen erzeugen. Das braucht man ja embedded eigentlich auch
nicht.
Ich kann mich nicht mehr an alle OS erinnern, aber Nucleus und
jetzt OSEK sind komplett statisch konfiguriert. Trotzdem kann man die
Tasks beliebig starten und terminieren. Wie es eben gebtraucht wird.
Alle ASIL belasteten Task muessen genau so aufgezogen sein (also sie
muessen sich nach einem Durchlauf selbst terminieren). Da wird zB im
1ms, 10ms, 100ms der zugehoerige Task neu gestartet. Sollte er
allerdings vom letzten Start noch nicht fertig geworden sein, gibts
eine doppelte Task Aktivierung.
Schwerer Fehler -> Sicherer Zustand.