Dieser Beitrag wurde auf Wunsch des Autors geloescht.
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.
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.
In so zeitkritischen Geschichten sollte man vielleicht kein C verwenden - manchmal gehts halt doch nicht ohne Assembler.
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
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.
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
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();
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
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
Hallo Guido, Frage: wo hast du die Schaltung/Platine/Anleitung zu dem tollen Projekt den her. Sieht toll aus.... mfg Karl
@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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.