Hi,
auf einem raspberry pi benötige ich einen Scheduler.
Mit diesem Objekt soll ein einfacher Timer gekapselt werden. In der
Regel handelt es sich einfach um eine Interruptserviceroutine, die alle
Millisekunde aufgerufen wird, und den Zeitzähler um eins zu
inkrementiert.
Auf einem STM32 hab ich das bereits umgesetzt. Gibt es auf dem raspberry
pi auch so ein Hardwareinterrupt der jede Millisekunde ausgelöst wird?
fuzzy schrieb:> Das bedeutet? Ich habe ja das raspberry pi OS drauf.
Es gibt kein "Raspberry OS". Das ist Linux. Und Linux ist in der
Normalversion eben kein Echtzeit OS.
fuzzy schrieb:> Kann ich nicht einen Thread aufsetzen und dadurch einen 1ms Tick> erzeugen?
Kannst Du machen. Ob der dann allerdings pünktlich kommt, sei
dahingestellt.
Andreas B. schrieb:> Es gibt kein "Raspberry OS". Das ist Linux.
„Raspberry Pi OS“ ist nun der Name für das, was früher „Raspbian“ hieß –
damit ist nix verkehrt. Man könnte sicher auch einen RT-Kernel dafür
bauen, ±1ms sind damit dann sicher sicher (intended) drin. Auf der
anderen Seite gibt’s auch dedizierte RT-Systeme, die, je nach sonstigen
Anforderungen, die bessere Wahl wären. Natürlich nicht, wenn’s um eine
Linux-Anwendung geht ….
Jack V. schrieb:> Man könnte sicher auch einen RT-Kernel dafür> bauen, ±1ms sind damit dann sicher sicher (intended) drin.
Das haben schon andere gemacht. Gockel hilft.
Andreas B. schrieb:> Gockel hilft.
Du meinst Meinolf Gockel (http://www.gockel.de)? Ich bin mir nicht
sicher, wie ’n Laden, der heute noch nicht mal TLS, sondern nur
unverschlüsseltes HTTP für einen Onlineshop(!) anbietet, bei doch recht
speziellen IT-Fragen helfen können soll.
Hi fuzzy,
Soweit ich weiss ist der RT Teil seit ca. 1-2 im RPi OS drin. Glaube die
Timer sind vom OS genutzt. Mit threads sollte das gehen - pthread ist
das Zauberwort. Musst du dann mal schaun, ob der Jitter ok ist.
Jack V. schrieb:> Andreas B. schrieb:>> Gockel hilft.>> Du meinst Meinolf Gockel (http://www.gockel.de)?
Er meint vermutlich Google, leidet aber unter einem ganz besonders
lustigem Humor oder womöglich einer Tastaturlegasthenie.
> Ich bin mir nicht> sicher, wie ’n Laden, der heute noch nicht mal TLS, sondern nur> unverschlüsseltes HTTP für einen Onlineshop(!) anbietet, bei doch recht> speziellen IT-Fragen helfen können soll.
Also bei mir hat https://shop.gockel.de ein TLS-Zertifikat von Let's
encrypt.
fuzzy schrieb:> auf einem raspberry pi benötige ich einen Scheduler.> Mit diesem Objekt soll ein einfacher Timer gekapselt werden. In der> Regel handelt es sich einfach um eine Interruptserviceroutine, die alle> Millisekunde aufgerufen wird, und den Zeitzähler um eins zu> inkrementiert.>> Auf einem STM32 hab ich das bereits umgesetzt. Gibt es auf dem raspberry> pi auch so ein Hardwareinterrupt der jede Millisekunde ausgelöst wird?
Der Rpi ist kein uC; sondern eher ein PC. Da benutzt man in der Regel
ein OS (Raspbian bzw. Nachfolger; aka Linux). Es gibt auch RTOS wie oben
geschrieben. Man kann auch Bare Metal machen (also Ansatz a la uC), das
ist aber kein einfacher Einstieg. Was genau hast du denn vor?
Lothar schrieb:>> Thread aufsetzen und dadurch einen 1ms Tick erzeugen>> Thread is asynchron - wird nicht funktionieren. Zudem ist der Context> Switch 10 msec
Diese Aussage ergibt irgenwie wenig Sinn.
Wenn ich "Echtzeit" auf dem Raspi brauche, dann packe ich meist eine
extra Hardware dazu. Wie wäre es mit einem billigen Arduino, der macht
das Millisekunden-Timing, und der Raspi hat genug Zeit, mal etwas aus
der lahmen SD-Karte zu holen. Einfach per USB anschliessen. Läuft bei
mir seit Jahren.
Für noch mehr Echtzeit nehme ich die kleinen FPGAs von Lattice. Die
lasse sich vom Raspi über SPI befüllen, und machen dann Microsekunden
Timing.
Ein Gerät, welches als Massenspeicher eine SD-Karte hat, dem würde ich
keine Echtzeit anvertrauen.
Vielen Dank für eure Antworten. Ich brauche ja keinen Realtime
Systemtakt von 1ms. Mir reicht nur ein 1ms Takt für gewisse Anwendungen.
Dieser kann auch schwanken. In Windows habe ich bereits auch einen mit C
entwickelt und einem Thread. Das ganze müsste doch quasi auch mit dem
raspberry pi OS realisierbar sein.
Für Threads gibt es ja die Möglichkeit mit pthreads oder std::thread.
fuzzy schrieb:> In Windows habe ich bereits auch einen mit C entwickelt und einem Thread
Kannst Du den Code mal zeigen? Grade in Windows ist doch ein .NET
Callback Timer die naheliegende Lösung für 1 msec
Timer_sampling.Interval = 1
Timer_sampling.Start()
Private Sub TimerSampling_Tick(sender As Object, e As EventArgs) Handles
Timer_sampling.Tick
Und das geht unter Linux mit z.B. FLTK genau so.
Rolf M. schrieb:> clock_nanosleep()
Das ist doch blocking = der main thread steht dann so lange?
Die Lösung ist doch einfach ein Timer Callback Handler der genau einer
Timer ISR beim uC entspricht ...
Klar man könnte noch mit signals anrücken aber wozu kompliziert?
Lothar schrieb:> Rolf M. schrieb:>> clock_nanosleep()>> Das ist doch blocking = der main thread steht dann so lange?
Der Thread, in dem man es aufruft, steht so lange.
> Die Lösung ist doch einfach ein Timer Callback Handler der genau einer> Timer ISR beim uC entspricht ...
Ein Callback muss aber auch erstmal von irgendwo aufgerufen werden.
Andreas B. schrieb:> fuzzy schrieb:>> Das bedeutet? Ich habe ja das raspberry pi OS drauf.> Es gibt kein "Raspberry OS". Das ist Linux. Und Linux ist in der> Normalversion eben kein Echtzeit OS.
Das ist natürlich nur... teilweise richtig. Richtig ist, daß man jedem
Linuxkernel auf Multicores mit dem Bootparameter "isolcpus" mitteilen
kann daß der Kernelscheduler die angegebenen Cores nicht mit "normalen"
Tasks beschicken soll. Dann laufen im Betrieb auf diesem/n Core/s nur
die minimalen Interrupts, sonst nichts. Mit dem CLI-Werkzeug taskset(1)
können dann aber trotzdem Prozesse fest an den "isolierten" Core
gebunden werden. Das funktioniert auch ohne RT-Patches.
Nebenbei bin ich etwas... verunsichert hinsichtlich der Frage, ob die
Damen und Herren in diesem Thread sich darüber bewußt sind, was
"Echtzeit" bedeutet. Leider scheinen die meisten Menschen --
insbesondere IT-Fachleute -- zu glauben, daß es sich dabei um besonders
schnelle Reaktions- oder Laufzeiten handele. Richtig ist, daß es sich
dabei allerdings lediglich um eine Vereinbarung handelt, wie lange das
Prozessieren eines Ereignisses dauert. Ein Beispiel: die Simulationen
des Deutschen Wetterdienstes laufen in Echtzeit, auch wenn sie bis zu
acht Stunden zum Prozessieren brauchen.
Lothar schrieb:> Wie das unter Linux geht sieht man doch in den beiden verlinkten> Beispielen. Direkt mit timer_create() eine ISR machen die den Callback> periodisch aufruft
Das läuft dann aber auch in einem separaten Thread. Die man-Page klingt
mir auch nicht so vertrauenerweckend:
"Notify the process by invoking sigev_notify_function "as if" it were
the start function of a new thread. (Among the implementation
possibilities here are that each timer notification could result in the
creation of a new thread, or that a single thread is created to receive
all notifications.)
Kann also sein, dass dann jede Millisekunde ein neuer Thread erstellt
und wieder zerstört wird, was nicht sehr performant klingt und für's
Debugging auch nicht grad toll ist.
Da erstelle ich mir den Thread doch lieber selber, mach da eine
Endlosschleife rein, in der er halt sein Ding macht und sich dann mit
clock_nanosleep() schlafen legt, bis der nächste Zyklus dran ist. Das
ist nun auch kein Hexenwerk.
- oder über eine Library die das intern macht - wie
> FLTK:
Da wird aber kein Signal oder Thread verwendet, sondern dein Callback
wird über die Eventloop von FLTK aufgerufen. Über diese Eventloop läuft
dann aber auch alles andere. Ob man da auch nur halbwegs sauber eine
Millisekunde halten kann, wenn da zwischendurch irgendwo ein Fenster neu
gezeichnet oder eine XML-Datei eingelesen werden soll?
fuzzy schrieb:> Vielen Dank für eure Antworten. Ich brauche ja keinen Realtime> Systemtakt von 1ms. Mir reicht nur ein 1ms Takt für gewisse Anwendungen.> Dieser kann auch schwanken. In Windows habe ich bereits auch einen mit C> entwickelt und einem Thread. Das ganze müsste doch quasi auch mit dem> raspberry pi OS realisierbar sein.>> Für Threads gibt es ja die Möglichkeit mit pthreads oder std::thread.
Also hat die Thematik nichts mit dem Rpi zu tun; du möchtest in einem
Linux (userland) Process lediglich (ungefähr) jede Millisekunde einmal
alarmiert werden und eine Funktion f() aufrufen?!
Wenn du eh schon nebenläufig arbeitest, warum nicht einen separaten
Thread starten der abwechselnd f() aufruft und dann 1ms schläft?! (Also
prinzipiell was Rolf vorschlägt.)
Wenn du tatsächlich einen "Scheduler" willst (ohne Multi-Threading),
dann realisiert man das in der Regel basierend auf poll/sellect (damit
hat man die FD Events; und an den Timeout koppelt man die zeigesteuerten
Jobs).
Rolf M. schrieb:> Callback wird über die Eventloop von FLTK aufgerufen
Probier es doch selbst mal aus. Dem ist nicht so. Das würde ja dazu
führen, dass wenn der User ein Menü festhält, während dessen keine
Callbacks aufgerufen werden:
int main() {
// do stuff there pre-emtively - like acquiring data from GPIO
Fl::add_timeout(0.001, callback);
while (RUNNING) {
// do stuff here co-operatively - like reading value from slider
widget
// yield()
RUNNING = Fl::check(); }
return RUNNING;
}
Threads dagegen haben genau dieses Problem. Um den Zugriff auf
Ressourcen zu synchronisieren, braucht es ein Spinlock, und das zerstört
die Echtzeit:
https://www.fltk.org/doc-1.3/advanced.html
Lothar schrieb:> Rolf M. schrieb:>> Callback wird über die Eventloop von FLTK aufgerufen>> Probier es doch selbst mal aus. Dem ist nicht so. Das würde ja dazu> führen, dass wenn der User ein Menü festhält, während dessen keine> Callbacks aufgerufen werden:
Warum? Was macht FLTK denn während dieser Zeit?
> int main() {> // do stuff there pre-emtively - like acquiring data from GPIO> Fl::add_timeout(0.001, callback);> while (RUNNING) {> // do stuff here co-operatively - like reading value from slider> widget> // yield()> RUNNING = Fl::check(); }> return RUNNING;> }
Und wsa denkst du jetzt, von wo aus dein Callback aufgerufen wird? Ich
kann's dir sagen: Das wird innerhalb von Fl::check() gemacht, wie auch
die Doku schon sagt. Nix asynchron oder präemptiv, sondern alles schön
nacheinander. Und wenn deine GUI zu lange braucht, um ein Fenster neu zu
pinseln, fehlt halt dein Miiisekunden-Timer solange. Wie sollte es das
ohne Threads auch sonst machen?
> Threads dagegen haben genau dieses Problem. Um den Zugriff auf> Ressourcen zu synchronisieren, braucht es ein Spinlock, und das zerstört> die Echtzeit:
Einen Spinlock verwendet man deshalb für sowas nur in besonderen
Ausnahmefällen. Und wie viel man synchornisieren muss, hängt sehr stark
von der Aufgabe ab. Deshalb sind Threads nicht überall sinnvoll.
> https://www.fltk.org/doc-1.3/advanced.html
Da steht überhaupt nix von Spinlocks.
Rolf M. schrieb:> Callback ... wird innerhalb von Fl::check()> gemacht, wie auch die Doku schon sagt
Die Doku ist so eine Sache. Probier es doch selbst mal aus. Dann wirst
Du sehen, dass Fl::check() nicht zurückkommt, bis alle Pending Events
abgearbeitet sind. Wenn der User ein Menü festhält, kommt der Event erst
mit dem Loslassen, und bis dahin kommt Fl::check() nicht zurück.
Die Callbacks werden an einen System Timer gehängt. Der läuft weiter,
auch wenn sich Fl::check() oder main() aufgehängt haben.
Das ist übrigens bei allen Toolboxen die ich kenne so. Auch auf RTOS wo
es gar keine Unterstützung für Threads gibt.
Kennst Du das nicht aus der uC Programmierung? Dort werden doch auch die
Callbacks in eine Timer ISR eingehängt, und laufen unabhängig von main()
- ganz ohne OS und Threads.
> Spinlock ... nur in besonderen Ausnahmefällen
Ein Spinlock ist doch schon nötig, wenn es für die Einstellung eines
Parameters in der GUI ein Textfeld und einen Slider gibt, und beides mit
Threads gemacht werden soll. Dann müssen die gegeneinander gelockt
werden, weil sonst Unsinn passiert.