Problema de primer byte del esclavo AVR SPI

1

He escrito un sencillo SPI esclavo en un ATMEGA328PB . En su mayoría funciona, sin embargo, parece que no consigo que el primer byte sea 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' seguido de '0x00', espera otros 500us y luego libera la 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 precedo el registro SPDR (como prueba). Dicho esto, todavía encuentro este comportamiento inesperado, por lo que debo estar entendiendo mal algo en la sección de SPI de hoja de datos del AVR .

No puedo envolver mi cabeza en torno a 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 entender la diferencia entre la segunda y la tercera (y todas las subsiguientes) comunicaciones.

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

    
pregunta evildemonic

1 respuesta

3

La respuesta ya está en tu pregunta. Simultáneamente es la palabra clave.

La interrupción se llama en RX completa, que es cuando ya se ha recibido un byte del maestro. Esto también debe significar que un byte del esclavo ya se ha enviado , y su código configura el siguiente byte que se enviará.

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

    
respondido por el domen

Lea otras preguntas en las etiquetas