IRQ Serielle Schnittstelle

Message
Author
macke_a

IRQ Serielle Schnittstelle

#1 Post by macke_a »

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

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#2 Post by Janka »

Ist das ein Echtzeitprozess? Wenn nein, kannst du dich nicht auf ein bestimmtes Zeitraster verlassen.

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

macke_a

#3 Post by macke_a »

Hallo Janka,
was verstehst bzw. wie definierst Du Echtzeitprozess ?

macke_a

#4 Post by macke_a »

Hallo !?

Hat denn keiner eine Idee, wie ich mein Problem des langsamen Puffers entgegen wirken kann ? Was soll man verändern, damit der Puffer sich schneller meldet?

Gruss macke_a

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#5 Post by Janka »

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
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

macke_a

#6 Post by macke_a »

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

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#7 Post by Janka »

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
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

macke_a

#8 Post by macke_a »

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

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#9 Post by Janka »

macke_a wrote:Hallo !
Ein Aufruf von sched_setscheduler mit SCHED_FIFO oder SCHED_RR ist nicht in meinem Programm - code vorhanden!
Dann muss der da rein.
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?
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.
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?
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.

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.

macke_a

#10 Post by macke_a »

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

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#11 Post by Janka »

macke_a wrote: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 */ }
}
Ähem. Das muss

Code: Select all

void setprio()
{
  struct sched_param sch;
  sch.sched_priority = 1;

  if (sched_setscheduler(0, SCHED_FIFO, &sch) != 0) 
     { /* Fehler */ }
}
heißen. Dein Code erzeugt im besten Fall einen SIGSEGV, im schlechtesten überschreibt er irgendwas wichtiges. Lies dir erstmal ein Buch zu C durch!
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 ?
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.

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: Select all

Scheife {
 Timer hochzählen
 Timer abgelaufen? Ja, dann raus mit Fehler
 Nichtblockierendes Lesen
} bis Daten komplett gelesen
hast du eine schöne Busy-Loop gebastelt. Die macht das System immer langsam. So muss das aussehen:

Code: Select all

Schleife {
 select(Eingabegerät, Timer) abgelaufen? Ja, dann raus mit Fehler.
 Nichtblockierendes Lesen
} bis Daten komplett gelesen
Dann kann der Kernel, während der Prozess im select() wartet, den Prozessor einem anderen Prozess zuteilen.

$ man select
$ man poll
Das sched_priority = 1 habe ich bereits auf andere Werte (-19 bis + 19)
Ähm. Du liest dir Manpages aber auch mal durch? Da steht eindeutig drin, dass Werte zwischen 0 und 99 erlaubt sind.
Gibt es vielleicht eine andere sanfte Methode das mein Betriebssystem nicht so beeinflußt?
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.

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

macke_a

#12 Post by macke_a »

Hallo Janka...
Diesen Programmteil habe ich jetzt mit eingebunden:

Code: Select all

void setprio()
{
  struct sched_param sch;
  sch.sched_priority = 1;

  if (sched_setscheduler(0, SCHED_FIFO, &sch) != 0)
     { /* Fehler */ }
} 
Die Folge ist ein Absturz des Navi. Es erfolgt ein Software Reset nach Aufruf meines Programms.

Die Abfrage meines seriellen Schnittstelle erfolgt mittels

Code: Select all

Schleife {
 select(Eingabegerät, Timer) abgelaufen? Ja, dann raus mit Fehler.
 Nichtblockierendes Lesen
} bis Daten komplett gelesen 
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]

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#13 Post by Janka »

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
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

macke_a

#14 Post by macke_a »

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

Code: Select all

      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

macke_a

#15 Post by macke_a »

Sorry, kleiner Druckfehler

wait.tv_usec = 100000;

if(FD_ISSET(fd1,&rt)) { InitPipe(); }

Post Reply