Forum: Mikrocontroller und Digitale Elektronik FreeRTOS, synchronisation über Variable?


von Holger K. (holgerkraehe)


Lesenswert?

Hallo zusammen

ich stehe vor folgendem Problem:
Ich habe hier ein FreeRTOS am laufen mit 3 Tasks.

1
functionA
2
{
3
  Prüfe Ob Buffer zum Schreiben auf SD voll ist. 
4
  Wenn Ja, StopRequest = 1;
5
}
6
7
8
TaskA 
9
{
10
11
  warteBisDatenIn QueueA
12
  {
13
     Verarbeite Daten. 
14
     Gib ID aus QueueA in QueueB ein. 
15
     
16
     if(StopRequest && QueueA leer)
17
     {
18
        give(SemaphoreWriteSD);
19
     }
20
  }
21
}
22
23
TaskB
24
{
25
26
  if(StopRequest == 0)
27
  {
28
    warteBisDatenIn QueueB
29
    {
30
       FunctionA()
31
       Verarbeite Daten.
32
       Gibt ID von QueueB zurück in QueueA
33
    }
34
  }
35
}
36
37
38
TaskC
39
{
40
   TakeSemaphore(SemaphoreWriteSD);
41
   {
42
      Schreibe auf SD....
43
      StopRequest = 0;
44
   }
45
}


Nun, wie ihr seht, koordiniere ich die Tasks mit einer externen 
variabel.
Diese habe ich als
1
 uint8_t StopRequest
 definiert.

Unklücklicherweise, tritt nach ca. 2-3 Stunden (kein exakter Zeitpunkt) 
der Fall ein, dass die Variabel stehts auf 1 ist, der TaskC welcher nach 
dem Schreiben die Variabel auf 0 setzen würde, aber nie augerufen wird.

Da sich alle Programmzustände nach ca. 30 Sekunden wiederholen, gehe ich 
hier von einer Eigenheit des Schedulers aus.

Deshalb die Frage an euch, darf man überhaupt, so wie hier versucht, 
Tasks synchronisieren? Müsste die Variable als volatile definiert 
werden?

Ich habe keine Semaphoren verwendet, weil ich nicht wirklich sehe, wie 
sich dies mit diesen elegant lösen liesse.

Hoffe auf eure Inputs.

Danke

: Bearbeitet durch User
von Stefan K. (stefan64)


Lesenswert?

Und wann und wo wird functionA aufgerufen?

Gruß, Stefan

von Einer K. (Gast)


Lesenswert?

Holger K. schrieb:
> Müsste die Variable als volatile definiert
> werden?

Preemptives Multitasking?
Dann garantiert: Ja!

von Holger K. (holgerkraehe)


Lesenswert?

Stefan K. schrieb:
> Und wann und wo wird functionA aufgerufen?
>
> Gruß, Stefan

Sorry, habs ergänzt.

Arduino F. schrieb:
> Holger K. schrieb:
>> Müsste die Variable als volatile definiert
>> werden?
>
> Preemptives Multitasking?
> Dann garantiert: Ja!

#define configUSE_PREEMPTION 1

Dann lags wohl an dem!


Aber noch kurz zur Grundsatzfrage.
Ist es legitim solche dinge über eine Variable zu steuern, oder sollte 
man strikt Semaphoren verwenden?

: Bearbeitet durch User
von Ruediger A. (Firma: keine) (rac)


Lesenswert?

volatile hilft Dir in diesem Fall NICHT! Wenn die Zuweisung

StopRequest = 1

nicht atomar übersetzt werden kann, sind beim preemptiven Multitasking 
immer Szenarien (race Konditionen) denkbar, in denen die Variable nicht 
den Wert der gedachten logischen Folge hat. volatile Deklaration 
garantiert keinen atomischen Zugriff!

Prinzipiell ist das Vorgehen aber legitim. Du kannst alle Zugriffe auf 
die Variable unter Mutexkontrolle vornehmen, oder aber je nach 
verwendetem Prozessor atomare Operationen nutzen (beim Cortex gibt's 
z.B. den exclusive access monitor, der über die Maschinenbefehle ldrex 
und strex arbeitet).

In meinem Buch diskutiere ich die Problematik ausführlich in Kapitel 6. 
Ich weiss, es fängt mir selber an, auf den Senkel zu gehen, wiederholt 
auf mein eigenes Buch zu verweisen, aber die Problematik ist recht 
weitreichend, so dass eine vollständige Diskussion hier den Rahmen 
sprengen würde.

von Holger Kraehe (Gast)


Lesenswert?

Ruediger A. schrieb:
> nicht atomar übersetzt werden kann, sind beim preemptiven Multitasking
> immer Szenarien (race Konditionen) denkbar, in denen die Variable nicht
> den Wert der gedachten logischen Folge hat. volatile Deklaration
> garantiert keinen atomischen Zugriff!

Hat auch tatsächlich nicht funktioniert.


Ruediger A. schrieb:
> In meinem Buch diskutiere ich die Problematik ausführlich in Kapitel 6.
> Ich weiss, es fängt mir selber an, auf den Senkel zu gehen, wiederholt
> auf mein eigenes Buch zu verweisen, aber die Problematik ist recht
> weitreichend, so dass eine vollständige Diskussion hier den Rahmen
> sprengen würde.

Das stimmt wohl.
Ich verwende einen Cortex M3.

Da du der Community ja nahe bist, und ich das Problem möglichst Zeitnah 
lösen sollte, wärst du eventuell so freundlich und würdest mir einen 
Tipp geben, wie ich dies in diesem Fall lösen könnte?

Soll ich für den Zugriff auf die Variabel einen Mutex erstellen?

Danke und Gruss

von Peter II (Gast)


Lesenswert?

Ruediger A. schrieb:
> StopRequest = 1
>
> nicht atomar übersetzt werden kann, sind beim preemptiven Multitasking
> immer Szenarien (race Konditionen) denkbar, in denen die Variable nicht
> den Wert der gedachten logischen Folge hat. volatile Deklaration
> garantiert keinen atomischen Zugriff!

kannst du das bitte etwas genauer erklären?

Wie kann eine 8bit Variable nicht atomar beschrieben werden? Es geht mir 
nur ums setzen der Variabel nicht um abfrage und dann setzen.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Holger Kraehe schrieb:
>
> Da du der Community ja nahe bist, und ich das Problem möglichst Zeitnah
> lösen sollte, wärst du eventuell so freundlich und würdest mir einen
> Tipp geben, wie ich dies in diesem Fall lösen könnte?
>

Sieh Dir mal diesen Funktionssatz an:

http://gcc.gnu.org/onlinedocs/gcc-4.4.5/gcc/Atomic-Builtins.html

der übersetzt plattformspezifisch atomisch.

> Soll ich für den Zugriff auf die Variabel einen Mutex erstellen?
>

wie gesagt ist das eine Alternative für den Fall, dass die 
Nichtatomarität das Problem ist. "Soll" ist eine etwas ungünstige 
Formulierung. Du MUSST etwas tun, was das Problem löst, und die 
Entscheidung, was das ist, liegt bei Dir. Wenn Du etwas tun SOLLST, dann 
deswegen, weil Dir ein Vorgesetzter das sagt. Da ich in deinem Projekt 
in keinster Form involviert bin, kann ich Dir nicht sagen, was Du tun 
sollst, ich kann nur versuchen, Dir Hilfestellung bei der Entscheidung 
zu geben, was Du tun MUSST (wobei die Entscheidung am Ende des Tages bei 
Dir liegt, was auch voraussetzt, dass Du nach Bestem Wissen und Gewissen 
sagen kannst, dass Du WEISST, wo das Problem ist).

Dein Ansatz ist falsch; eine schnelle Lösung (also eine Lösung die so 
aussieht also ob sie funzt) ist bei der Nebenläufigkeit selten eine 
funktionierende Lösung. Vielleicht verzögert eine schnelle, auf den 
ersten Blick funktionierende Lösung das Fehlerbild nur so, dass der 
Fehler statt also 20 Minuten nur noch alle 14 Tage auftritt, d.h. nach 
Bestehen der internen Tests und Rollout im Feld. Einfach nur zu sagen 
"jetzt ist es eine halbe Stunde nicht mehr aufgetreten, also Problem 
gelöst" hat so manche Firma in die Pleite getrieben. Bei Fehlern in 
nebenläufigen Architekturen muss man sich schon mit spiztem Bleistift 
und viel Papier hinsetzen und alle möglichen Raceszenarien trocken 
durchspielen, bis man sich sicher ist, dass man weiss warum. DIE Arbeit 
wird sich hier auf dem Forum sicherlich Niemand für Dich machen.

: Bearbeitet durch User
von Stefan K. (stefan64)


Lesenswert?

Ich nehme mal an, in den Tasks gibt es noch while(1) Schleifen?
Wie ist die Priorität der Tasks?
1
TaskB
2
{
3
  while (1)
4
  {
5
    if(StopRequest == 0)
6
    {
7
      warteBisDatenIn QueueB
8
      {
9
         FunctionA()       // setzt ggf. SopRequest auf 1
10
         Verarbeite Daten.
11
         Gibt ID von QueueB zurück in QueueA
12
      }
13
    }
14
  }
15
}

Falls TaskB eine höhere Priorität als TaskA hat, kann TasksB hier in 
einer Endlosschleife laufen, wenn (StopRequest == 1).

Gruß, Stefan

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Peter II schrieb:
> Ruediger A. schrieb:
>> StopRequest = 1
>>
>> nicht atomar übersetzt werden kann, sind beim preemptiven Multitasking
>> immer Szenarien (race Konditionen) denkbar, in denen die Variable nicht
>> den Wert der gedachten logischen Folge hat. volatile Deklaration
>> garantiert keinen atomischen Zugriff!
>
> kannst du das bitte etwas genauer erklären?
>
> Wie kann eine 8bit Variable nicht atomar beschrieben werden? Es geht mir
> nur ums setzen der Variabel nicht um abfrage und dann setzen.

Hallo Peter,

Cortex Prozessoren arbeiten grundsätzlich im Load-and-Store Modus (ich 
bin mir sicher, dass Du das weisst), also ist das Setzen einer Variable 
egal welcher Grösse grundsätzlich eine mindestens zwei Instruktionen 
umfassende (also nicht atomische und damit unterbrechbare) Operation. 
Der EAM umschifft dieses Problem, muss aber halt explizit genutzt 
werden.

Ich stimme mit deinem Punkt überein, dass die Atomizität in dem Fall, 
dass kein Set-und-Test involviert ist, vermutlich keine Rolle spielen 
sollte; ich habe nur grundsätzlich auf die Frage geantwortet, wo es 
Probleme mit der Synchronisation über globale Variablen geben kann (und 
den Irrweg mit der volatile Annahme aufgegriffen).

Möglicherweise ist eine andere Racekondition Schuld an der Inkonsistenz 
als die einer unterbrochenen Zuweisung; wie ich schon vorher schrieb, 
muss man dafür die möglichen Kontrollpfade sehr genau analysieren. DIE 
Arbeit kann einem Niemand abnehmen.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Stefan K. schrieb:
> Ich nehme mal an, in den Tasks gibt es noch while(1) Schleifen?
> Wie ist die Priorität der Tasks?
>
> ...
>
> Falls TaskB eine höhere Priorität als TaskA hat, kann TasksB hier in
> einer Endlosschleife laufen, wenn (StopRequest == 1).
>
> Gruß, Stefan

Sehr guter Punkt; hier könnte man ein vTaskDelayUntil() andenken, um 
sicherzustellen, dass die Anderen Tasks eine Chance bekommen. 
Interessanterweise könnte eine Mutexlösung hier durch die Priority 
Inversion Policy das Problem lösen, aber aus Anderen Gründen als man 
denkt. Deswegen ist nebenläufige Programmierung niemals durch 
trial-and-error richtig zu bewältigen.

von Holger Kraehe (Gast)


Lesenswert?

Bei mir haben alle Tasks die selben prioritäten.

Ich habe nun folgendes implementiert:

An allen stellen, wo ich auf die Variable zugreife.
1
xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
2
  stopProcess = 1;
3
xSemaphoreGive(xStopProcessMutex);



Leider hat sich das System erneut aufgehängt.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Holger Kraehe schrieb:
> Bei mir haben alle Tasks die selben prioritäten.
>
> Ich habe nun folgendes implementiert:
>
> An allen stellen, wo ich auf die Variable zugreife.
>
1
> xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
2
>   stopProcess = 1;
3
> xSemaphoreGive(xStopProcessMutex);
4
>
>
>
>
> Leider hat sich das System erneut aufgehängt.

Installiere mal den tracealyzer von percepio, der integriert sehr gut 
mit FreeRTOS. Du wirst offensichtlich nicht drumrumkommen zu verstehen, 
wie dein System als Ganzes funktioniert, und dabei hilft die 
Visualisierung enorm.

von Holger Kraehe (Gast)


Lesenswert?

Ruediger A. schrieb:
> Installiere mal den tracealyzer von percepio, der integriert sehr gut
> mit FreeRTOS. Du wirst offensichtlich nicht drumrumkommen zu verstehen,
> wie dein System als Ganzes funktioniert, und dabei hilft die
> Visualisierung enorm.

funktioniert der auch in Atollic?

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

funktioniert komplett unabhängig von der Entwicklungsumgebung.

von Karl (Gast)


Lesenswert?

Tracealyzer von Percepio ist eigentlich nicht mehr zu empfehlen. Es gibt 
da eine bessere Variante von SEGGER. Nennt sich SystemView: 
https://www.segger.com/systemview.html

FreeRTOS wird auch unterstützt und die große Vorteil gegenüber Percepio 
ist das es völlig kostenlos ist!!

Ansonsten überlege dir doch mal anstatt FreeRTOS ein kommerzielles RTOS 
einzusetzen, z.B. embOS von SEGGER. Dann bekommst du direkt Support und 
Training vom Hersteller und bist nicht hier auf das Forum angewiesen. Im 
Endeffekt sparst du damit Zeit und Geld.

von Holger Kraehe (Gast)


Lesenswert?

Karl schrieb:
> Tracealyzer von Percepio ist eigentlich nicht mehr zu empfehlen. Es gibt
> da eine bessere Variante von SEGGER. Nennt sich SystemView:
> https://www.segger.com/systemview.html

Was genau benötige ich, um den Tracealyzer zum laufen zu bekommen?

Genügt eine SWD Verbindung zum Controller?
Ich vermute dass ich dafür einen Segger J-Link benötige?

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Karl schrieb:
> Tracealyzer von Percepio ist eigentlich nicht mehr zu empfehlen.

? Warum nicht und speziell warum nicht MEHR?

> Es gibt
> da eine bessere Variante von SEGGER. Nennt sich SystemView:
> https://www.segger.com/systemview.html
>

Was ist daran besser?

> FreeRTOS wird auch unterstützt und die große Vorteil gegenüber Percepio
> ist das es völlig kostenlos ist!!
>

? Tracealyzer gerade für FreeRTOS war und ist kostenlos (habe gerade 
nochmal mit der HP gecheckt)!

> Ansonsten überlege dir doch mal anstatt FreeRTOS ein kommerzielles RTOS
> einzusetzen, z.B. embOS von SEGGER. Dann bekommst du direkt Support und
> Training vom Hersteller und bist nicht hier auf das Forum angewiesen. Im
> Endeffekt sparst du damit Zeit und Geld.

Damit würde ich übereinstimmen. Es gibt nichts umsonst; wenn Du "freie 
Software" einsetzt, bezahlst Du Anders als mit direkten Kosten (eine 
Binsenweisheit, die erst langsam in die Köpfe eindringt). Segger ist 
sicherlich eine gute Wahl, es gibt aber z.B. auch kommerzielle Derivate 
von FreeRTOS, falls man auf das FreeRTOS Modell nicht verzichten will.

: Bearbeitet durch User
von Stefan K. (stefan64)


Lesenswert?

Holger Kraehe schrieb:
> Bei mir haben alle Tasks die selben prioritäten.

In diesem Fall: ist Time-Slicing aktiviert?

Aus: FreeRTOS -> Task Priorities:
Any number of tasks can share the same priority. If 
configUSE_TIME_SLICING is not defined, or if configUSE_TIME_SLICING is 
set to 1, then Ready state tasks of equal priority will share the 
available processing time using a time sliced round robin scheduling 
scheme.

Ich bin mir ziemlich sicher, dass Du Dir ein DeadLock-Problem eingebaut 
hast. Leider ist Deine Code-Beschreibung nicht ganz exakt 
(while(1)-Schleifen fehlen, etc...), als dass man dieses Problem daraus 
wirklich erkennen kann.

Insgesamt bin ich mittlerweile der Meinung, dass zur 
Intertask-Kommunikation ausschliesslich die Mechanismen verwendet werden 
sollten, die vom FreeRTOS zur Verfügung gestellt werden. Das hat nicht 
nur den Vorteil, dass Fragen wie Atomar j/n erst gar nicht aufkommen. 
Auch das Debuggen mit Tools wie dem von Rüdiger erwähntem tracealyzer 
wird dadurch konsistenter.

Viele Grüße, Stefan

von Karl (Gast)


Lesenswert?

Ruediger A. schrieb:
> Karl schrieb:
>> Tracealyzer von Percepio ist eigentlich nicht mehr zu empfehlen.
>
> ? Warum nicht und speziell warum nicht MEHR?

Ich meinte nicht mehr seitdem es SystemView gibt. Mir persönlich gefällt 
das besser. Ich glaube auch nicht das es Percepio noch lange geben wird. 
Wieso sollten Kunden für deren einziges Produkt bezahlen wenn es das in 
besser von Segger kostenlos gibt? Der Percepio Stand auf der EW2017 war 
recht überschaubar ;-).

Ruediger A. schrieb:
> Was ist daran besser?

Ich finde die Darstellung einfacher zu verstehen. Bei Percepio finde ich 
das eher unübersichtlich. Außerdem basiert SystemView auf RTT, d.h. dort 
können deutlich mehr Trace Daten übertragen werden und beeinflußen 
weniger das Target.

Holger Kraehe schrieb:
> Was genau benötige ich, um den Tracealyzer zum laufen zu bekommen?
>
> Genügt eine SWD Verbindung zum Controller?
> Ich vermute dass ich dafür einen Segger J-Link benötige?

Meinst du jetzt Tracealyzer oder SystemView? SystemView funktioniert 
natürlich perfekt mit dem J-Link aber es geht auch ohne, dann ist es nur 
nicht mehr so komfortabel, geht aber auch. Ich habe das z.B. schon auf 
einem RL78 benutzt und da gibt es kein JTAG.

von Holger Kraehe (Gast)


Angehängte Dateien:

Lesenswert?

Danke für eure Antworten

Ich habe nun die Sourcefiles aus dem Zip SystemView_Src_V242.zip in mein 
Projekt includiert.

Habe _ARM_ARCH_7M_ global definiert, damit überall CM3 ausgewählt 
wird.
Ich verwende einen STM32F105RBT6

Ich habe zudem #define SYSVIEW_RAM_BASE        (0x20000000) gesetzt,
da laut Datenblatt ab dort das RAM beginnt.

FreertosConfig.h ist im Anhang.

Der Code wir compiliert.
Er warnt nur dass gewisse defines, redefines sind. Siehe Bild im anhang.


Leider findet der SystemView keinen RTT Block.

Muss ich den Code auf dem Controller noch irgendwie "Starten"?

von Felix F. (wiesel8)


Lesenswert?

Ich gehe zu 98% davon aus, dass du kein Sync-Problem sondern ein 
Logik-Problem hast.

Was ist, wenn TaskA das Flag immer auf 1 setzt? (Gewöhnlicherweise 
füllen MCU Puffer deutlich schneller als externe Peripherie ihn leert)
Was ist, wenn die SD Semaphore nicht freigegeben wird, weil nur 1 
Bedingung war ist?
Ist der Pseudocode überhaupt identisch zum C-Code?

Zudem solltest du den den TaskC über Events/Notifications steuern.

mfg

von Holger Kraehe (Gast)


Lesenswert?

Hab nun
1
 SEGGER_SYSVIEW_Conf();

In meinem main.c aufgerufen.
Nun findet SystemView einen RTT Block.
Aber Bei Timeline steht nur Unified. Und sonst nichts.

von Holger Kraehe (Gast)


Lesenswert?

Felix F. schrieb:
> Ist der Pseudocode überhaupt identisch zum C-Code?

Ja ist er.

Felix F. schrieb:
> Zudem solltest du den den TaskC über Events/Notifications steuern.

Ich hab den doch über eine Semaphore gesteuert.
Oder wie würde das anderst gehen?

von Karl (Gast)


Lesenswert?

Holger Kraehe schrieb:
> Nun findet SystemView einen RTT Block.
> Aber Bei Timeline steht nur Unified. Und sonst nichts.

Welche FreeRTOS Version benutzt du? Das FreeRTOS muss ja dafür 
instrumentiert sein, das es die Trace Daten in den RTT Buffer schreibt. 
Das sollte aber im SystemView Manual beschrieben sein.

von Karl (Gast)


Lesenswert?

SystemView manual "8.3.1 Configuring FreeRTOS for SystemView":

The patch file Sample.2.3_Core.patch shows the required modifications of 
the FreeRTOS 8.2.3 source and the GCC/ARM_CM4F port. It can be used as a 
reference when using another version or port of FreeRTOS. I.e. if 
another port than GCC/ARM_CM4F is used, the traceISR_ENTER(), 
traceISR_EXIT(), and traceISR_EXIT_TO_SCHEDULER() calls have to be added 
accordingly.


Hast du das Patch File benutzt?

von Holger Kraehe (Gast)


Lesenswert?

Karl schrieb:
> Welche FreeRTOS Version benutzt du?

8.2.3

Karl schrieb:
> Hast du das Patch File benutzt?

Ja, hab ich angewendet und habe FreeRTOS_TRace auf 1 gesetzt.
Das Patchfile ersetzt ja die Tracefunktionen von FreeRTOS mit jenen aus 
dem SystemView.

Ich habe jedoch einen CM3. Daher sieht mein Port anderst aus.

Aktuell kann ich im SystemView Record klicken und es tut irgenwas, Daten 
sehe ich allerdings keine. Wenn ich dann auch stop clicke und dann auf 
Read Recorded Data, kommt "0 Bytes received"

von Holger K. (holgerkraehe)


Lesenswert?

So, nun tut das ganze etwas mehr.

Es zeigt mir nun die SysTick interrupts an (Sehr viele halt)

Ein Problem bleibt aber noch bestehen.

Jenes mit dem "Redefined defines".
Hat jemand einen Tipp?

Irgendwie muss ich es hinkriegen, dass zuerst die Defines vom 
SystemView.h definiert sind anstellen von jenen des FreeRTOS.

von Holger K. (holgerkraehe)


Lesenswert?

Also, SystemView läuft.

Für jene welches interessiert, ihr müsst

#include "SEGGER_SYSVIEW_FreeRTOS.h"

In der FreeRTOSConf.h hinzufügen!

Leider sehe ich in SystemView meine Semaphoren nicht.
Zudem scheint es masslos überforert zu sein mit meinen events.

von Carl D. (jcw2)


Lesenswert?

Holger Kraehe schrieb:
> Bei mir haben alle Tasks die selben prioritäten.
>
> Ich habe nun folgendes implementiert:
>
> An allen stellen, wo ich auf die Variable zugreife.
>
1
> xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
2
>   stopProcess = 1;
3
> xSemaphoreGive(xStopProcessMutex);
4
>
>
>
>
> Leider hat sich das System erneut aufgehängt.

Gibt es da irgend eine Behandlung der Timeout-Situation?

von Holger K. (holgerkraehe)


Angehängte Dateien:

Lesenswert?

Carl D. schrieb:
> Holger Kraehe schrieb:
>> Bei mir haben alle Tasks die selben prioritäten.
>>
>> Ich habe nun folgendes implementiert:
>>
>> An allen stellen, wo ich auf die Variable zugreife.
>>> xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
>>   stopProcess = 1;
>> xSemaphoreGive(xStopProcessMutex);
>> >
>>
>>
>> Leider hat sich das System erneut aufgehängt.
>
> Gibt es da irgend eine Behandlung der Timeout-Situation?

Nein, ich gehe davon aus, dass ich irgendwan Zugriff erhalte, da die 
Tasks gleichberechtigt sind.

Anbei sind die TraceDaten.

Ab 02:23 ist das system gekippt, und die Variable permanent auf 1

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Holger K. schrieb:
> Carl D. schrieb:
>> Holger Kraehe schrieb:
>>> Bei mir haben alle Tasks die selben prioritäten.
>>>
>>> Ich habe nun folgendes implementiert:
>>>
>>> An allen stellen, wo ich auf die Variable zugreife.
>>>> xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
>>>   stopProcess = 1;
>>> xSemaphoreGive(xStopProcessMutex);
>>> >
>>>
>>>
>>> Leider hat sich das System erneut aufgehängt.
>>
>> Gibt es da irgend eine Behandlung der Timeout-Situation?
>
> Nein, ich gehe davon aus, dass ich irgendwan Zugriff erhalte, da die
> Tasks gleichberechtigt sind.

Aha, Prinzip Hoffnung, das ist dann der Moment , in dem der Windows-PC 
einen Restart braucht.

Gibt es eigentlich einen Plan welche Tasks, welche (geshared-ten) 
Resourcen welche Funktion haben sollen. Bisher sieht das von außen eher 
nach Extreme Progamming aus.
FreeRTOS hatte früher mal ein schönes Tutorial, mit schönen Beispielen, 
das man sich genauer zu Gemüte führen sollte. Denn daß da keine 
Jahrzente RT-Erfahrung am Werk sind, merkt man auch. Ist auch nicht 
schlimm, jeder fängt halt mal an.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Carl D. schrieb:
> Holger Kraehe schrieb:
>> Bei mir haben alle Tasks die selben prioritäten.
>>
>> Ich habe nun folgendes implementiert:
>>
>> An allen stellen, wo ich auf die Variable zugreife.
>>
1
>> xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
2
>>   stopProcess = 1;
3
>> xSemaphoreGive(xStopProcessMutex);
4
>>
>>
>>
>>
>> Leider hat sich das System erneut aufgehängt.
>
> Gibt es da irgend eine Behandlung der Timeout-Situation?

Bei dem Code sollte ein Timeout beim Take unnötig sein, weil der durch 
die Mutex geschützte Code die besitzende task nicht suspendieren kann. 
In einem wie von Stefan geschilderten Lockout Szenario bei unendlicher 
CPU bound Taskschleife würde diese Task auch gar nicht erst dran kommen, 
könnte also auch nicht timeouten.

Allerdings war ja die Idee der fehlenden Atomizität in diesem Fall eh 
eine geistige Sackgasse; man kann also die Mutex komplett wieder 
entfernen und anfangen, einen anderen Baum hochzubellen.

Holger, Du solltest wirklich mal Dir die Zeit nehmen, Multithreading 
etwas besser konzeptuell zu verstehen, dann hättest Du auch die 
Werkzeuge an der Hand, um Dir deine Fragen selber beantworten zu können. 
Wenn Du z.B. in dem fehlerhaften Zustand bist, wäre es sehr hilfreich zu 
wissen, ob alle tasks suspendiert oder wartend sind (deadlock; läßt sich 
durch OS plugins oder eben Visualisierung erkennen) oder z.B. bei jedem 
Break dieselbe Task in derselben Funktion läuft (das wäre dann das von 
Stefan skizzierte Lockout Problem).

Es kann auch sein, dass das Problem komplett woanders liegt, z.B. bei 
fehlkonfiguriertem OS oder ein Problem in der Middleare (kann es z.B. 
sein, dass eine Task in einer Aufruffunktion im FS hängt und nicht 
zurückkehrt?) Dazu müsste man aber genauere Infos über den Systemzustand 
im Fehlerfall haben.

von Holger K. (holgerkraehe)


Lesenswert?

Carl D. schrieb:
> Holger K. schrieb:
>> Carl D. schrieb:
>>> Holger Kraehe schrieb:
>>>> Bei mir haben alle Tasks die selben prioritäten.
>>>>
>>>> Ich habe nun folgendes implementiert:
>>>>
>>>> An allen stellen, wo ich auf die Variable zugreife.
>>>>> xSemaphoreTake(xStopProcessMutex,portMAX_DELAY);
>>>>   stopProcess = 1;
>>>> xSemaphoreGive(xStopProcessMutex);
>>>> >
>>>>
>>>>
>>>> Leider hat sich das System erneut aufgehängt.
>>>
>>> Gibt es da irgend eine Behandlung der Timeout-Situation?
>>
>> Nein, ich gehe davon aus, dass ich irgendwan Zugriff erhalte, da die
>> Tasks gleichberechtigt sind.
>
> Aha, Prinzip Hoffnung, das ist dann der Moment , in dem der Windows-PC
> einen Restart braucht.
>
> Gibt es eigentlich einen Plan welche Tasks, welche (geshared-ten)
> Resourcen welche Funktion haben sollen. Bisher sieht das von außen eher
> nach Extreme Progamming aus.
> FreeRTOS hatte früher mal ein schönes Tutorial, mit schönen Beispielen,
> das man sich genauer zu Gemüte führen sollte. Denn daß da keine
> Jahrzente RT-Erfahrung am Werk sind, merkt man auch. Ist auch nicht
> schlimm, jeder fängt halt mal an.

Habe mir das Tutorial bereits mehrmals angeschaut und durchgelesen.

Grundsätzlich geht es um folgendes:

Es müssen Flash Memories beschrieben werden, dann muss der jeweilige 
sektor gelöscht werden und dabei die Zeit welche zum löschen benötigt 
wurde, gemessen werden.

Leider haben die Chips keinen Busy pin sondern nur ein Flag welches per 
SPI ausgelesen werden muss.

Ich habe zwei queues. Eine für den Poll Task und eine mit den Memories 
welche Ready sind.

Der Polltask nimmt sich ein element seiner queue und prüft das 
entsprechende memory ob es bereit ist. Wenn nicht, sendet er die ID 
wieder ans ende der queue. Wenn es jedoch ready war, schreib er die 
aktuelle anzahl der systicks in ein globales array, zudem schreibt er 
die ID in die Queue für den Memory Process task.

Der Memory Process task, nimmt sich das erste element und schaut in 
einem globalen array nach, welchen status das entsprechende memory hat.
Entsprechend führt er die aktion aus, und setzt das memory wieder auf 
die liste der zu prüfenden memories in die Queue für den ersten task.

Wenn der prozess task merkt, dass zuvor ein memory gelöscht wurde 
(anhand des states) dann schreibt er einen log eintrag mit der Zeit 
(aktuelle ticks - ticks bei start) in einen buffer. Wenn dieser eine 
gewisse grösse erreicht hat, wird die varable ProcessStop gesetzt.

Nun muss gewartet werden, bis der PollTask welcher prüft ob die memorys 
ready sind, eine leere Queue hat. Denn dann sind alle memorys gelöscht 
und die zeiten erfasst. Nun schreibt der SD-Task auf die Karte.

Dann wird stopProcess = 0 gesetzt und weiter gehts.

Leider kriege ich mommentan zufällige HardFault errors. Eventuell liegts 
am systemview?

von Carl D. (jcw2)


Lesenswert?

Es gibt also eine Anzahl HW-Geräte, deren Status gepollt werden muß, 
wegen mangelnder Interruptfähigkeiten, und Benutzern dieser Geräte, die 
notfalls auf "Ready" warten können müssen. Wenn sie eine Screiboperation 
angestoßen haben, dann muß auf deren Abschluß gewartet werden.

Kann man den Status schnell ermitteln? Dann könnte man das im 
ApplicatioTickHook machen und bei Ok einen Semaphore je Gerät releasen.
Jeder der auf ein Gerät schreiben will, muß sich vorher den zugehörigen 
Semaphore holen, den er aber nie selber zurück gibt, sondern per 
"Quasi-Interrupt" ApplicationTick.

Man kann das optimieren, indem jede Schreibfunktion ein Bit Futur 1 
setzt, wenn es ein Gerät in den Zustand Busy versetzt hat, was nach 
erfolgter Statusprüfung wieder zurückgesetzt wird, aber das muß man dann 
wieder ordentlich synchronisieren. Erster Schritte wäre mal straigh 
forward.

BTW, wichtige Regel: optimieren wenn's funktioniert, nicht früher!

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Holger K. schrieb:
>
> Ich habe zwei queues. Eine für den Poll Task und eine mit den Memories
> welche Ready sind.
>

kann es sein, dass Du ein xQueueSend mit portMAX_DELAY benutzt und die 
Queue voll ist? So etwas kann zu Deadlocksiutationen führen, wenn das 
Flushen der Queue durch die Syncvariable unterdrückt wird (ich habe mir 
den Code nicht so genau angesehen, ob das konkret hier möglich ist). Wie 
gesagt wäre es zunächst mal hilfreich zu wissen, ob das System im 
Deadlock, Lockout oder wie auch immer steht.

von Stefan K. (stefan64)


Lesenswert?

Holger K. schrieb:
>> Gibt es da irgend eine Behandlung der Timeout-Situation?
>
> Nein, ich gehe davon aus, dass ich irgendwan Zugriff erhalte, da die
> Tasks gleichberechtigt sind.

Das ist eine falsche Annahme. Wenn alle Tasks dieselbe Priorität haben, 
dann kann kein Task den anderen unterbrechen (zumindest wenn 
Time-Slicing abgeschaltet ist, e.g. configUSE_TIME_SLICING = 0). D.h. 
wenn ein Task in einer Endlosschleife hängt, dann steht das komplette 
System.

Holger Kraehe schrieb:
>> Ist der Pseudocode überhaupt identisch zum C-Code?
>
> Ja ist er.

Exakt? Heisst das, es gibt in den Tasks keine while(1)-Schleife?

Der Weg, das System mit systemview zu debuggen, ist auf jeden Fall der 
richtige Weg und wird Dir auch bei zukünftigen Problemen weiterhelfen.

Viele Grüße, Stefan

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.