Hello!
I am trying to use the Seeeduino XIAO as an SPI slave, with very little success. After much searching, I have pieced together the code below, while using the default SERCOM0 SPI pins (also below).
However, I have two issues.
-
The interrupt does not fire - not at all, regardless of accurate data.
-
The master device slows down significantly, I know this because I am trying to act as a device in the middle, only sniffing the line (pure slave). Seems like a clock issue? Why does the atmel datasheet tell us to set a clock on slave mode when the slave is not supposed to set a clock?
Any assistance is greatly appreciated. A working SPI slave code example for this board (or on SERCOM0) would be fantastic. 3 hours of googling have turned up a lot on Sercom 1 and Sercom 4, but not Sercom 0.
void Seeeduino_spiSlave_init()
{
// Pin
// 4 - SS(CS)
// 8 - SCK - SERCOM0 - PAD 3
// 9 - MISO - SERCOM0 - PAD 1
// 10 - MOSI - SERCOM0 - PAD 2pinMode(SS, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(SS), SERCOM0_Handler, FALLING);//Disable SPI 1
SERCOM0->SPI.CTRLA.bit.ENABLE = 0;
while (SERCOM0->SPI.SYNCBUSY.bit.ENABLE);//Reset SPI 1
SERCOM0->SPI.CTRLA.bit.SWRST = 1;
while (SERCOM0->SPI.CTRLA.bit.SWRST || SERCOM0->SPI.SYNCBUSY.bit.SWRST);//Setting up NVIC
NVIC_EnableIRQ(SERCOM0_IRQn);
NVIC_SetPriority(SERCOM0_IRQn, 2);//Setting Generic Clock Controller!!!
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(GCM_SERCOM0_CORE) | //Generic Clock 0
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is the source
GCLK_CLKCTRL_CLKEN; // Enable Generic Clock Generatorwhile (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); //Wait for synchronisation
//Set up SPI Control A Register
SERCOM0->SPI.CTRLA.bit.DORD = 0; //MSB first
SERCOM0->SPI.CTRLA.bit.CPOL = 0; //SCK is low when idle, leading edge is rising edge
SERCOM0->SPI.CTRLA.bit.CPHA = 0; //data sampled on leading sck edge and changed on a trailing sck edge
SERCOM0->SPI.CTRLA.bit.FORM = 0x0; //Frame format = SPI
SERCOM0->SPI.CTRLA.bit.DIPO = 2; //DATA PAD0 MOSI is used as input (slave mode)
SERCOM0->SPI.CTRLA.bit.DOPO = 1; //DATA PAD3 MISO is used as output
SERCOM0->SPI.CTRLA.bit.MODE = 0x2; //SPI in Slave mode
SERCOM0->SPI.CTRLA.bit.IBON = 0x1; //Buffer Overflow notification
SERCOM0->SPI.CTRLA.bit.RUNSTDBY = 1; //wake on receiver complete//Set up SPI control B register
SERCOM0->SPI.CTRLB.bit.SSDE = 0x1; //Slave Select Detection Enabled
SERCOM0->SPI.CTRLB.bit.CHSIZE = 0; //character size 8 Bit//Set up SPI interrupts
SERCOM0->SPI.INTENSET.bit.SSL = 0x1; //Enable Slave Select low interrupt
SERCOM0->SPI.INTENSET.bit.RXC = 0x1; //Receive complete interrupt
SERCOM0->SPI.INTENSET.bit.TXC = 0x1; //Receive complete interrupt
SERCOM0->SPI.INTENSET.bit.ERROR = 0x1; //Receive complete interrupt
SERCOM0->SPI.INTENSET.bit.DRE = 0x1; //Data Register Empty interrupt//Enable SPI
SERCOM0->SPI.CTRLA.bit.ENABLE = 1;
while (SERCOM0->SPI.SYNCBUSY.bit.ENABLE);
SERCOM0->SPI.CTRLB.bit.RXEN = 0x1; //Enable Receiver, this is done here due to errant issue
while (SERCOM0->SPI.SYNCBUSY.bit.CTRLB); //wait until receiver is enabled
}
void SERCOM0_Handler()
{
noInterrupts();uint8_t data = 0;
data = (uint8_t)SERCOM0->SPI.DATA.reg;
uint8_t interrupts = SERCOM0->SPI.INTFLAG.reg; //Read SPI interrupt registerif (interrupts & (1 << 3))
{
SERCOM0->SPI.INTFLAG.bit.SSL = 1; //clear slave select interrupt
}
if (interrupts & (1 << 2))
{
data = SERCOM0->SPI.DATA.reg; //Read data register
SERCOM0->SPI.INTFLAG.bit.RXC = 1; //clear receive complete interrupt
}
if (interrupts & (1 << 1))
{
SERCOM0->SPI.INTFLAG.bit.TXC = 1; //clear receive complete interrupt
}if (interrupts & (1 << 0))
{
SERCOM0->SPI.DATA.reg = 0xAA;
}
char _data = data;
Serial.print(_data); // print received datainterrupts();
}