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!
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.
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!
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.
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?
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.
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.
„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
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.
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.
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".
>> 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
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.
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.
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.
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.
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.
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.
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.