Seeed-Studio / XIAO_Series

MIT License
10 stars 0 forks source link

Any XIAO SPI to any other XIAO #10

Open hpssjellis opened 2 weeks ago

hpssjellis commented 2 weeks ago

Any XIAO SPI to any other XIAO

Presently data is not moving between the boards.

@LynnL4

Background: The XIAO only has 10 pins most other boards have 20-40 pins. Many large projects need more pins, and a multiplexer is just another layer of confusion. Solution: Connect 2 or more XIAO together.

I have I2C and UART XIAO to XIAO communication working here

XIAO SPI works fine with other boards that need SPI like a XIAO to OLED etc, so the issue should not be with the receiver (Master) the issue is probably with the Transmitter (Slave).

Here is my semi-working code: I typically make code as simple as possible but have tried several ideas here to make things work. It is likely that I have missed some simple thing.

Slave (transmitter)

/*
Connect all wires the same on both XIAO's

GND      to GND
3V3      to 3V3
MOSI D10 to MOSI D10
MISO D9  to MISO D9
SCK  D8  to SCK  D8
SS  D0   to SS   D0

*/

#include <SPI.h>

// Note: XIAO-ESP32C3  SS is D7

#define SS D0         // Needed for XIAO-SAMD
const int mySS = SS;  // SS is D7 on XIAO-ESP

void setup() {
  pinMode(mySS, OUTPUT);
  digitalWrite(mySS, HIGH);
  SPI.begin();
  //SPI.setDataMode(SPI_MODE3); // Set the SPI mode to match the transmitter
  SPI.setClockDivider(SPI_CLOCK_DIV128); // Adjust the clock divider if necessary

}

void loop() {
  digitalWrite(mySS, LOW);
  // SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0));
  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 
  SPI.transfer(200);
  SPI.endTransaction();
  digitalWrite(mySS, HIGH);
  delay(1000);
}

and the much longer Master (receiver) code:

/*
Connect all wires the same on both XIAO's

GND      to GND
3V3      to 3V3
MOSI D10 to MOSI D10
MISO D9  to MISO D9
SCK  D8  to SCK  D8
SS  D0   to SS   D0

*/

#include <SPI.h>

#define SS D0         // Needed for XIAO-SAMD
const int mySS = SS;  // SS is D7 on XIAO-ESP

volatile byte myReceivedData;

void setup() {
  pinMode(mySS, INPUT_PULLUP);
  SPI.begin();
  //SPI.setDataMode(SPI_MODE0); // Set the SPI mode to match the transmitter
  // SPI.setDataMode(SPI_MODE3); // Set the SPI mode to match the transmitter
  //SPI.setClockDivider(SPI_CLOCK_DIV8); // Adjust the clock divider if necessary
  SPI.setClockDivider(SPI_CLOCK_DIV128); // Adjust the clock divider if necessary
  Serial.begin(115200);
}

void loop() {

  if (digitalRead(mySS) == LOW) {
    delay(1);
    // SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0));
    SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); 
    myReceivedData = SPI.transfer(0); // Read data from the transmitter

    SPI.endTransaction();
    Serial.print("myReceivedData:");    
    Serial.println(myReceivedData);
    Serial.print("MOSI:"+String(MOSI) + ", MISO:"+String(MISO));
    Serial.println(", SCK:"+String(SCK)+", SS:"+String(SS));
    Serial.println("mySS:"+String(mySS) +", D0:"+String(D0) + ", D2:" + String(D2) + ", D4:" + String(D4) + ", D7:"+String(D7));
    Serial.println("SPI_MODE0:"+String(SPI_MODE0)+", SPI_CLOCK_DIV8:"+String(SPI_CLOCK_DIV8));
    Serial.println("----------------");
    delay(1);
  }
}

/*
 * SPI Data Mode: Determines the clock polarity (CPOL) and clock phase (CPHA). There are four possible modes:

SPI_MODE0 (CPOL = 0, CPHA = 0)
SPI_MODE1 (CPOL = 0, CPHA = 1)
SPI_MODE2 (CPOL = 1, CPHA = 0)
SPI_MODE3 (CPOL = 1, CPHA = 1)
Example: SPI.setDataMode(SPI_MODE0);

Clock Divider: Sets the SPI clock frequency relative to the system clock frequency. Possible dividers are:

SPI_CLOCK_DIV2
SPI_CLOCK_DIV4
SPI_CLOCK_DIV8
SPI_CLOCK_DIV16
SPI_CLOCK_DIV32
SPI_CLOCK_DIV64
SPI_CLOCK_DIV128
Example: SPI.setClockDivider(SPI_CLOCK_DIV8);

Bit Order: Defines whether the most significant bit (MSB) or least significant bit (LSB) is sent first.

MSBFIRST
LSBFIRST
Example: SPI.setBitOrder(MSBFIRST);

Clock Speed: Specifies the desired SPI clock frequency in Hz. This setting is used when more fine-grained control of the SPI clock frequency is required.

Example: SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); (where 1000000 is the clock speed in Hz)

DATA:

XIAO-ESP32C3
myReceivedData:255
MOSI:10, MISO:9, SCK:8, SS:2
mySS:2, D0:2, D2:4, D4:6, D7:20
SPI_MODE0:0, SPI_CLOCK_DIV8:4984833
----------------

XIAO-ESP32S3-Sense
myReceivedData:0
MOSI:9, MISO:8, SCK:7, SS:1
mySS:1, D0:1, D2:3, D4:5, D7:44
SPI_MODE0:0, SPI_CLOCK_DIV8:4984833
----------------

XIAO-SAMD

myReceivedData:255
MOSI:10, MISO:9, SCK:8, SS:0
mySS:0, D0:0, D2:2, D4:4, D7:7
SPI_MODE0:2, SPI_CLOCK_DIV8:12
----------------

From SPI.h
  // Default speed set to 4MHz, SPI mode set to MODE 0 and Bit order set to MSB first.
  SPISettings() { init_AlwaysInline(4000000, MSBFIRST, SPI_MODE0); }

*/
hpssjellis commented 2 weeks ago

I found the esp32spiSlave library, which makes sense that the slave is not configured to send, but presently dont have it running.

limengdu commented 2 weeks ago

The idea of pin expansion via spi in series with multiple xiao is quite interesting. Maybe we'll verify it for you and export it as a wiki.

hpssjellis commented 2 weeks ago

The idea of pin expansion via spi in series with multiple xiao is quite interesting. Maybe we'll verify it for you and export it as a wiki.

@limengdu

On MBED an entire library is used for the SpiSlave https://os.mbed.com/docs/mbed-os/v6.16/apis/spislave.html It makes sense that MISO, MOSI, SCK will need to be set differently for the slave, and perhaps the spi.transfer function needs to work differently. I will continue to work on it, but if you can give me some suggestions that would be great.

I think Eric Pan knows that you are welcome to use any of my open source XIAO-ESP32S3-sense maker100-eco code on your wiki. Just credit both Jeremy Ellis and the TinyML4D community.

hpssjellis commented 2 weeks ago

@limengdu The following SPI slave code is different than my original and compiled and sent some data but still is not working. It is based on the idea that the SPIClass has functionality to work as a slave device, but it really needs to be an easier, better system.

I did find out that I need to plug the main usb device into the usb plug a few times before both XIAO's start properly. Kind of strange but might explain some earlier frustrations.


#define SS_PIN D0      // Slave Select pin
#define MOSI_PIN D10   // Master Out Slave In
#define MISO_PIN D9    // Master In Slave Out
#define SCK_PIN D8     // Serial Clock

//volatile byte myReceivedData;
volatile byte mySendingData;

void setup() {
  pinMode(SS_PIN, INPUT_PULLUP);  // Set SS pin as input with pull-up resistor
  SPI.begin(SCK_PIN, MISO_PIN, MOSI_PIN);  // Initialize as SPI slave

  // Attach interrupt to the SPI slave select pin
  attachInterrupt(digitalPinToInterrupt(SS_PIN), onReceive, FALLING);

  Serial.begin(115200); // Initialize serial communication for debugging
}

void loop() {

  Serial.print("Slave Sent: ");
  Serial.println(mySendingData, HEX);

  delay(1000);
}

void onReceive() {
  SPIClass *spi = &SPI;
  mySendingData = 3
  spi->transfer(mySendingData);
}
hpssjellis commented 2 weeks ago

Unless I learn something new, I am stuck. Nothing is consistent, even the library esp32spiSlave does not seem to work with the XIAO boards. Most Arduino systems only work for an old AVR method, the new MBED boards also don't seem to work. As far as I can tell putting the SPIClass into slave mode is the only issue, but I can't seem to get it working. Hopefully someone can have a look at this and make some suggestions.

limengdu commented 1 week ago

Thanks for the detailed description, I'll come back and look into your scenario after I've been busy with my latest business. We can discuss and study the details of it together.

hpssjellis commented 1 week ago

Found this repository that looks promising. I will try to test it later.

https://github.com/ramiss/SeeeduinoXIAO_SPISlave