Problema del primer byte del esclavo AVR SPI

He escrito un esclavo SPI simple en un ATMEGA328PB . Funciona principalmente, sin embargo, parece que no puedo obtener el primer byte para ser lo que quiero. La diferencia entre el primero, el segundo y todos los demás intentos también me confunde.

El maestro baja la línea SS, espera 500us, luego registra 15 '0xFF' seguidos de '0x00', espera otros 500us y luego libera el SS. Simultáneamente, el AVR responde con su 'carga útil'.

#define F_CPU 8000000L

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdint.h>

#define togbit(port,bit) (port) ^= (1 << (bit))  // XOR

// SPI variables
volatile uint8_t received = 0;
volatile uint8_t cnt = 0;
volatile uint8_t incoming[16] = {0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA};
volatile uint8_t payload[16] = "ABCDEFGHIJKLMNO";

uint8_t spiCom(uint8_t data)
{
    SPDR0 = data; // Put current 'payload' into outgoing buffer
    return SPDR0;  // return incoming byte
}

ISR(SPI0_STC_vect)
{
    incoming[received] = spiCom(payload[cnt]);  // Transfer a byte

    if (incoming[received] == 0xFF) // start clocking out data when receiving 0xFF padding
    {
        cnt++;
        received++;
    }

    if (received >= 16 || incoming[received] == 0x00)  // reset array position counters if buffer overflows or received NULL
    {
        received = 0;
        cnt = 0;
    }
}

void initSPI(void)
{
    volatile char IOReg;  // Ignore compiler warnings about me...I'm needed to clear a flag
    DDRB |= (1<<PINB4);  // Set PB4(MISO) as output
    SPCR0 |= (1<<SPIE)|(1<<SPE);  // Enable SPI Interrupt and Slave Mode with SCK = CK/4

    // Clear SPIF bit in SPSR by accessing the SPI registers
    IOReg = SPSR0;
    IOReg = SPDR0;

    sei();
}

int main(void)
{
    DDRB = 0x00; // all of PORTB is input
    initSPI();
    DDRB |= (1<<PINB0);  // LED I/O is output

    SPDR0 = 0xC8;  // pre-load something identifiable into SPI buffer

    while (1) 
    {
        togbit(PORTB, PINB0);  // Blink LED while waiting for SPI interrupt
        _delay_ms(1000);
    }
}

El primer intento de comunicación, el maestro recibe: 0xC8,A,B,C,D...etc.

El segundo intento de comunicación, el maestro recibe: 0x00,A,B,C,D...etc.

La tercera y todas las comunicaciones subsiguientes , el maestro recibe: A,A,B,C,D...etc.

Estas señales fueron verificadas por mi analizador lógico.

Casi puedo aceptar cómo va el primer intento, ya que 0xC8 es con lo que precargué el registro SPDR (como prueba). Dicho esto, todavía encontré este comportamiento inesperado, por lo que debo estar malinterpretando algo en la sección SPI de la hoja de datos del AVR .

No puedo entender lo que está sucediendo después de eso. Si mi malentendido tiene que ver con el orden con el que se maneja el registro SPDR (¿búfer?) Durante la comunicación, todavía no puedo descifrar la diferencia entre la segunda y la tercera (y todas las subsiguientes) comunicaciones.

He leído casi todos los tutoriales de SPI en AVR que pude encontrar, pero no puedo entender dónde me estoy equivocando. Cualquier consejo sería muy apreciado.

Respuestas (1)

La respuesta ya está en tu pregunta. Siendo simultáneamente la palabra clave.

Se llama a la interrupción en RX completo, que es cuando ya se ha recibido un byte del maestro. Esto también debe significar que ya se ha enviado un byte del esclavo , y su código configura el próximo byte que se enviará.

Debe configurar el primer byte que se enviará antes de que comience la comunicación.