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.