www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Frage zur Code-Optimierung


Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Randy N. (huskynet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 :-)

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Randy N. (huskynet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

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.

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, hinter dem OPTIMIZE verbirgt sich die -Os Option. Ich werde das 
mit den verschiedenen Compiler-Optionen mal ausprobieren.

Danke.

Gruß
Werner

Autor: I_ H. (i_h)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum hast du die beiden globalen Variablen denn als volatile 
deklariert?

Autor: chris (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!!!!!

   ...

}

Autor: DerSchelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Werner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: gAST (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo  Werner,

wieso benutzt Du nicht einfach einen 7,373 bzw 14,746 MHz Quarz?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.