www.mikrocontroller.net

Forum: Compiler & IDEs Optimierung bei if-Abfrage mit kurzem Rumpf


Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Moin moin,

Ich möchte mit folgendem C-Code-Schnipsel für ATMega8 ein Signal 
generieren:
ISR(TIMER0_OVF_vect)
{
  uint16_t temp = outputValue; // global deklariert
  for(uint8_t i=16; i>0 i--)
  {
    if(temp & (1<<15))
    {
      SDA_PORT |= (1<<SDA_PIN);
    }
    else
    {
      SDA_PORT ~= (1<<SDA_PIN);
    }
    // toggle clock
    SCL_PORT &= ~(1<<SCL_PIN);
    SCL_PORT |= (1<<SCL_PIN);
    
    // next bit
    temp <<= 1;
  }
}

Wird soweit mit -Os ganz nett übersetzt in sbi, cbi etc. Nur die 
if-else-Abfrage mit den extrem kurzen Schleifenrümpfen (1 
Assembler-Befehl) würde ich in Assembler schneller und vor allem immer 
gleich schnell hinbekommen - das Ergebnis ist nämlich:
  sbrs r25,7
  rjmp .L6
  sbi 53-0x20,4
  rjmp .L7
.L6:
  cbi 53-0x20,4
.L7

Das dauert in Zyklen 2(sbrs)+1(sbi)+2(rjmp) für gesetzt, 
1(sbrs)+2(rjmp)+1(cbi) für gelöscht.

Ich würde sowas schreiben wie:
  sbrs r25,7
  cbi 53-0x20,4
  sbrc r25,7
  sbi 53-0x20,4

Das dauert in Zyklen 2(sbrs)+1(sbrc)+1(sbi) für gesetzt, 
1(sbrs)+1(cbi)+2(sbrc) für gelöscht - und etwas kleiner ist der Code 
auch noch...

Ist das
a) ein Fall für inline-Assembler?
b) in neueren Versionen von avr-gcc besser geworden (aktuell hier 
4.3.3)?

Oder gibt es eine geschicktere Variante, das in C zu schreiben? Zwei 
getrennte if-Abfragen (einmal auf gesetzt, einmal auf gelöscht) habe ich 
ausprobiert, kompiliert zu dem gleichen Code wie die Variante mit 
if-else - obwohl eine einzelne if-Abfrage auf gelöscht den gleichen Code 
erzeugt wie meine Assembler-Variante.

Oder verrechne ich mich hier gerade und der gcc-Code ist genauso schnell 
wie meiner?

Hat ein Bugreport einen Sinn? Wenn ja, wo?

MfG, Heiko

P.S: Es kommt mir hier nicht nur auf den einen (halben) Zyklus an, 
sondern viel mehr darauf, dass ich gerne high- und low-Bytes gleich lang 
hätte...

Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Heiko schrieb:
> P.S: Es kommt mir hier nicht nur auf den einen (halben) Zyklus an,
> sondern viel mehr darauf, dass ich gerne high- und low-Bytes gleich lang
> hätte...

Bei deiner handgeschriebenen Variante sind die Bits doch auch nicht 
gleich lang. Die Gesamtdurchlaufzeit ist zwar in beiden Fällen gleich, 
aber cbi und sbi liegen relativ zum Funktionsanfang an unterschiedlichen 
Zeitpunkten. (von der nicht konstanten Interrupt-Latenz mal ganz zu 
schweigen)

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Heiko
Bugreport mit deinem fehlerhaften (zwei Fehler) Code?
Ich schmeiß mich weg;)

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich merke schon, mal eben schnell etwas abtippen sollte man nicht kurz 
vor Feierabend machen...

Extra für holger der (hoffentlich jetzt vollständig) fehlerkorrigierte 
Code:
ISR(TIMER0_OVF_vect)
{
  uint16_t temp = outputValue; // global deklariert
  for(uint8_t i=16; i>0; i--)
  {
    if(temp & (1<<15))
    {
      SDA_PORT |= (1<<SDA_PIN);
    }
    else
    {
      SDA_PORT &= ~(1<<SDA_PIN);
    }
    // toggle clock
    SCL_PORT &= ~(1<<SCL_PIN);
    SCL_PORT |= (1<<SCL_PIN);
    
    // next bit
    temp <<= 1;
  }
}

Stefan: Du hast Recht, die Dauer des High- bzw. Low-Pegels ist auch bei 
meiner Variante unterschiedlich - da die Kommunikation aber synchron 
abläuft, ist das nicht entscheidend. Wäre eben schön, wenn der Optimizer 
noch dieses bisschen besser optimieren würde...

MfG, Heiko

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Machs doch einfach so:

ISR(TIMER0_OVF_vect)
{
  uint16_t temp = outputValue; // global deklariert
  for(uint8_t i=16; i>0; i--)
  {
    SDA_PORT &= ~(1<<SDA_PIN);
    if(temp & (1<<15))
    {
      SDA_PORT |= (1<<SDA_PIN);
    }
    // toggle clock
    SCL_PORT &= ~(1<<SCL_PIN);
    SCL_PORT |= (1<<SCL_PIN);
    
    // next bit
    temp <<= 1;
  }
}


Peter

Autor: Heiko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Machs doch einfach so:fasdf

kopfklatsch natürlich :)

MfG, Heiko

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.