Hallo, ich habe einen Atmega32 mit 1 MHz auf einem STK-600 laufen. Der Takt kommt vom STK-600, am XTAL1 kann ich per Ossi ca. 1 MHz messen. Habe nun folgenden simplen Code übersetzt (mit AVR Studio 5 Optimierung -O1) dann zum Atmega32 übertragen: int main(void) { DDRD |= 0x04; // Bit 2 auf Ausgang setzen; while(1) { PORTD ^= ( 1 << PD2 ); // PD2 toggeln } } Wenn ich nun an Pin 2 von PortD messe, bekomme ich 'nur noch' 66 kHz angezeigt. Wenn ich mit -O3 kompiliere ändert sich nichts. Warum kommt von dem 1Mhz bei so simplen Code keine höhere Frequenz am PD2 an? Ist der Compiler nicht effizient oder mache ich einen Denkfehler? Danke für Infos!
Schau Dir mal den Assembler-Code an, im Simulator, dann wießt Du was das Ding in Wirklichkeit tut. (Sofern das Studio 5 noch anbietet)
67kHz sind 7 Zyklen pro Schleifendurchlauf. Das ist für eine RISC-CPU ganz o.k. Mit -Os solltest Du etwas besser werden. Andere Optimierungen sollte man nur dann nehmen, wenn man auch weiß warum. Peter
Mr.Burns schrieb: > PORTD ^= ( 1 << PD2 ); // PD2 toggeln Diese Zeile enthält eine ganze Menge mehr als es auf den ersten Blick aussieht. Aufgespalten auf einzelne Befehle sieht das in etwa so aus: ( ist jetzt nicht speziell auf AVR's geschrieben, dafür kenne ich die Teile zu wenig) 1. Lade "PORTD" in ein Register ( Sollte 1 Assembler Intruction sein ) 2. Lade "1" in ein Register ( Sollte 1 Assembler Intruction sein ) 3. Lade "PD2" in ein Register ( Sollte 1 Assembler Intruction sein ) 4. Schiebe "1" um eine Stelle nach Links und erhöhe den Zähler ( Sollte 1 oder 2 Assembler Intruction(s) sein ) 5. Vergleiche Zähler mit Register "PD2" ( Sollte 1 Assembler Intruction sein ) 6. Sprung nach 4. oder nach 7. ( Sollte 1 Assembler Intruction sein ) 7. ^ Operation auf Register "PORTD" mit Register "1" ( Sollte 1 Assembler Intruction sein ) 8. Schreibe Register "PORTD" nach der Adresse für "PORTD" Also ich komme da im günstigsten Fall auf 8 Instructions. ==> 1 MHz / 8 = 125 KHz am Ausgang. Dazu kommt noch die While(1) Loop mit idealerweise einer Instruction. ==> also noch 1 MHz / 9 = 111 KHz Je nachdem wie groß der Wert PD2 ist, kommen die entsprechenden Wiederholungen für die Punkte 4 - 6 hinzu. Wenn du dir jetzt das Assemblerlisting in deiner IDE ansiehst, wirst du etwas ähnliches wie meine Punkte finden.
Ralph, (1 << PD2) ist für den Compiler eine Konstante, dafür wird kein Code erzeugt, der etwas nach links schiebt. Poste mal den Assemblercode. Ist evtl. die Fuse CKDIV8 gesetzt?
das sollten bei "-O3" 5 ticks sein (*2) also 100kHz
1 | PORTD ^= ( 1 << PD2 ); // PD2 toggeln |
2 | c0: 94 e0 ldi r25, 0x04 ; 4 |
3 | c2: 82 b3 in r24, 0x12 ; 18 |
4 | c4: 89 27 eor r24, r25 |
5 | c6: 82 bb out 0x12, r24 ; 18 |
6 | c8: fc cf rjmp .-8 ; 0xc2 <main+0x4> |
Mr.Burns schrieb: > Danke erstmal für die Antworten, wie prüfe ich ob CKDIV8 gesetzt ist in > AVR Studio 5? Deine Mainloop dauert nur 7 Zyklen, also kann sie nicht gesetzt sein. Peter
@Sebastian: rjmp braucht 2 Zyklen, also insgesamt 6. Dafür aber 2 Register. Mit sbic/sbis und sbi/cbi komme ich auch auf 7, ohne Registernutzung.
Oliver schrieb: > (1 << PD2) ist für den Compiler eine Konstante, dafür wird kein Code > erzeugt, der etwas nach links schiebt. Erstmal ist das eine Anweisung die zur Laufzeit ausgeführt wird und KEINE Konstante. Wenn der Compiler erkennen kann, das PD2 eine Konstante ist, kann unter Umständen diese Anweisung zur Compilezeit berechnet und als Konstante in den Code eingefügt werden. Das muss aber nicht so sein. Aus dem Ursprungspost geht nicht hervor ob "PD2" eine Konstante oder eine Variable ist.
Ralph schrieb: > Wenn der Compiler erkennen kann, das PD2 eine Konstante ist natürlich kann er das. Es ist ein Symbol, dass er auflösen muss und wo 2 rauskommt Kann er das nicht, gibts einen Fehler zur Compile-Zeit > , kann unter > Umständen diese Anweisung zur Compilezeit berechnet und als Konstante in > den Code eingefügt werden. sobald irgend eine optimierung angeschaltet ist wird das ersetzt.
Ralph schrieb: > Erstmal ist das eine Anweisung die zur Laufzeit ausgeführt wird und > KEINE Konstante. > [...] > Aus dem Ursprungspost geht nicht hervor ob "PD2" eine Konstante oder > eine Variable ist. Erst so sicher, und dann doch wieder nicht? Ja, PD2 ist eine Konstante, nein, natürlich kannst du es nicht wissen, wenn du dich nicht mit dem AVR-GCC auseinander setzt, und nein, das wäre an sich auch kein Problem, aber dann bitte auch die Füße stillhalten falls dich jemand korrigiert.
Hallo, danke erstmal an alle hier! PD2 ist wie folgt definiert: #define PD2 2 (aus C:\Programme\Atmel\AVR Studio 5.0\AVR ToolChain\avr\include\avr\iom32.h (542): #define PD2 2 ) Ich weiß aber immernoch nicht, wie ich auslesen kann, ob ich einen Vorteiler verwende. Habe mal einen Screenshot von den Fuses im AVR Studio 5 gemacht. Wo sehe ich nun dort den Vorteiler? Danke!
Der Mega32 hat noch gar keinen Vorteiler für den µC Takt. Den gibt es dann beim neueren, sonst ähnlichen Mega324. Prüfen ob CLKDIV8 gestetzt ist kann man durch auslesen der Fuses mit dem dem Programmer. Wie das angezeigt wird hängt von der Software ab mit der man den Programmer steuert.
MrBurns schrieb: > Wo sehe ich nun dort den Vorteiler? Der Mega32 hat keine CKDIV8 Fuse (siehe Datenblatt, in dem stehen alle Fuses und auch speziell diejenigen, die die Taktfrequenz des µC betreffen). Also kann die auch nicht eingeschaltet sein. (*) DU hast also keinen 'Vorteiler'. Wenn dein µC mit einem 1Mhz Quarz getaktet wird, dann läuft der auch mit 1Mhz. Hängst du einen 16MHz QUarz und (und sind die Fuses so, dass der auch benutzt wird), dann läuft der auch mit 16Mhz. * Zur Not kann man auch darauf vertrauen, dass das Brennprogramm alle Fuses einbes speziellen Prozessors kennt.
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.