AVR SPI2X no tiene efecto

1

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:

  1. 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)
  2. ¿SPI2X no se está configurando correctamente? No, después del bucle if (SPSR & (1<<SPI2X)) devuelve true.
  3. ¿SPI2X debe configurarse antes de habilitar SPI? No, configurarlo primero no tiene efecto.
  4. No hay cambios entre las optimizaciones -O3 y -Os , pero un gran aumento en valor del temporizador para -O0 .
  5. 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í.

    
pregunta Adam Griffin

1 respuesta

3

¿Estás seguro de que la línea while (!(SPSR) & (1 << SPIF)); es correcta? Sospecho que se supone que funciona: while (!(SPSR & (1 << SPIF)));

    
respondido por el TMa

Lea otras preguntas en las etiquetas