Die Größe des globalen Arrays beeinflusst die Taktfrequenz nur unter Linux (avr-gcc)

Ich habe das merkwürdigste Problem. Wenn sich die Größe eines globalen Arrays ändert, ändert es die Taktfrequenz des ATmega164a. Dies ist unter Linux. Bei der Kompilierung unter Windows tritt dieses Problem nicht auf (unabhängig davon, ob die .hex-Datei tatsächlich auf dem ATmega164a in Windows oder Linux programmiert ist, alias ich vermute nicht, dass avrdude zu diesem Problem beiträgt). Ich habe sogar unter Linux die genauen Befehle ausgeführt, die von AVR Studio ausgeführt werden, um das Ziel zu erstellen, und bin immer noch auf dieses Problem gestoßen.

Die CLKDIV8-Sicherung ist nicht gesetzt, und die interne RC-Sicherung ist gesetzt, sodass der ATmega164a mit 8 MHz nominal laufen sollte.

Dies ist das minimal funktionierende Beispiel für den Code, der korrekt ausgeführt wird:

#include <avr/io.h> 
uint8_t bytes[6]; 
int main(void){ 
    DDRB = (1<<PB5); 

    while(1){ 
        PORTB |= (1<<PB5); 
        PORTB &= ~(1<<PB5); 
    } 
}

Ein Oszilloskop zeigt, dass der resultierende Impuls 250 ns breit ist (2 Zyklen).

Das Erhöhen der globalen Array-Größe um eins führt jedoch zu einem merkwürdigen Verhalten.

#include <avr/io.h> 
uint8_t bytes[7]; 
int main(void){ 
    DDRB = (1<<PB5); 

    while(1){ 
        PORTB |= (1<<PB5); 
        PORTB &= ~(1<<PB5); 
    } 
}

Ein Oszilloskop zeigt diese Impulsbreite als 444 ns an, und die Zeit zwischen den Impulsen nimmt im gleichen Verhältnis zu, was anzeigt, dass die Taktfrequenz abgenommen hat.

Ich habe keine Ahnung, wohin ich von hier aus gehen soll. Ich habe sehr lange gebraucht, um es auf dieses minimal funktionierende Beispiel einzugrenzen. Ich habe mein Makefile in pastebin eingefügt .

BEARBEITEN

Hier sind die Auflistungsdateien für die beiden Fälle. bytes[6]: pastebin bytes[7]: pastebin

Ich habe mit einem 16-Bit-Timer überprüft, dass die Taktfrequenz tatsächlich um den zuvor angegebenen Faktor abnimmt (250 ns -> 444 ns).

Posten Sie die Montageliste für beide Fälle.
Dies ist keine besonders zuverlässige Methode zur Messung der Taktfrequenz. Benutze vielleicht einen Timer mit Max. Prescaler und setze es auf Toggle oben oder was hast du und miss das. Sie sind dann nicht von Compiler-Macken betroffen.
@ThePhoton weist darauf hin, dass die Assembler-Liste im Wesentlichen nur 1 Zeile Unterschied aufweist. 0x66 -> 0x67 @ Adresse 0x92. Das bedeutet, dass die Ausgabe (dh der Hex-Code), die an den Programmierer geht, verglichen werden sollte. Der Objekt-/Baugruppencode zeigt keinen Hinweis auf einen Unterschied.

Antworten (2)

Es stellt sich heraus, dass dies ein bekannter Fehler mit avr-gcc ( PR50652 ) ist und in Version 4.6.2 behoben wurde. Leider verwenden Ubuntu-Repositories (die ich verwendet habe) Version 4.5.3.

Die Taktfrequenz hat sich höchstwahrscheinlich nicht geändert (es sei denn, Sie haben Ihre eingerichteten Register durcheinander gebracht). Die Schleifenzeit ist das, was sich für Sie ändert, aus irgendeinem Grund fügt das eine Werkzeug mehr Anweisungen oder länger ausführende Anweisungen in diese Schleife in der Binärdatei ein.

Da Sie zwei Versionen haben, sollten Sie in der Lage sein, sie im richtigen Editor zu öffnen und einen A/B-Vergleich durchzuführen und zu sehen, wo sich die beiden Opcode-Sätze unterscheiden.

Es könnte so einfach sein wie eine Compiler-Einstellung, eine Compiler-Version oder irgendetwas anderes.

Und wenn Sie Ihre Setup-Register wackelt haben, ist dies wahrscheinlich auch eine Compiler-Einstellung, die sich in der Ausgabe-Binärdatei manifestiert.

Er hat die Assembly gepostet, und ich sehe keine Änderung im Schleifencode. Ich dachte, so etwas wie der Code landete anders seitenausgerichtet im Speicher, aber das ist ziemlich weit hergeholt ...