Forum: Mikrocontroller und Digitale Elektronik FreeRTOS Shared Memory


von Mark (Gast)


Lesenswert?

Hi,
ich würde gerne bei FreeRTOS einen Shared Memory einrichten, um Daten 
mehreren Tasks zur Verfügung zu stellen. 
https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__PoolMgmt.html#details
Leider finde ich nirgends eine Doku oder ein passendes Beispiel wie das 
genau funktioniert.
So von meinen Überlegungen könnte ich mir das in etwa so vorstellen, 
dass ich eine globale Funktion schreibe, die allen Tasks zugänglich ist 
und welche mithilfe von Mutexes oder Semaphoren  den gleichzeitigen 
Zugriff auf den Speicher verhindert.

Allerdings verstehe ich schon das Beispiel in der Dokumentation nicht:
1
pMem = (MEM_BLOCK_t *)osMemoryPoolAlloc(mpid_MemPool, 0U);  // get Mem Block
2
    if (pMem != NULL) {                                         // Mem Block was available
3
      pMem->Buf[0] = 0x55U;                                     // do some work...
4
      pMem->Idx    = 0U;
5
 
6
      status = osMemoryPoolFree(mpid_MemPool, pMem);            // free mem block
Wieso wird der Memory Block gleich wieder freigegeben? Wie kann ich den 
Später wieder genau auf diesem Zugreifen?

Mehr Doku oder Beispiele wären schön! Danke euch!

: Verschoben durch Moderator
von Klaus W. (mfgkw)


Lesenswert?

Mark schrieb:
> Wieso wird der Memory Block gleich wieder freigegeben?

Zwischen Allokieren und Freigeben steht doch im Kommentar "do some 
work".
Ist halt nur eine Demo, wie man es machen kann/soll.

In einem realen Beispiel wird da sicher mehr gemacht, aber nach Ende 
wohl auch wieder freigegeben, wenn man den Speicher nicht mehr braucht.

Nach dem Freigeben wird natürlich nicht drauf zugegriffen.

: Bearbeitet durch User
von Mark (Gast)


Lesenswert?

Ok, ist dann folgender schematischer Ansatz richtig? Ich habe 4 Tasks.
Task 1: Liest Sensorwerte vom ADC
Task 2: Statemaschine welche anhand dieser Werte den Status ändert
Task 3: Sendet die Werte über den UART zur weiteren Verwendung
Task 4: Zeigt die Werte auf einem Display

Ich dachte, es ist sinnvoll die Werte in einen Shared Memory zu 
schreiben und die 3 Tasks holen sie sich ab wen sie diese benötigen.

Ich schreibe eine globale Zugriffsfunktion zum Schreiben und Lesen auf 
diesen Memory in etwa so:

Schreiben:
- Memory Allokieren und Handler generieren. Der Handler ist nur in der 
Funktion bekannt.
- Mutex setzten
- Werte schreiben
- Mutex löschen

Lesen:
- Mutex setzen
- Werte lesen mit Handler.... Wie übergebe ich der Funktion den Handler 
am besten?
-Mutex löschen

Zur Laufzeit wird der Speicher nie mehr freigegeben. Ist das gut so?

Danke euch!

von Johannes S. (Gast)


Lesenswert?

Der MemoryPool ist auch eher eine Speicherverwaltung wie malloc, dafür 
threadsafe und bei gleich großen Blöcken kann man Speicherzerstückelung 
vermeiden.
Um Werte von einem Thread in einen anderen zu schicken bieten sich 
Queues an. Durch die Q kommen dann alle Werte sicher an solange die Q 
nicht überläuft. Für ein GUI ist das nicht unbedingt nötig, da reicht 
oft ein asynchrones reingreifen in die aktuellen Werte (atomare 
Datentypen vorrausgesetzt). Änderungen kann man da auch durch Eventflags 
signalisieren. Das sind einfache Flags an denen ein Thread warten kann 
und man spart sich ein polling. Bringt natürlich nur was wenn sich die 
Werte selten ändern.

von Rolf M. (rmagnus)


Lesenswert?

Ich verstehe nicht ganz, was das mit shared memory zu tun hat. Du 
scheinst hier von ganz normalen Variablen zu sprechen, deren Zugriff per 
Mutex threadsafe gemacht wird.

Mark schrieb:
> Zur Laufzeit wird der Speicher nie mehr freigegeben. Ist das gut so?

Warum wird er dann dynamisch allokiert?

von Purzel H. (hacky)


Lesenswert?

Shared memory wird memory gemannt, welche zwischen mehreren Programmen 
geshart wird. Was du meinst ist in einem Programm - eine globale 
Variable, welche mit einem Semaphore geschuetzt wird. Das ist viel 
einfacher im Sinne, dass du nur eine Semaphore benoetigst und mit dir 
selbst ausmachen musst, wozu die gut ist. Indem die Variable zB nur per 
access procedure verwendet wird.

von drm (Gast)


Lesenswert?

Daten tauscht man zwischen Tasks mit Queues aus.
Ein Task füllt die Queue, ein anderer bedient sich aus der Queue bei den 
ankommenden Daten. Die Queue ist FIFO, RTOS kümmert sich um die 
Kommunikation.
Natürlich kann man um das RTOS Konzept herumprogrammieren, in dem man 
Semaphoren und globale Variablen verwendet, aber jeder kann schliesslich 
so proggen wie er es für richtig hält.

von Mucky F. (Gast)


Lesenswert?

drm schrieb:
> Daten tauscht man zwischen Tasks mit Queues aus.

Werden dann die Daten in die Queue kopiert oder  sind auch Pointer 
möglich?

von Ergo70 (Gast)


Lesenswert?

„Using queues that pass data by copy does not prevent queues from being 
used to pass data by reference. When the size of a message reaches a 
point where it is not practical to copy the entire message into the 
queue byte for byte, define the queue to hold pointers and copy just a 
pointer to the message into the queue instead.“

https://www.freertos.org/Embedded-RTOS-Queues.html

von Mucky F. (Gast)


Lesenswert?

Ergo70 schrieb:
> the queue to hold pointers and copy just a pointer to the message into
> the queue instead.“

Wozu dann shared memory?

von Rolf M. (rmagnus)


Lesenswert?

drm schrieb:
> Daten tauscht man zwischen Tasks mit Queues aus.

Das kommt natürlich auf den Anwendungsfall an.

> Natürlich kann man um das RTOS Konzept herumprogrammieren, in dem man
> Semaphoren und globale Variablen verwendet,

Semaphoren sind Teil des RTOS-Konzepts.

von ergo70 (Gast)


Lesenswert?

Mucky F. schrieb:
> Wozu dann shared memory?

Wohin zeigt der Pointer denn sonst?

Aber wenn das Zielsystem keine MMU/MPU hat und Du nicht FreeRTOS-MPU 
benutzt, ist aller Speicher aus Sicht der Tasks shared. Da gibt es keine 
Prozessisolation wie z. B. bei Linux auf Architekturen mit MMU, wo man 
shared memory explizit mit mmap() oder shmget() anfordert und dann über 
Prozessgrenzen hinweg benutzen kann.

von Rolf M. (rmagnus)


Lesenswert?

ergo70 schrieb:
> Mucky F. schrieb:
>> Wozu dann shared memory?
>
> Wohin zeigt der Pointer denn sonst?

Einfach auf Speicher.

> Aber wenn das Zielsystem keine MMU/MPU hat und Du nicht FreeRTOS-MPU
> benutzt, ist aller Speicher aus Sicht der Tasks shared.

Da muss nix geshared werden, weil die sowieso alle auf den gesamten 
Speicher zugreifen können.

> Da gibt es keine Prozessisolation wie z. B. bei Linux auf Architekturen
> mit MMU, wo man shared memory explizit mit mmap() oder shmget() anfordert
> und dann über Prozessgrenzen hinweg benutzen kann.

Eben, deshalb gibt es da keinen "shared memory", sondern einfach nur den 
"memory".

: Bearbeitet durch User
von drm (Gast)


Lesenswert?

>> Natürlich kann man um das RTOS Konzept herumprogrammieren, in dem man
>> Semaphoren und globale Variablen verwendet,
>Semaphoren sind Teil des RTOS-Konzepts.

um Signale zwischen Tasks auszutauschen, nicht Daten
z.B., Achtung, Task01 verwendet den einigen I2C Bus, alle anderen Tasks 
Finger weg von I2C

von drm (Gast)


Lesenswert?

besseres Beispiel:
Daten von Task1 an Task2 über eine Queue schicken,
Task gibt eine Semaphore frei um Task2 zu signalisieren das neue Daten 
verfügbar sind. Task2 nimmt die Semaphore um zu signalisieren, das die 
Daten geholt + bearbeitet werden (es passt z.B. nur eine definierte 
Menge Daten in die Queue). Nach Abarbeitung gibt Task2 die Semaphore 
wieder frei um Task1 zu signalisieren das neue Daten entgegengenommen 
werden könnten.

Vorteil:
Task2 konsumiert keine Rechenzeit so lange es nichts zu tun gibt.
Task1 konsumiert keine Rechenzeit so lange Task2 am Arbeiten ist.

von Johannes S. (Gast)


Lesenswert?

In dem Fall ist eine Semaphore unnötig, weil ein Task auch wartend auf 
Daten in der Q blockieren kann. Sowohl beim put als auch beim get.
Aber auch ein Speicherbereich ist eine Resource die man per Semphore 
schützen kann wenn ein Block konsistent sein soll, also z.B. eine 
Struktur enthält die ja in mehreren Schritten gelesen/geschrieben wird.

von Rolf M. (rmagnus)


Lesenswert?

drm schrieb:
>>> Natürlich kann man um das RTOS Konzept herumprogrammieren, in dem man
>>> Semaphoren und globale Variablen verwendet,
>>Semaphoren sind Teil des RTOS-Konzepts.
>
> um Signale zwischen Tasks auszutauschen, nicht Daten

Sie dienen zur Synchronisation, unter anderem von Zugriffen auf 
Ressourcen wie z.B. Speicher.

> z.B., Achtung, Task01 verwendet den einigen I2C Bus, alle anderen Tasks
> Finger weg von I2C

Oder: Achtung, Task01 verwendet die Variable X, alle anderen Tasks 
Finger weg von X.

Johannes S. schrieb:
> In dem Fall ist eine Semaphore unnötig, weil ein Task auch wartend auf
> Daten in der Q blockieren kann.

Kommt auf das Framework an. Aber ja, das gibt es. In dem Fall ist die 
Semaphore eben schon in der Queue eingebaut.

von Joe J. (j_955)


Lesenswert?

Ich hab mir das Buch Hands-On-Rtos gekauft. Hier werden alle Konzepte 
vom FREERTOS anschaulich erklärt. Gute Beispiele und skalierbare 
Konzepte sind ebenfalls drin. Das Geld ist hier gut angelegt.

von drm (Gast)


Lesenswert?

>Ich hab mir das Buch Hands-On-Rtos gekauft.
ISBN ?

von drm (Gast)


Lesenswert?

Herausgeber ‏ : ‎ Packt Publishing (15. Mai 2020)
Sprache ‏ : ‎ Englisch
Taschenbuch ‏ : ‎ 496 Seiten
ISBN-10 ‏ : ‎ 1838826734
ISBN-13 ‏ : ‎ 978-1838826734

igitt, nur englisch

von Mucky F. (Gast)


Lesenswert?

ergo70 schrieb:
> Mucky F. schrieb:
>> Wozu dann shared memory?
>
> Wohin zeigt der Pointer denn sonst?

Eben, was will der TE mit shared memory wenn das RTOS n besseres Konzept 
hat?

> Aber wenn das Zielsystem keine MMU/MPU hat und Du nicht FreeRTOS-MPU
> benutzt, ist aller Speicher aus Sicht der Tasks shared.

s.o. aber wenn er schon RTOS nutzt muss er sich nicht drum kümmern.

drm schrieb:
> Task gibt eine Semaphore frei um Task2 zu signalisieren das neue Daten
> verfügbar sind. Task2 nimmt die Semaphore

Das die Unterprogramme sich irgenwie einigen müssen wer was wann damit 
macht finde ich irgenwie selbstverständlich.

Warum da so ein unübersichtliches Semaphorengebastel sein muss verstehe 
ich aber eher weiniger. Da enstehen lokale interdependenzen die schwer 
zu tracken sind, zuminmest für mich.  Das kann man imo mit ner zentralen 
Statusvariable und enum einfacher lösen.

von ergo70 (Gast)


Lesenswert?

Was anderes habe ich doch auch nicht geschrieben. Da es keinen 
speziellen Speicherschutz gibt, ist aller Speicher geteilter Speicher. 
Und die Frage wohin der Pointer zeigt, sollte eigentlich nur darauf 
hinweisen, dass er auf Speicher zeigen sollte der auch allokiert ist.

von Joe J. (j_955)


Lesenswert?

drm schrieb:
> Herausgeber ‏ : ‎ Packt Publishing (15. Mai 2020)
> Sprache ‏ : ‎ Englisch
> Taschenbuch ‏ : ‎ 496 Seiten
> ISBN-10 ‏ : ‎ 1838826734
> ISBN-13 ‏ : ‎ 978-1838826734
>
> igitt, nur englisch

;-)

Also das lässt sich nach einer durchgezechten Nacht noch locker so im 
Halbschlaf lesen. Sind sogar noch schöne Bildchen drin...
Kann ich echt empfehlen.

von Rolf M. (rmagnus)


Lesenswert?

drm schrieb:
> igitt, nur englisch

Na wenigstens nicht deutsch. 😉

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.