-
Notifications
You must be signed in to change notification settings - Fork 59
Description
Problem in DxCore/library/SPI.c
I have a setup where the error is reproducible and I could analyze the problem. The problem depends on the state of the SS pin, if it is configured as output evering is ok, if it is configured as input the error shows up when the input level is low. The root cause of the problem is that SPI0.CTRLA is written with SPI_ENABLE_bm before SPI.CTRLB is written with SPI_SSD_bm set. Initialization by the book would first set up all registers and as last action set the SPI_ENABLE_bm. A simple fix appears to write SPI0.CTRLB first and then SPI0.CTRLA with SPI_ENABLE_bm.
Below is the code used for debugging with Arduino IDE using DxCore 1.5.11 (insync with the github repository), the chip is an AVR64EA28. The problem was also observed with an AVR64DD28.
// chase the magical "SPI master error: on first transaction, second byte is not sent / received."
//#define NO_ERROR
//#define ERROR_DEPENDS_ON
//#define SIMPLE_FIX
#include <SPI.h>
void setup() {
volatile char data;
PORTA.DIR |= (1<<4) | (1<<6); // PA4 MOSI, PA6 SCK
#ifdef ERROR_DEPENDS_ON
PORTA.DIR |= (1<<7);
#endif
#ifdef NO_ERROR
SPI0.CTRLA = (SPI_DORD_bm&0) | SPI_MASTER_bm | SPI_PRESC_DIV4_gc;
SPI0.CTRLB = SPI_SSD_bm | SPI_MODE_0_gc;
SPI0.INTCTRL = 0;
SPI0.CTRLA |= SPI_ENABLE_bm;
#else
#ifndef SIMPLE_FIX
SPI0.CTRLA = (SPI_DORD_bm&0) | SPI_MASTER_bm | SPI_PRESC_DIV4_gc | SPI_ENABLE_bm;
SPI0.CTRLB = SPI_SSD_bm | SPI_MODE_0_gc;
SPI0.INTCTRL = 0;
SPI0.CTRLA = (SPI_DORD_bm&0) | SPI_MASTER_bm | SPI_PRESC_DIV4_gc | SPI_ENABLE_bm;
SPI0.CTRLB = SPI_SSD_bm | SPI_MODE_0_gc;
#else // simple fix
SPI0.CTRLB = SPI_SSD_bm | SPI_MODE_0_gc;
SPI0.CTRLA = (SPI_DORD_bm&0) | SPI_MASTER_bm | SPI_PRESC_DIV4_gc | SPI_ENABLE_bm;
SPI0.INTCTRL = 0;
#endif
#endif
SPI0.DATA=0x55;
while( ! (SPI0.INTFLAGS & SPI_IF_bm) );
data=SPI0.DATA;
SPI0.DATA=0x33;
while( ! (SPI0.INTFLAGS & SPI_IF_bm) );
data=SPI0.DATA;
}
void loop() {
delay(100);
}