SPI master and slave for SAMD21G18

I am trying to set up a SPI communication between two arduino xiao boards.
However, only the slave is able to receive data from the master. Master is not able to receive anything from the slave. Is there any wrong with my code or something.

Master code:

#include<SPI.h>                             //Library for SPI 

#define mySS 6

void setup (void){
  pinMode(mySS, OUTPUT);

  Serial.begin(115200);                   //Starts Serial Communication at Baud Rate 115200

  SPI.begin();                            //Begins the SPI commnuication

  SPI.setClockDivider(SPI_CLOCK_DIV8);    //Sets clock for SPI communication at 8 (16/8=2Mhz)

  digitalWrite(mySS, HIGH);                 // Setting SlaveSelect as HIGH (So master doesnt connnect with slave)
}


void loop(void){
  byte Mastersend, Mastereceive;
  digitalWrite(mySS, LOW);                  //Starts communication with Slave connected to master

  Mastersend = 99;
  Mastereceive = SPI.transfer(Mastersend); //Send the mastersend value to slave also receives value from slave

  
  digitalWrite(mySS, HIGH);
  Serial.print("Master Receive : ");
  Serial.println(Mastereceive);

  delay(1000);
}

###########################################################

Slave code:
#define SPI_MOSI_B_PIN  10   // Board Pin 
#define SPI_SCK_B_PIN   8  // Board Pin 
#define SPI_MISO_B_PIN  9  // Board Pin 
#define SPI_CS_B_PIN    1   // Board Pin 

#define SPI_MOSI_PIN    6  
#define SPI_SCK_PIN     7  
#define SPI_MISO_PIN    5  
#define SPI_CS_PIN      4   


// Macros for the pin and port group
#define GPIO_PIN(n) (((n)&0x1Fu) << 0)
#define GPIO_PORT(n) ((n) >> 5)
#define GPIO(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))
#define GPIO_PIN_FUNCTION_OFF 0xffffffff
// Port Critical Sections
#if defined(ENABLE_PORT_CRITICAL_SECTIONS)
#define PORT_CRITICAL_SECTION_ENTER() CRITICAL_SECTION_ENTER()
#define PORT_CRITICAL_SECTION_LEAVE() CRITICAL_SECTION_LEAVE()
#else
#define PORT_CRITICAL_SECTION_ENTER()
#define PORT_CRITICAL_SECTION_LEAVE()
#endif
// Variables
typedef uint8_t  hri_port_pmux_reg_t;

void setup() {
  
  // Set all pins are input so we don't disrupt communication on boot
  pinMode(SPI_MOSI_B_PIN, INPUT);
  pinMode(SPI_SCK_B_PIN, INPUT);
  pinMode(SPI_MISO_B_PIN, INPUT);
  pinMode(SPI_CS_B_PIN, INPUT);

  // init Serial USB
  Serial.begin(115200);//for debugging  

  //wait for serial to init
  //while (!Serial); 

  // Seeduino XIAO - Enable SPI as Slave
  Seeeduino_spiSlave_init();

#ifdef ENABLE_PORT_CRITICAL_SECTIONS
Serial.println("ENABLE_PORT_CRITICAL_SECTIONS is defined from the start")
#endif

  //Serial.println("Setup Completed");   
}

void loop() { 
  
}

void Seeeduino_spiSlave_init()
{
  // assign our board pins to SERCOM0
  gpio_set_pin_function(SPI_MOSI_PIN, PINMUX_PA06D_SERCOM0_PAD2);
  gpio_set_pin_function(SPI_SCK_PIN, PINMUX_PA07D_SERCOM0_PAD3);
  gpio_set_pin_function(SPI_MISO_PIN, PINMUX_PA05D_SERCOM0_PAD1);
  gpio_set_pin_function(SPI_CS_PIN, PINMUX_PA04D_SERCOM0_PAD0);

  //Serial.print("PINMUX_PA10C_SERCOM0_PAD2 = "); Serial.println(PINMUX_PA10C_SERCOM0_PAD2);//A0002
  //Serial.print("PINMUX_PA11C_SERCOM0_PAD3 = "); Serial.println(PINMUX_PA11C_SERCOM0_PAD3);//B0002
  //Serial.print("PINMUX_PA08C_SERCOM0_PAD0 = "); Serial.println(PINMUX_PA08C_SERCOM0_PAD0);//80002
  //Serial.print("PINMUX_PA09C_SERCOM0_PAD1 = "); Serial.println(PINMUX_PA09C_SERCOM0_PAD1);//90002
  //Serial.print("GPIO_PIN_FUNCTION_OFF = "); Serial.println(GPIO_PIN_FUNCTION_OFF);//90002
  
  
  //Disable SPI 0
  SERCOM0->SPI.CTRLA.bit.ENABLE = 0;
  while (SERCOM0->SPI.SYNCBUSY.bit.ENABLE);

  //Reset SPI 0
  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 Generator

  while (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.DIPO = 0; //DATA PAD0 MOSI is used as input (slave mode)
  //SERCOM0->SPI.CTRLA.bit.DOPO = 0x2; //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.RXEN = 0x1; //Enable Receiver
  SERCOM0->SPI.CTRLB.bit.SSDE = 0x1; //Slave Selecte Detection Enabled
  SERCOM0->SPI.CTRLB.bit.CHSIZE = 0; //character size 8 Bit
  //SERCOM0->SPI.CTRLB.bit.PLOADEN = 0x1; //Enable Preload Data Register
  //while (SERCOM0->SPI.SYNCBUSY.bit.CTRLB);

  //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
  //init SPI CLK
  //SERCOM0->SPI.BAUD.reg = SERCOM_FREQ_REF / (2*4000000u)-1;
  //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 errate issue
  while (SERCOM0->SPI.SYNCBUSY.bit.CTRLB); //wait until receiver is enabled
}


// Seeduino SPI interrupt routine
void SERCOM0_Handler()
{
  //Serial.println("In Handler");
  noInterrupts();
  uint8_t data = 0;
  uint8_t interrupts = SERCOM0->SPI.INTFLAG.reg; //Read SPI interrupt register
  
  if (interrupts & (1 << 3))
  {
    //Serial.println("clear slave select interrupt");
    SERCOM0->SPI.INTFLAG.bit.SSL = 1; //clear slave select interrupt
  }

  // This is where data is received, and is written to a buffer, which is used in the main loop
  if (interrupts & (1 << 2))
  {
    //Serial.println("data is received");
    data = SERCOM0->SPI.DATA.reg; //Read data register
    //data = 40;
    
    SERCOM0->SPI.INTFLAG.bit.RXC = 1; //clear receive complete interrupt

    // Put the data somewhere, like a buffer - or print it for testing
    Serial.print("receive data:");
    Serial.println(data, DEC); // print received data as a number
  }

  // This is where data is transmitted
  if (interrupts & (1 << 1))
  {
    //Serial.println("data is transmitted");
    SERCOM0->SPI.INTFLAG.bit.TXC = 1; //clear transmit complete interrupt
  }

  // Data Register Empty Interrupt
  if (interrupts & (1 << 0))
  {
    SERCOM0->SPI.DATA.reg = 0xAA;
  }
  interrupts();
}

static inline void gpio_set_pin_function(const uint32_t gpio, const uint32_t function)
{
  uint8_t port = GPIO_PORT(gpio);
  uint8_t pin  = GPIO_PIN(gpio);

  //Serial.print("port = "); Serial.println(port);
  //Serial.print("pin = "); Serial.println(pin);
  //Serial.println("");

  if (function == GPIO_PIN_FUNCTION_OFF) {
    hri_port_write_PINCFG_PMUXEN_bit(PORT, port, pin, false);

  } else {
    hri_port_write_PINCFG_PMUXEN_bit(PORT, port, pin, true);

    if (pin & 1) {
      // Odd numbered pin
      hri_port_write_PMUX_PMUXO_bf(PORT, port, pin >> 1, function & 0xffff);
    } else {
      // Even numbered pin
      hri_port_write_PMUX_PMUXE_bf(PORT, port, pin >> 1, function & 0xffff);
    }
  }
}

static inline void hri_port_write_PINCFG_PMUXEN_bit(const void *const hw, uint8_t submodule_index, uint8_t index,
                                                    bool value)
{
  uint8_t tmp;
  PORT_CRITICAL_SECTION_ENTER();
  tmp = ((Port *)hw)->Group[submodule_index].PINCFG[index].reg;
  tmp &= ~PORT_PINCFG_PMUXEN;
  tmp |= value << PORT_PINCFG_PMUXEN_Pos;
  
  ((Port *)hw)->Group[submodule_index].PINCFG[index].reg = tmp;
  PORT_CRITICAL_SECTION_LEAVE();
}

static inline void hri_port_write_PMUX_PMUXO_bf(const void *const hw, uint8_t submodule_index, uint8_t index,
                                                hri_port_pmux_reg_t data)
{
  uint8_t tmp;
  PORT_CRITICAL_SECTION_ENTER();
  tmp = ((Port *)hw)->Group[submodule_index].PMUX[index].reg;
  tmp &= ~PORT_PMUX_PMUXO_Msk;
  tmp |= PORT_PMUX_PMUXO(data);
  //Serial.print("hri_port_write_PMUX_PMUXO_bf / tmp = "); Serial.println(tmp);
  ((Port *)hw)->Group[submodule_index].PMUX[index].reg = tmp;
  PORT_CRITICAL_SECTION_LEAVE();
}

static inline void hri_port_write_PMUX_PMUXE_bf(const void *const hw, uint8_t submodule_index, uint8_t index,
                                                hri_port_pmux_reg_t data)
{
  uint8_t tmp;
  PORT_CRITICAL_SECTION_ENTER();
  tmp = ((Port *)hw)->Group[submodule_index].PMUX[index].reg;
  tmp &= ~PORT_PMUX_PMUXE_Msk;
  tmp |= PORT_PMUX_PMUXE(data);
  //Serial.print("hri_port_write_PMUX_PMUXE_bf / tmp = "); Serial.println(tmp);
  ((Port *)hw)->Group[submodule_index].PMUX[index].reg = tmp;
  PORT_CRITICAL_SECTION_LEAVE();
}

As a quick guess, at some point does this pin not need to be an output?

Wild guess: the slave must supply the byte to be sent quite early, before the start of the transmission, typically when the slave is selected. Only later bytes in a multi-byte transfer can be supplied by a callback.

Thank you for your reply, but the MISO pin on the oscilloscope appears to be 0 as well. I guess something is wrong with my slave code.

thank u for your reply, neither INPUT or OUTPUT works in this case.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.