IRQ Serielle Schnittstelle
IRQ Serielle Schnittstelle
Hallo!
Ich habe ein Problem mit meiner seriellen Schnittstelle. Es passiert relativ häufig das mein Empfangspuffer Daten erhält er diese aber nicht an mir weiter leitet!
Dabei habe ich ein zeitliches Raster von 50ms in dem ich Daten bekomme, eingestellt.
Nun kommt es vor das sich mein BS sich erst nach 300ms meldet und mir dann den gesamten Puffer übergibt. Ich muss aber die Daten im 50ms Takt auswerten!! Was kann ich dagegen machen? Soll ich die IRQ Priorität verändern? Habt Ihr ne schlaue Idee für mich!
Gruss macke_a
Ich habe ein Problem mit meiner seriellen Schnittstelle. Es passiert relativ häufig das mein Empfangspuffer Daten erhält er diese aber nicht an mir weiter leitet!
Dabei habe ich ein zeitliches Raster von 50ms in dem ich Daten bekomme, eingestellt.
Nun kommt es vor das sich mein BS sich erst nach 300ms meldet und mir dann den gesamten Puffer übergibt. Ich muss aber die Daten im 50ms Takt auswerten!! Was kann ich dagegen machen? Soll ich die IRQ Priorität verändern? Habt Ihr ne schlaue Idee für mich!
Gruss macke_a
Ein Echtzeitprozess ist einer, der zumindest in bestimmten Anteilen unter SCHED_FIFO oder SCHED_RR läuft.
$ man sched_setscheduler
Mit der normalen Einstellung SCHED_OTHER kann der Prozess jederzeit von anderen Prozessen unterbrochen werden, da alle dieselbe Priorität haben. Nice-Level helfen nicht, da ein Prozess, der viel tut (der, der schnell sein muss), mit der Zeit immer weiter ausgebremst wird, um die anderen Prozesse mal ranzulassen. Wenn man das nicht will, muss man SCHED_FIFO oder SCHED_RR benutzen.
Janka
$ man sched_setscheduler
Mit der normalen Einstellung SCHED_OTHER kann der Prozess jederzeit von anderen Prozessen unterbrochen werden, da alle dieselbe Priorität haben. Nice-Level helfen nicht, da ein Prozess, der viel tut (der, der schnell sein muss), mit der Zeit immer weiter ausgebremst wird, um die anderen Prozesse mal ranzulassen. Wenn man das nicht will, muss man SCHED_FIFO oder SCHED_RR benutzen.
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Hallo Janka...
Dein Komentar war:
Ein Echtzeitprozess ist einer, der zumindest in bestimmten Anteilen unter SCHED_FIFO oder SCHED_RR läuft.
Ich programmiere Navigationsgerät das unter Linux arbeitet, um!
Wie bekomme ich das jetzt raus unter welchen Bedingungen der Echtzeitprozess arbeitet?
Was muss ich machen um an diese Information zu gelangen ?
Gruss macke_a
Dein Komentar war:
Ein Echtzeitprozess ist einer, der zumindest in bestimmten Anteilen unter SCHED_FIFO oder SCHED_RR läuft.
Ich programmiere Navigationsgerät das unter Linux arbeitet, um!
Wie bekomme ich das jetzt raus unter welchen Bedingungen der Echtzeitprozess arbeitet?
Was muss ich machen um an diese Information zu gelangen ?
Gruss macke_a
Du solltest in den Quellcode gucken. Da sollte irgendwo (hoffentlich auch entsprechend kommentiert) zumindest ein Aufruf von sched_setscheduler mit SCHED_FIFO oder SCHED_RR drin sein. Wenn nicht, muss du dir das Programm vornehmen, kapieren was es macht, evtll vorhandene Busy-Loops ausbauen und danach(!) dieses Programm um einen sched_setscheduler-Aufruf in main() ergänzen.
Janka
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Hallo !
Ein Aufruf von sched_setscheduler mit SCHED_FIFO oder SCHED_RR ist nicht in meinem Programm - code vorhanden!
Jetzt bleibt mir eigentlich nur noch die Möglichkeit den sched_setscheduler-Aufruf in main() selber zu verwirklichen. Oder was bleibt sonst noch an Möglichkeiten über?
Es nervt mich so langsam, das der Puffer meiner seriellen nicht schneller reagiert!
Mit Prioritäten etc.. kann ich auch keine nennenswerten Veränderungen hervorrufen?
Gruss macke_a
Ein Aufruf von sched_setscheduler mit SCHED_FIFO oder SCHED_RR ist nicht in meinem Programm - code vorhanden!
Jetzt bleibt mir eigentlich nur noch die Möglichkeit den sched_setscheduler-Aufruf in main() selber zu verwirklichen. Oder was bleibt sonst noch an Möglichkeiten über?
Es nervt mich so langsam, das der Puffer meiner seriellen nicht schneller reagiert!
Mit Prioritäten etc.. kann ich auch keine nennenswerten Veränderungen hervorrufen?
Gruss macke_a
Dann muss der da rein.macke_a hat geschrieben:Hallo !
Ein Aufruf von sched_setscheduler mit SCHED_FIFO oder SCHED_RR ist nicht in meinem Programm - code vorhanden!
Da ist er zumindest am einfachsten aufgehoben. Ich hab' mal vor Jahren ein EPROM-Programmierinterface am Parallelport zusammengelötet, da war dann nur eine einzelne Funktion mit nanosleep(10ms) zwischen SCHED_FIFO und SCHED_OTHER untergebracht, um eine Zelle im EPROM zu exakt 10ms lang zu programmieren.Jetzt bleibt mir eigentlich nur noch die Möglichkeit den sched_setscheduler-Aufruf in main() selber zu verwirklichen. Oder was bleibt sonst noch an Möglichkeiten über?
sched_setscheduler stellt erhöhte Prioritäten ein. Aber eben statische, keine dynamischen, wie man sie mit "nice" festlegen kann. Letztere sind nur Empfehlungen an den Scheduler, und wenn der Prozess viel tut, und der Rechner auch sonst ausgelastet ist, wird er halt dynamisch niedriger priorisiert. Selbst bei einem wenig ausgelasteten Rechner ist so eine Konstruktion immer wackelig -- Pfusch.Es nervt mich so langsam, das der Puffer meiner seriellen nicht schneller reagiert!
Mit Prioritäten etc.. kann ich auch keine nennenswerten Veränderungen hervorrufen?
Wenn du eine garantierte Antwortzeit benötigst, müssen die beteiligten Prozesse SCHED_FIFO oder SCHED_RR benutzen.
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Hallo Janka,
ich habe die folgenden Einstellungen bei mir in der Software gemacht:
void setprio()
{ struct sched_param *sch;
sch->sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, sch) != 0)
{ /* Fehler */ }
}
Dieses Unterprogramm rufe ich unmittelbar nach meiner main - Routine auf. Da ich eine Navigationssystem verwende und ich dieses dementsprechend nicht mit einem "normalen PC" vergleichen kann , habe ich jetzt das Problem das mein Programm beim aufrufen gar nicht mehr funktioniert bzw. das System anfängt instabil zu werden. Ich habe den Eindruck, das dieser Programm ihm zu viel Ressourcen wegnimmt!
Was kann ich jetzt machen ?
Das sched_priority = 1 habe ich bereits auf andere Werte (-19 bis + 19) gesetzt, allerdings habe ich immer wieder das selbe Problem. Meine selbst erstellten Programme auf dem Navi funktionieren nicht mehr!
Gibt es vielleicht eine andere sanfte Methode das mein Betriebssystem nicht so beeinflußt?
Gruss macke_a
ich habe die folgenden Einstellungen bei mir in der Software gemacht:
void setprio()
{ struct sched_param *sch;
sch->sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, sch) != 0)
{ /* Fehler */ }
}
Dieses Unterprogramm rufe ich unmittelbar nach meiner main - Routine auf. Da ich eine Navigationssystem verwende und ich dieses dementsprechend nicht mit einem "normalen PC" vergleichen kann , habe ich jetzt das Problem das mein Programm beim aufrufen gar nicht mehr funktioniert bzw. das System anfängt instabil zu werden. Ich habe den Eindruck, das dieser Programm ihm zu viel Ressourcen wegnimmt!
Was kann ich jetzt machen ?
Das sched_priority = 1 habe ich bereits auf andere Werte (-19 bis + 19) gesetzt, allerdings habe ich immer wieder das selbe Problem. Meine selbst erstellten Programme auf dem Navi funktionieren nicht mehr!
Gibt es vielleicht eine andere sanfte Methode das mein Betriebssystem nicht so beeinflußt?
Gruss macke_a
Ähem. Das mussmacke_a hat geschrieben:Hallo Janka,
ich habe die folgenden Einstellungen bei mir in der Software gemacht:
void setprio()
{ struct sched_param *sch;
sch->sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, sch) != 0)
{ /* Fehler */ }
}
Code: Alles auswählen
void setprio()
{
struct sched_param sch;
sch.sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, &sch) != 0)
{ /* Fehler */ }
}
Du musst das Programm hinsichtlich der Ressourcenverschwendung untersuchen! Bisher hat der Scheduler der Ressourcenverschwendung Einhalt geboten, indem er das Programm (wegen Ressourcenverschwendung) runtergewertet hat, mit statischer Priorität macht er das natürlich nicht mehr. Habe ich doch bereits oben geschrieben.Dieses Unterprogramm rufe ich unmittelbar nach meiner main - Routine auf. Da ich eine Navigationssystem verwende und ich dieses dementsprechend nicht mit einem "normalen PC" vergleichen kann , habe ich jetzt das Problem das mein Programm beim aufrufen gar nicht mehr funktioniert bzw. das System anfängt instabil zu werden. Ich habe den Eindruck, das dieser Programm ihm zu viel Ressourcen wegnimmt!
Was kann ich jetzt machen ?
Vermutlich wird im Programm ständig ein Eingang (serielle Schnittstelle z.B.) nichtblockierend auf Daten abgefragt, ohne danach eine "Schonzeit" zu warten, in der andere Prozesse mal den Prozessor benutzen dürfen.
Wenn dein Programm so aussieht:
Code: Alles auswählen
Scheife {
Timer hochzählen
Timer abgelaufen? Ja, dann raus mit Fehler
Nichtblockierendes Lesen
} bis Daten komplett gelesen
Code: Alles auswählen
Schleife {
select(Eingabegerät, Timer) abgelaufen? Ja, dann raus mit Fehler.
Nichtblockierendes Lesen
} bis Daten komplett gelesen
$ man select
$ man poll
Ähm. Du liest dir Manpages aber auch mal durch? Da steht eindeutig drin, dass Werte zwischen 0 und 99 erlaubt sind.Das sched_priority = 1 habe ich bereits auf andere Werte (-19 bis + 19)
Wenn dein Programm wackelig steht, ist es Unsinn, ein Haus drumrumzubauen, damit der Wind es nicht umpustet. Spätestens wenn jemand ein Fester aufmacht (sic!), fällt das Ding um.Gibt es vielleicht eine andere sanfte Methode das mein Betriebssystem nicht so beeinflußt?
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Hallo Janka...
Diesen Programmteil habe ich jetzt mit eingebunden:
Die Folge ist ein Absturz des Navi. Es erfolgt ein Software Reset nach Aufruf meines Programms.
Die Abfrage meines seriellen Schnittstelle erfolgt mittels
Der Timer steht auf 0 Sekunden Warte Zeit, d.h. nach dem Überprüfen aller spezifizierten Filedeskriptoren kehrt select sofort wieder zurück.
Der "select Code Teil" läuft in einer while(1) Schleife...
Vermutlich wird das ein Problem sein..??? Ich habe das aber extra gemacht, da meine empfangenden Daten in einem Zyklus von 10 - 50ms Sekunden kommen.
Ich will bzw. ich muss die Daten so schnell wie möglich auswerten!!
Ich glaube da könnte meine Probleme? Was meinst Du Janka ?
Gruss macke_a
Ach und erstmal besten Dank für Deine Mithilfe!!! Es mag zwar etwas schwierig mit mir sein, aber wenn man mit einem Linux BS noch nie umgegangen ist, braucht man jede Menge Starthilfe. Bücher sind Theorie, die Praxis ist dann doch anders!
[/code]
Diesen Programmteil habe ich jetzt mit eingebunden:
Code: Alles auswählen
void setprio()
{
struct sched_param sch;
sch.sched_priority = 1;
if (sched_setscheduler(0, SCHED_FIFO, &sch) != 0)
{ /* Fehler */ }
}
Die Abfrage meines seriellen Schnittstelle erfolgt mittels
Code: Alles auswählen
Schleife {
select(Eingabegerät, Timer) abgelaufen? Ja, dann raus mit Fehler.
Nichtblockierendes Lesen
} bis Daten komplett gelesen
Der "select Code Teil" läuft in einer while(1) Schleife...
Vermutlich wird das ein Problem sein..??? Ich habe das aber extra gemacht, da meine empfangenden Daten in einem Zyklus von 10 - 50ms Sekunden kommen.
Ich will bzw. ich muss die Daten so schnell wie möglich auswerten!!
Ich glaube da könnte meine Probleme? Was meinst Du Janka ?
Gruss macke_a
Ach und erstmal besten Dank für Deine Mithilfe!!! Es mag zwar etwas schwierig mit mir sein, aber wenn man mit einem Linux BS noch nie umgegangen ist, braucht man jede Menge Starthilfe. Bücher sind Theorie, die Praxis ist dann doch anders!
[/code]
Da liegt das Problem. Wenn du select sagst, es soll nicht warten, hast du eine busyloop. Bei SCHED_OTHER wird dein Prozess dadurch automatisch immer weiter runtergewertet. Du wirst dadurch also nicht schneller, sondern langsamer. Bei SCHED_FIFO kann mit so einer busyloop kein anderer Prozess mit normaler Priorität mehr arbeiten und der Rechner "steht". (Der Kernel und dein Prozess laufen aber noch). => Stell bei select() die tatsächliche Timeout-Zeit ein, also irgendwas *über* 50ms. Wenn die Daten früher anliegen, kommt auch select() früher zurück.
Du kannst dir auch eine Shell über einen Wrapper mit SCHED_FIFO noch etwas höher priorisieren als deinen Testprozess (danach execve("/bin/sh")), dann kannst du den Testprozess mithilfe dieser Shell abbrechen. Die Shell verhält sich bei SCHED_FIFO ordentlich, hat keine busyloops. Wie gehst du an das Gerät ran? Serielle Konsole oder Netzwerk? Im letzteren Fall muss du auch noch den sshd (oder telnetd etc) auf dem Gerät höher priorisieren, damit du es noch bedienen kannst, wenn dein Prozess Mist baut.
Janka
Du kannst dir auch eine Shell über einen Wrapper mit SCHED_FIFO noch etwas höher priorisieren als deinen Testprozess (danach execve("/bin/sh")), dann kannst du den Testprozess mithilfe dieser Shell abbrechen. Die Shell verhält sich bei SCHED_FIFO ordentlich, hat keine busyloops. Wie gehst du an das Gerät ran? Serielle Konsole oder Netzwerk? Im letzteren Fall muss du auch noch den sshd (oder telnetd etc) auf dem Gerät höher priorisieren, damit du es noch bedienen kannst, wenn dein Prozess Mist baut.
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.
Ich mag die Schreie.
Hallo Janka,
danke für die Info.
Ich arbeite jetzt mit einem Intervall von 100ms für den select Aufruf.
Jetzt habe ich noch ein weiteres anliegen.
Den select Aufruf habe ich in einer while Schliefe laufen. Ist das in Ordnung?
Oder wäre es besser einen Timer zu definieren, denn ich alle 100ms aufrufe?
Was ist Deine Meinung? Wie programmier ich dies am besten?
Ausschnitt while Schleife / Timer
Nochmals Vielen Dank für Deine Mithilfe!!
Gruss macke_a
danke für die Info.
Ich arbeite jetzt mit einem Intervall von 100ms für den select Aufruf.
Jetzt habe ich noch ein weiteres anliegen.
Den select Aufruf habe ich in einer while Schliefe laufen. Ist das in Ordnung?
Oder wäre es besser einen Timer zu definieren, denn ich alle 100ms aufrufe?
Was ist Deine Meinung? Wie programmier ich dies am besten?
Ausschnitt while Schleife / Timer
Code: Alles auswählen
wait.tv_sec = 0;
wait.tv_usec = 10000;
FD_SET(fd1,&rt);
FD_SET(fd2,&wt);
select(fd1 + fd2 1,&rt,&wt,NULL,&wait);
if(FD_ISSET(fd1i,&rt)) { InitPipe(); }
if(FD_ISSET(fd2,&wt)) { }
Nochmals Vielen Dank für Deine Mithilfe!!
Gruss macke_a