SAMD21G18A Multiple SPI interfaces not working

I have a custom board using a samd21g18A running the bootloader from the adafruit feather M0 express (i ripped that chip off and put it onto my board so i wouldn't have to burn a bootloader).

My design uses two SPI peripherals. For now lets just focus on one. Following the adafruit tutorial i did this:

#include <SPI.h>
#include "wiring_private.h" // pinPeripheral() function

//Internal spi setup. This controls the ADC and onboard storage
#define internalSPImosi 4
#define internalSPImiso 2
#define internalSPIsck 3
#define flashCS PIN_PA13
#define adcCS 12

//spi config
#define speedMaximum 1000000
#define dataOrder MSBFIRST
#define dataMode SPI_MODE0

//serial config
#define Serial SerialUSB

SPIClassSAMD INTERNALSPI (&sercom2, internalSPImiso, internalSPIsck, internalSPImosi, SPI_PAD_0_SCK_3, SERCOM_RX_PAD_1);


void setup() {
  //serial speed is set to maximum 2,000,000 baud
  Serial.begin(2000000);

  // Initilize SPI
  INTERNALSPI.begin();

  // Assign pins for internal SPI to SERCOM functionality
  pinPeripheral(internalSPImosi, PIO_SERCOM);
  pinPeripheral(internalSPImiso, PIO_SERCOM);
  pinPeripheral(internalSPIsck, PIO_SERCOM);
}



void loop() {
  
  INTERNALSPI.beginTransaction(SPISettings(speedMaximum, dataOrder, dataMode));
  digitalWrite (adcCS, LOW);

  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  
  digitalWrite (adcCS, HIGH);
  INTERNALSPI.endTransaction();
}

the main code does nothing useful other than just spit out a bunch of data fast. Nothing shows up on the oscilloscope. as a sanity check, i actually probed the USB interface doing a rapid serial print, which probed fine, so its not a probing issue, at least i don't think

the code defines show which pins i'm using for serial, which according to the datasheet should work.

my question is what am i doing wrong, and how might i change my code to correctly enable the serial peripheral interface i want? if i forgot information that's needed, as i'm sure i have, please let me know.

Hi @billybob983

Here's Adafruit's tutorial on how to create additional SPI ports on the SAMD21:

thanks.

yeah thats the tutorial i followed to get to this point. ill take a look again incase i missed something but i did follow it pretty closely

I changed this. Now it outputs something. However its still not right. MOSI and SCK both output the same thing (MOSI data). Miso has nothing, as there is no device. SCK has significantly smaller amplitude than MOSI, but is definitely outputting something, and is definitely the same signal as MOSI. seems I am getting closer to a solution I hope.

  // Assign pins for internal SPI to SERCOM functionality
  pinPeripheral(internalSPImosi, PIO_SERCOM_ALT);
  pinPeripheral(internalSPImiso, PIO_SERCOM);
  pinPeripheral(internalSPIsck, PIO_SERCOM);

Did you also set the pinMode() to output? That's required on at least some of the peripherals of some of the ARM chips...

yes i did. Didnt help. Its weird to me that sck and mosi appear to output the same thing.

  pinMode(internalSPImosi, OUTPUT);
  pinMode(internalSPImiso, INPUT);
  pinMode(internalSPIsck, OUTPUT);
  pinMode(flashCS, OUTPUT);
  pinMode(adcCS, OUTPUT);

tried following this tutorial SPIOnD21 and came up with the following code:

#include <SPI.h>
#include "wiring_private.h" // pinPeripheral() function

//Internal spi setup. This controls the ADC and onboard storage
#define internalSPImosi 4 //TX sercom
#define internalSPImiso 2 //RX sercom alt
#define internalSPIsck 3 //sercom alt
#define flashCS PIN_PA13
#define adcCS 12

//spi config
#define speedMaximum 1000000
#define dataOrder MSBFIRST
#define dataMode SPI_MODE0

//serial config
#define Serial SerialUSB

SPIClassSAMD INTERNALSPI (&sercom2, internalSPImiso, internalSPIsck, internalSPImosi, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_0);


void setup() {
  //serial speed is set to maximum 2,000,000 baud
  Serial.begin(2000000);

  pinMode(internalSPImosi, OUTPUT);
  pinMode(internalSPImiso, INPUT);
  pinMode(internalSPIsck, OUTPUT);
  pinMode(flashCS, OUTPUT);
  pinMode(adcCS, OUTPUT);

  // Initilize SPI
  INTERNALSPI.begin();

  // Assign pins for internal SPI to SERCOM functionality
  pinPeripheral(internalSPImosi, PIO_SERCOM);
  pinPeripheral(internalSPImiso, PIO_SERCOM_ALT);
  pinPeripheral(internalSPIsck, PIO_SERCOM_ALT);
}



void loop() {
  
  INTERNALSPI.beginTransaction(SPISettings(speedMaximum, dataOrder, dataMode));
  digitalWrite (adcCS, LOW);

  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  
  digitalWrite (adcCS, HIGH);
  INTERNALSPI.endTransaction();
}

Still doesnt work, but the behavior of the sck and mosi pins are now switched?! SCK outputs SCK data, MOSI outputs SCK data at significantly smaller amplitude. I am dumbfounded as to what the issue is. Reading other forums people are having very similar issue. Anyone know what my issue may be? Thanks.

figured it out!! Here is the working code. Commented decently for someone's future reference.

#include <SPI.h>
#include "wiring_private.h" // pinPeripheral() function

//Internal spi setup. This controls the ADC and onboard storage
#define internalSPImosi 4 //PA08 D4 TX (sercom alt) SERCOM2 PAD[0]
#define internalSPImiso 2 //PA14 D2 RX (sercom) SERCOM2 PAD[2]
#define internalSPIsck 3 //PA09 D3 (sercom alt) SERCOM2 PAD[1]
#define flashCS PIN_PA13
#define adcCS 12

//spi config
#define speedMaximum 1000000
#define dataOrder MSBFIRST
#define dataMode SPI_MODE0

//serial config
#define Serial SerialUSB

//create the SPI interface
SPIClassSAMD INTERNALSPI (&sercom2, internalSPImiso, internalSPIsck, internalSPImosi, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_2);


void setup() {
  //serial speed is set to maximum 2,000,000 baud
  Serial.begin(2000000);

  //setup pinmode for serial pins
  pinMode(internalSPImosi, OUTPUT);
  pinMode(internalSPImiso, INPUT);
  pinMode(internalSPIsck, OUTPUT);
  pinMode(flashCS, OUTPUT);
  pinMode(adcCS, OUTPUT);

  // Initilize SPI
  INTERNALSPI.begin();

  // Assign pins for internal SPI to SERCOM functionality
  pinPeripheral(internalSPImosi, PIO_SERCOM_ALT);
  pinPeripheral(internalSPImiso, PIO_SERCOM);
  pinPeripheral(internalSPIsck, PIO_SERCOM_ALT);
}



void loop() {

  //just send a bunch of junk down the serial lines to test on osciloscope
  INTERNALSPI.beginTransaction(SPISettings(speedMaximum, dataOrder, dataMode));
  digitalWrite (adcCS, LOW);

  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  INTERNALSPI.transfer(0x86);
  
  digitalWrite (adcCS, HIGH);
  INTERNALSPI.endTransaction();
}

The secret is this chart here. Line up the raw port definition "PA09 etc" to your boards board definition and initialize it as such.

Arduino	Processor	C		D	
Pin	Pin	SERCOM		SERCOM_ALT	
D0	PA11	SERCOM0	PAD[3]	SERCOM2	PAD[3]
D1	PA10	SERCOM0	PAD[2]	SERCOM2	PAD[2]
D2	PA08	SERCOM0	PAD[0]	SERCOM2	PAD[0]
D3	PA09	SERCOM0	PAD[1]	SERCOM2	PAD[1]
D4	PA14	SERCOM2	PAD[2]	SERCOM4	PAD[2]
D5	PA15	SERCOM2	PAD[3]	SERCOM4	PAD[3]
D6	PA20	SERCOM5	PAD[2]	SERCOM3	PAD[2]
D7	PA21	SERCOM5	PAD[3]	SERCOM3	PAD[3]
D8	PA06			SERCOM0	PAD[2]
D9	PA07			SERCOM0	PAD[3]
D10	PA18	SERCOM1	PAD[2]	SERCOM3	PAD[2]
D11	PA16	SERCOM1	PAD[0]	SERCOM3	PAD[0]
D12	PA19	SERCOM1	PAD[3]	SERCOM3	PAD[3]
D13	PA17	SERCOM1	PAD[1]	SERCOM3	PAD[1]
A0	PA02				
A1	PB08			SERCOM4	PAD[0]
A2	PB09			SERCOM4	PAD[1]
A3	PA04			SERCOM0	PAD[0]
A4	PA05			SERCOM0	PAD[1]
A5	PB02			SERCOM5	PAD[0]
SDA	PA22	SERCOM3	PAD[0]	SERCOM5	PAD[0]
SCL	PA23	SERCOM3	PAD[1]	SERCOM5	PAD[1]

Glad to finally have it working lol. Tested it and it is able to communicate with my ADC.