Forum: Mikrocontroller und Digitale Elektronik MCU zu langsam für mehrere Interrupts?


von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von thkaiser (Gast)


Lesenswert?

Das kann vieles sein:
Seiteneffekte durch mehrfach genutzte Register (passiert schon mal , daß 
man ein Register nicht pusht/popt)
Tatsächliche Timing-Probleme - dann könnte es sein, daß ein 
Register-Inhalt überschrieben wird, bevor der vorhergehende fertig 
gesendet ist.
Oftmals hilft da Optimierung oder ein Umdenken.
Ich hatte beispielsweise das Problem, daß eine I²C-Routine im 
Zusammenhang mit Software-PWM nicht mehr so richtig wollte. Ein wenig 
umschreiben, eine Art von Interrupt-Priorisierung und schon klappte 
es....
Evtl. die Interruptroutinen kürzen und mehr ins Hauptprogramm.
Ohne mehr Info ist es allerdings schwer, weitergehende Vorschläge zu 
machen.

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Bist du sicher dass du ein Softwareproblem hast? "rotierender Trafo" 
hört sich jedenfalls schon mal ziemlich abenteuerlich an. Funktioniert 
die Übertragung fehlerfrei wenn die anderen Interrupts deaktiviert sind?

Wenn ein Interrupt auftritt wird das entsprechende Statusbit gesetzt, 
die Abarbeitung erfolgt dann sobald eine evtl. gerade laufende 
Interruptroutine wieder beendet ist. Die Priorität der Abarbeitung 
entspricht der Reihenfolge der Interruptvektoren im Datenblatt. 
"Verloren" geht in Int nur dann, wenn schon ein anderer des gleichen 
Typs in der Warteschlange sitzt. Deshalb ist es grundsätzlich wichtig, 
die Interruptroutinen möglichst kurz zu halten, damit erst gar keine 
längeren "Warteschlangen" entstehen.

Wenn man einen selten auftretenden Interrupt mit langer Bearbeitungszeit 
hat und einen der sehr oft auftritt, dann kann man bei dem langsamen am 
Anfang der Int.routine mit "sei" die Interrupts wieder aktivieren, so 
dass die Routine durch den schnellen Interrupt unterbrochen werden kann.

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von thkaiser (Gast)


Lesenswert?

In so zeitkritischen Geschichten sollte man vielleicht kein C verwenden 
- manchmal gehts halt doch nicht ohne Assembler.

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Peter D. (peda)


Lesenswert?

Ich denke auch, daß da irgendein Interrupt zu lange dauert. In C sieht 
man eben nicht mehr, wie teuer in Bezug auf Rechenzeit bestimmte 
Instruktionen sind.

Beim 8051 ist das auch leichter zu entschärfen, da man dort 2-4 
verschiedene Prioritätsstufen vergeben kann. D.h. ein schneller 
Interrupt kann einen langsamen unterbrechen ohne das es Probleme gibt.

Beim AVR muß man das simulieren, indem ein langsamer Interrupt zuerst 
sich selber sperrt, damit er sich nicht versehentlich wieder selbst 
aufruft und dann die Interupts global wieder freigegeben werden. Wenn er 
dann durch eine weiteren langsamen unterbrochen werden könnte, muß 
dieser es genau so machen.
Vor dem Verlassen des Interrupts muß dann alles wieder rückgängig 
gemacht werden.


Zu langsam dürfte Deine CPU aber in keinem Fall sein.
Vielleicht kannst Du ja Deinen Kode als Anlage anhängen, damit man mal 
sehen kann wo die Rechenleistung verpulvert wird.


Peter

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von crazy horse (Gast)


Lesenswert?

ein paar einfache Tips, um die ISRs schneller zu machen:
-reserviere eine char Variable im C Programm mit fester Adresse
unsigned char sreg_bak @R3;
gibt zwar ne Warnung beim Compilerlauf (never used bla bla), ignorieren.
Des weiteren schaust du dir das erzeugte Assembleristing genau an und 
sicherst nur die Register, die wirklich verändert werden, der Compiler 
geht meist mit dem groben Besen drüber und sichert alle allgemeinen 
Register, auch wenn du in der ISR nur 2 benutzt. Das ist doppelt 
ärgerlich, da natürlich alle gesicherten Register wieder gepopt werden, 
dazu kommt je ein call für die Sicherungs- bzw. 
Wiederherstellungsroutine.
Beispiel: du siehst im Listing, daß nur R10, R11, R30,R31 benutzt 
werden.
Deine ISR sieht dann so aus:
#pragma savereg-   //nicht automatisch sichern
void interrupt isr1 (void) {
#asm
 in R3, sreg
 push r10
 push r11
 push r30
 push r31
#endasm
das eigentliche ISR in C
#asm
 pop r31
 pop r30
 pop r11
 pop r10
 out sreg, r3
#endasm
}
ist natürlich nur ein Beispiel, wie es exakt realisiert wird, hängt vom 
Compiler und deinem Programm ab. sreg_bak kannst du in allen ISR 
benutzen, wenn du keine verschachtelten Interrupts benutzt.
Ansonsten die allgemeinen Regeln beachten, möglichst kurze Laufzeit der 
ISR, nur das Ereignis in irgendeiner Art speichern, die Verarbeitung 
dann im Hauptprogramm.

von geloescht (Gast)


Angehängte Dateien:

Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Peter D. (peda)


Lesenswert?

Ja, die Division int/3 dürfte am meisten CPU-Zeit fressen. Divisionen 
sind mit Abstand das teuerste.

Auch kann man im Compare-Modus den Timer automatisch löschen lassen, 
dann muß man nicht immer OCR1 neu laden.


Peter

von crazy horse (Gast)


Lesenswert?

und die Display-routine würde ich auch aus der ISR verbannen.
In der ISR:
display_ready=1;  //Bitvariable


Im Hauptprogramm dann:
 while (!display_ready);
 display_ready=0;
 display();

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Peter D. (peda)


Lesenswert?

Die 2. Nutzung von T1 hatte ich übersehen, dann ist es ohne "clear on 
compare" besser.


Woher kommt denn diese magische 378 ?
Ich würde ja durch 60 teilen (60 Minuten).
Die Division sollte man dann aber im main() machen, ist ja egal, wann 
die fertig ist.

Wozu ist denn das Lap gut ?


Und in Interrupts nur das static bzw. global, wo der Wert auch wirklich 
das nächste mal bzw. woanders gebraucht wird.
Kostet dich ja jedesmal 8 Byte Flash, 6 Zyklen je char variable (=16,12 
je int).


Peter

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Ich hätte hier noch nen Vorschlag, das Ganze einfach als PLL zu machen.
Der T1 arbeitet mit "clear on compare" und der Wert von OCR1 wird 
solange nachgeführt, bis der Synchronimpuls genau in der Mitte des 
letzen Displaypunktes display_mem[59] erfolgt.

Die Daten für alle 60 Zeigerstellungen werden in display_mem[] abgelegt, 
das kann z.B. in aller Ruhe im main erfolgen.

Je nachdem, wie genau man den Startwert von OCR1 setzt, dreht sich die 
Uhr nach dem Einschalten, bis sie in der richtigen Position einrastet.


Peter

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Kalle (Gast)


Lesenswert?

Hallo Guido,

Frage: wo hast du die Schaltung/Platine/Anleitung zu dem tollen Projekt 
den her. Sieht toll aus....

mfg Karl

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von Peter D. (peda)


Lesenswert?

@Guido,

bei 8MHz, 50U/s und 120 Pixel dauert 1 Pixel 1333 Takte.
Die Änderung von OCR1 wirkt sich ja 120-fach aus, d.h. +/-120 Takte.

Soltest Du allerdings einen Vorteiler 1/8 nehmen, ist ein Pixel nur 167 
T1-Takte lang und dann sind 120 Takte schon sehr viel.

Man kann aber auch noch feiner synchronisieren, indem man immer ab einer 
bestimmten Position OCR1 um 1 verringert und am Nullpunkt wieder erhöht.
Diese Position wird dann im Synchronisationsinterrupt hoch- bzw. 
runtergezählt und bei >=120 bzw. <0 wird erst OCR1 geändert.


Peter

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

von geloescht (Gast)


Lesenswert?

Dieser Beitrag wurde auf Wunsch des Autors geloescht.

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.