Tengo un ATMega88A configurado para ejecutarse en un reloj interno de 8MHz:
lfuse = 0xE2
hfuse = 0xDF
efuse = 0x01
F_CPU defined as 8000000
Esto se confirma en el 'mundo real' parpadeando un LED con _delay_ms (1000). Es ~ 1 seg, no 8 segundos ni 1/8 seg.
He intentado configurar el SPI para que se ejecute en Fosc / 2 configurando solo SPI2X en 1. (SPR1, SPR0 se inicializa y debería permanecer en 0.) Esto debería dar como resultado una velocidad de SPI de 4MHz.
He configurado el temporizador en una preescala de 256x.
Estoy intentando enviar 5000 bytes a través de SPI. (No hay ningún dispositivo conectado, solo se desplazan los bits fuera del puerto). El temporizador se pone a cero antes de la transmisión y luego el valor se muestra como LED después de la transmisión.
Para enviar un bit a través de un SPI de 4 MHz debe tomar 1/4000000 = 250ns, un byte 8 * 250ns = 2us, 5000 byte 2us * 5000 = 10ms .
Sin embargo, desde mi temporizador: el reloj del sistema es 8MHz, por lo que el período es 1/8000000 = 125ns, el preescalador del temporizador de 256 tick del temporizador promedio de 125ns * 256 = 32us LED muestra un valor binario de 176, por lo que el tiempo de ciclo es 32us * 176 = 5.632ms .
¿Cómo es real más rápido que la teoría?
¿El pateador? El comentar SPSR = (1 << SPI2X);
no tiene efecto en el valor mostrado en los LED del temporizador.
Código de muestra:
#include <avr/io.h>
#include <util/delay.h>
#define set_output(portdir,pin) portdir |= (1<<pin)
void init() {
// Set MOSI, SCK, SS as Output
set_output(DDRB, DDB5);
set_output(DDRB, DDB3);
set_output(DDRB, DDB2);
// Enable SPI, Set as Master, Set CPOL & CPHA to 1 (SPI mode 3)
SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA);
SPSR = (1 << SPI2X); // Enable SPI clock doubler
DDRD = 0xff; // Set PORTD as output
TCCR1B |= (1 << CS12); // Setup Timer with 256 prescaling
}
int main(void) {
unsigned int i;
init();
TCNT1 = 0; // Zero the timer
for (i = 0; i < 5000; i++) {
SPDR = 0; // Load data into the SPI data reg
while (!(SPSR) & (1 << SPIF)); // Wait until transmission complete
}
PORTD = (unsigned char) TCNT1; // Display the timer on PORTD
for (;;) {}
return 0;
}
Algunos problemas que he probado:
- TCNT1 (16 bits) podría estar desbordando PORTD (8 bits)? No, bucle menos iteraciones reduce el valor del temporizador proporcionalmente. (5000 bucles = 175 tics; 1000 bucles = 35 tics)
- ¿SPI2X no se está configurando correctamente? No, después del bucle
if (SPSR & (1<<SPI2X))
devuelve true. - ¿SPI2X debe configurarse antes de habilitar SPI? No, configurarlo primero no tiene efecto.
- No hay cambios entre las optimizaciones
-O3
y-Os
, pero un gran aumento en valor del temporizador para-O0
. - Escribir algún otro valor en SPDR no tiene efecto.
¿Me estoy volviendo loco?
EDITAR: La parte del código de error que se responde a continuación fue copiada de manera descuidada de mí sin verificación de aquí.