Atmega8 - La frecuencia de salida máxima parece estar dividida en 4

3

Estoy un poco confundido, y espero que alguien aquí pueda señalarme lo que me estoy perdiendo ... Estoy usando un Atmega8-16PU, Se encendió el fusible con:

avrdude -b 19200 -c avrisp -P /dev/tty.usbserial-A9IHTRVJ -p atmega8 -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m

que significa ... de acuerdo con enlace que estoy usando int. osc 8 mhz. En mi código, sobrescribo OSCAL a OSCCAL = 0xFF; para trabajar a su máxima frecuencia.

sin embargo, en un bucle for (también probado con 'while'), solo estoy cambiando un pin LED1_STATE ^ = (1 < < LED1_PIN); y estoy midiendo 1.6Mhz ...

Estaba pensando que el AVR era capaz de ejecutar una instrucción por reloj del sistema ... aquí parece que la FCPU está dividida por 4 ...

También intenté usar Timer0 y su interrupción de desbordamiento con;

    TCNT0 = 254; 
    TIMSK |= (1<<TOIE0); // enable interrupt
    TCCR0 = 0x01; //prescaler = 1 
    sei();


ISR(TIMER0_OVF_vect){
    LED1_STATE ^=(1<<LED1_PIN);
    TCNT0 = 254;
}

y aquí la señal de salida 200Khz ....

¿Puede alguien ayudarme a averiguar qué está pasando? ¿No soy suficiente teniendo en cuenta el necesario tiempo de 'instrucciones'? Muchas gracias internet

Saludos

    
pregunta CrH

2 respuestas

1

gracias al archivo makefile jippie, pude ver el código del ensamblador correspondiente. De hecho, hay 6 instrucciones asm para hacer el while (1) y alternar.

 1e4:   8f ef           ldi r24, 0xFF   ; 255 <-- OSCAL = 0xFF (1 clk)
 1e6:   81 bf           out 0x31, r24   ; 49  <-- Switch pin voltage level (1clk)
 1e8:   92 e0           ldi r25, 0x02   ; 2   <-- ? (1clk)
 1ea:   85 b3           in  r24, 0x15   ; 21  <-- Read pins level (1clk)
 1ec:   89 27           eor r24, r25          <-- Excl. OR (1clk)
 1ee:   85 bb           out 0x15, r24   ; 21  <-- Switch pin voltage level (1clk)
 1f0:   fc cf           rjmp    .-8         ; 0x1ea <main+0x8> <-- Loop (2clk)

total: 8 clk ticks

Gracias

    
respondido por el CrH
1

Eche un vistazo al ensamblaje que se está generando, ambos casos tendrán instrucciones adicionales que no haya pensado. En un bucle while, por ejemplo, habrá una instrucción para saltar al principio del bucle.

El enfoque del temporizador es mejor, pero lo estás haciendo de forma incorrecta. Cuando se dispara el temporizador, estás llamando a una función. Hay varias instrucciones asociadas con eso. Afortunadamente, los temporizadores de 16 bits en los chips ATmega * pueden hacer otras cosas que disparar interrupciones, también pueden alternar los pines directamente. Prueba:

TCCR1B = 0x08 | 0x01; 
TCCR1A = 0x80; 
OCR1A = 1;
TCNT1 = 0;

Esto hará que el temporizador 1 cuente a uno, luego alterne el pin de salida asociado, luego cuente a uno y lo vuelva a activar. Tal como está escrito, obtendrás un reloj F_CPU / 4, tan dos veces más rápido que el que tienes y sin bloquear el sistema para que no puedas hacer nada más. Probablemente pueda obtener un reloj de F_CPU ajustando los fusibles para colocar el reloj maestro en uno de los pines de salida.

Verifique en la hoja de datos de qué pin es la salida. En la mayoría de los ATmegas puede elegir uno de los dos pines, no puede elegir un pin arbitrario si lo hace de esta manera.

Aquí hay un enlace útil que explica lo que hacen algunos de esos registros: enlace

Ahora que ha publicado su bucle while desensamblado, podemos ver lo que estaba sucediendo:

1e4:    8f ef ldi   r24, 0xFF   ; 255   Load the value 0xFF into a register
1e6:    81 bf out   0x31, r24   ; 49    Write that value to OSCCAL
1e8:    92 e0 ldi   r25, 0x02   ; 2     Load the value 0x02  into a register
1ea:    85 b3 in    r24, 0x15   ; 21    Read the pin state port into a register <-
1ec:    89 27 eor   r24, r25            XOR together the two registers           |
1ee:    85 bb out   0x15, r24   ; 21    Write the result to the pin state port   |
1f0:    fc cf rjmp  .-8 ;               Jump back to  ----------------------------

Por lo tanto, el bucle while incluye las instrucciones: entrada, salida, salida, rjump, que toman 1 + 1 + 1 + 2 = 5 ciclos de reloj, y alternar el pin una vez. Así que 10 ciclos para cambiarlo dos veces. Ya que está viendo una salida de 1.6MHz, eso implica que al establecer OSCCAL en 0xFF, ha obtenido una velocidad de reloj de 16MHz. Tenga en cuenta que, aunque esto funciona, la hoja de datos lo recomienda en su contra.

    
respondido por el Jack B

Lea otras preguntas en las etiquetas