El tamaño de la matriz global afecta la frecuencia del reloj solo en Linux (avr-gcc)

Estoy teniendo el problema más peculiar. Cuando cambia el tamaño de una matriz global, altera la frecuencia de reloj del ATmega164a. Esto es en Linux. Cuando se compila en Windows, este problema no ocurre (independientemente de si el archivo .hex está realmente programado en el ATmega164a en Windows o Linux, no sospecho que avrdude esté contribuyendo a este problema). Incluso ejecuté en Linux los comandos exactos ejecutados por AVR Studio para construir el objetivo, y todavía encontré este problema.

El fusible CLKDIV8 no está configurado y el fusible RC interno está configurado, por lo que el ATmega164a debería funcionar a 8 MHz nominales.

Este es el ejemplo mínimo de trabajo del código que se ejecuta correctamente:

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

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

Un osciloscopio muestra que el pulso resultante tiene un ancho de 250 ns (2 ciclos).

Sin embargo, aumentar el tamaño de la matriz global en uno da como resultado un comportamiento extraño.

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

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

Un osciloscopio muestra este ancho de pulso como 444 ns, y el tiempo entre pulsos aumenta en la misma proporción que indica que la frecuencia del reloj ha disminuido.

No tengo ni idea de adónde ir desde aquí. Me tomó mucho tiempo limitarlo a este ejemplo mínimo de trabajo. He pegado mi Makefile en pastebin .

EDITAR

Aquí están los archivos de listado para los dos casos. bytes[6]: pastebin bytes[7]: pastebin

He verificado con un temporizador de 16 bits que la frecuencia del reloj está disminuyendo en el factor citado anteriormente (250 ns -> 444 ns).

Publicar el listado de montaje para ambos casos.
Esta no es una forma particularmente confiable de medir la frecuencia del reloj. Tal vez use un temporizador con Max. Prescaler y configúrelo para alternar en la parte superior o lo que sea que tenga y mida eso. Entonces no se ve afectado por las peculiaridades del compilador.
@ThePhoton señala que la lista de Assembler solo tiene una diferencia sustancial de 1 línea. 0x66 -> 0x67 @ dirección 0x92. Eso significa que se debe comparar la salida (es decir, el código hexadecimal) que va al programador. El código objeto/ensamblador no muestra evidencia de diferencia.

Respuestas (2)

Resulta que este es un error conocido con avr-gcc ( PR50652 ) y se solucionó en la versión 4.6.2. Desafortunadamente, los repositorios de Ubuntu (que estaba usando) utilizan la versión 4.5.3.

Es muy probable que la frecuencia del reloj no haya cambiado (a menos que haya alterado los registros de configuración). El tiempo de bucle es lo que está cambiando para usted, por alguna razón, la única herramienta está insertando más instrucciones o ejecutando instrucciones más largas en ese bucle en el binario.

Como tiene dos versiones, debería poder abrirlas en el editor adecuado y hacer una comparación A/B y ver dónde son diferentes los dos conjuntos de códigos de operación.

Podría ser tan simple como una configuración del compilador, una versión del compilador o cualquiera de varias cosas.

Y si ha cambiado los registros de configuración, TAMBIÉN es probablemente una configuración del compilador que se manifestará en el binario de salida.

Publicó el ensamblado y no veo ningún cambio en el código del bucle. Estaba pensando que algo así como el código terminó alineado de manera diferente en la memoria, pero eso es una posibilidad remota...