Problem mit dem ersten Byte des AVR-SPI-Slaves

Ich habe einen einfachen SPI-Slave auf einem ATMEGA328PB geschrieben . Es funktioniert meistens, aber ich kann anscheinend nicht das erste Byte bekommen, was ich will. Der Unterschied zwischen dem ersten, zweiten und allen anderen Versuchen verwirrt mich auch.

Der Master zieht die SS-Leitung auf Low, wartet 500 us, taktet dann 15 '0xFF' gefolgt von einem '0x00' aus, wartet weitere 500 us und gibt dann die SS frei. Gleichzeitig antwortet der AVR mit seiner „Payload“.

#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);
    }
}

Beim ersten Kommunikationsversuch erhält der Master: 0xC8,A,B,C,D...etc.

Beim zweiten Kommunikationsversuch erhält der Master: 0x00,A,B,C,D...etc.

Bei der dritten und allen folgenden Mitteilungen erhält der Master: A, A, B, C, D ... usw.

Diese Signale wurden von meinem Logikanalysator verifiziert.

Ich kann fast akzeptieren, wie der erste Versuch verläuft, da ich das SPDR-Register mit 0xC8 vorlade (als Test). Trotzdem fand ich dieses Verhalten unerwartet, also muss ich etwas im SPI-Abschnitt des AVR- Datenblatts falsch verstehen .

Ich kann mir nicht vorstellen, was danach passiert. Wenn mein Missverständnis mit der Reihenfolge zu tun hat, in der das SPDR-Register (Puffer?) Während der Kommunikation behandelt wird, kann ich den Unterschied zwischen der zweiten und dritten (und allen nachfolgenden) Kommunikationen immer noch nicht herausfinden.

Ich habe so ziemlich jedes SPI-on-AVR-Tutorial gelesen, das ich finden konnte, kann aber nicht herausfinden, wo ich falsch liege. Jeder Rat wäre sehr willkommen.

Antworten (1)

Die Antwort steckt bereits in deiner Frage. Gleichzeitig das Stichwort.

Der Interrupt wird bei RX Complete aufgerufen, das heißt, wenn ein Byte vom Master bereits empfangen wurde. Dies muss dann auch bedeuten, dass bereits ein Byte vom Slave gesendet wurde , und Ihr Code richtet das nächste zu sendende Byte ein.

Sie müssen das erste zu sendende Byte einrichten, bevor die Kommunikation beginnt.