Hallo zusammen, ich wäre sehr daran interessiert, die folgenden Codefragmente etwas performanter zu lösen. Die beiden Berechnungen brauchen in der Form wie ich sie zur Zeit programmiert habe fast 500 us auf einem ATMega8 mit 3,686 MHz Quartz. Kann ich hier evtl. mit geschickten Shift-Operationen die Sache etwas schneller berechnen? Mir fehlt auf diesem Gebiet sicherlich einiges an Erfahrung. ... #define COUNTER_INCS_PER_MILLISECOND_T1 461 // (3.686.400 / 8) / 1000 volatile unsigned long ulAktuelleUmlaufzeitG=0; volatile unsigned long ulAktuelleDrehzahlG=0; ISR(INT0_vect) { ... ulAktuelleDrehzahlG = 600000UL / (ulAktuelleUmlaufzeitG*10 / COUNTER_INCS_PER_MILLISECOND_T1); ... unsigned int uiTableIndex = ulAktuelleDrehzahlG / 50; ... } Gruß Werner
Solltest du noch nicht haben, versuche mal in den Projektoptionen die Compileroptimierung aufs Höchste zu stellen - was optimierbar ist (Shifts z.B.) macht der Compiler dann automatisch für dich. Ansonsten wüsste ich nicht, was man optimieren kann (das macht alles schon der Compiler). Ich weiß nicht ob es möglich ist, aber kannst du vielleicht aus den Longs Integers machen? Das würde einiges bringen (fast die Hälfte, geschätzt). Aber das wird sicherlich nicht gehen, sonst wären es ja schon Ints :-)
Danke Randy für den Hinweis. Im Makefile benutze ich z.Zt. die folgenden Einstellungen: CC = avr-gcc CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS) LDFLAGS = -Wl,-Map,$(PRG).map Ich bin mir aber nicht sicher, ob das schon das Maximum an Codeoptimierung ist. Gruß Werner
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Optimierungsgrad Ich weiß nicht in welcher Form das jetzt schon in dem Makefile steckt, aber sowas wie -Os müsste da z.B. noch rein. Einfach mal die Zeiten für die verschiedenen Optimierungsgrade testen, wobei der kompakteste Code meistens nicht der Schnellste ist. Kommt drauf an.
Sorry, hinter dem OPTIMIZE verbirgt sich die -Os Option. Ich werde das mit den verschiedenen Compiler-Optionen mal ausprobieren. Danke. Gruß Werner
Warum hast du die beiden globalen Variablen denn als volatile deklariert?
Schreib das ganze doch mal wie folgt, dann sparst du eine Division und eine Multiplikation: #define COUNTER_INCS_PER_MILLISECOND_T1 461 #define TIME_TO_RPM_CONST (60000L * COUNTER_INCS_PER_MILLISECOND_T1) // (600000 * COUNTER_INCS_PER_MILLISECOND_T1) / 10 ISR(INT0_vect) { ... ulAktuelleDrehzahlG = TIME_TO_RPM_CONST / ulAktuelleUmlaufzeitG; ... unsigned int uiTableIndex = ulAktuelleDrehzahlG / 50; ... } Wenn der Wert für ulAktuelleDrehzahlG etwas ungenauer sein darf, kann man noch eine Division sparen und schreiben: #define COUNTER_INCS_PER_MILLISECOND_T1 461 #define TIME_TO_RPM_CONST (1200 * COUNTER_INCS_PER_MILLISECOND_T1) // (600000 * COUNTER_INCS_PER_MILLISECOND_T1) / ( 10 * 50) ISR(INT0_vect) { ... unsigned int uiTableIndex = TIME_TO_RPM_CONST / ulAktuelleUmlaufzeitG; ... ulAktuelleDrehzahlG = 50 * uiTableIndex; // da zuerst die Division ausgeführt wird, treten hier Rundungsfehler auf!!!!! ... }
Wenn Dein Compiler nicht expilizit eine Division kann, dann ist die Division sehr sehr sehr teuer. Darin denke ich, liegt der Grund für Deine langen Zeiten. Also: Nicht durch 50 teilen, sondern die Division durch eine Multiplikation und anschließende Teilung durch eine Zweierpotenz (shiften) ersetzen. Wieso multiplizierst Du mit 60000 und teilst dann durch 50 (also nur mit 1200 multiplizieren)? Macht der Compiler wirklich eine Division zur Laufzeit daraus (schau mal ins LST-File)? An der Division würde ich den Optimierungshebel ansetzen.
Werner wrote: > Die beiden Berechnungen brauchen in der Form wie > ich sie zur Zeit programmiert habe fast 500 us auf einem ATMega8 mit > 3,686 MHz Quartz. Erklär dochmal, was Dich an den 500µs stört. Warum brauchst Du die Ergebnisse schneller als 500µs? Wie groß ist die Tabelle, die Du damit adressierst? Eventuell reicht ja eine Berechnung mit 8Bit aus. Du machst insgesamt 3 Divisionen mit 3 Konstanten. Fasse mal alle 3 Konstanten zusammen und mache nur eine Division. Bzw. wenn Du nur ne Tabelle zugreifen willst, sollte es auch ganz ohne Division gehen. Peter
Wie wäre es mit einer intelligenteren Optimierung? Wenn ich das richtig sehe möchtest du die Drehzahl ermitteln, wahrscheinlich per Interrupt indem du die Ticks pro Zeiteinheit zählst. Die Berechnung ist also NUR NÖTIG wenn du die Drehzahl wirklich abfragst. Zähle in der Interruptroutine nur die Ticks und dort wo du die Drehzahl brauchst(im Hauptprogramm) berechnest du sie. Damit dürfte die Interruptzeit von 500us (wirklich so viel?) auf 2us fallen und du sparst dir zusätzlich noch eine ganze Menge unnötige Berechnungen.
Hallo zusammen, vielen Dank für zahlreichen hervorragenden Tipps, die ich gleich heute Abend umsetzen werde. Bin schon wirklich gespannt, um wieviel sich die ursprüngliche Zeit zusammenkürzen läßt. @I_H.: >Warum hast du die beiden globalen Variablen denn als volatile >deklariert? Die beiden globalen Variablen benutze ich sowohl in Interruptroutinen als auch im Hauptprogramm. Gesetzt werden sie allerdings nur in der Interruptroutine und bei der globalen Initialisierung. Ich war mir ehrlich gesagt nicht ganz sicher, ob ich hierfür das "volatile" nun zwingend angeben muß oder nicht. @Peter Danneger: >Erklär dochmal, was Dich an den 500µs stört. >Warum brauchst Du die Ergebnisse schneller als 500µs? > >Wie groß ist die Tabelle, die Du damit adressierst? >Eventuell reicht ja eine Berechnung mit 8Bit aus. Na ja, das Ganze ist eine variable Zündsteuerung für einen Zweitakt-Motor. Der erste Geber-Impuls (PickUp) wird 72° Grad vor OT ausgelöst und aktiviert den Interrupt, der die aktuelle Drehzahl berechnet und dann davon abhängig einen Timer-Wert (Delay) aus einer Tabelle ausliest. Nach Ablauf des Timers wird dann der eigentliche Zündimpuls ausgelöst. Bei Drehzahlen > 10.000 U/Min wird bei 500us Berechnungszeit für den Timer die Luft für den Einstellungsspielraum schon ziemlich dünn. Die Tabelle enthält 256 Werte und ich werde Deinen Tipp beherzigen und auf eine 8Bit-Berechnung umstellen. Ich denke, dass sich alle Tipps gut umsetzen lassen. Nochmals Danke an Alle. Gruß Werner
Hallo Werner, wieso benutzt Du nicht einfach einen 7,373 bzw 14,746 MHz Quarz?
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.