Arduino SPI Master Communicating To Electron Slave

I am trying to use SPI to communicate between an Intel Galileo to a Particle Electron. I have an existing project that I unfortunately cannot refactor to use any other communication protocol. I uploaded the example slave code from the Electron documentation and a basic master code to the Arduino. I have been unsuccessful at getting any information between the two. I am also testing this with an UNO to no avail.

Wiring

Arduino ----> Electron
13 —> SCK —> A3
12 —> MISO —> A4
11 —> MOSI —> A5
10 —> SS —> A2

Electron SPI Slave example

// SPI slave example
static uint8_t rx_buffer[64];
static uint8_t tx_buffer[64];
static uint32_t select_state = 0x00;
static uint32_t transfer_state = 0x00;

void onTransferFinished() {
	transfer_state = 1;
}

void onSelect(uint8_t state) {
	if (state)
		select_state = state;
}

/* executes once at startup */
void setup() {
	Serial.begin(9600);
	for (int i = 0; i < sizeof(tx_buffer); i++)
	  tx_buffer[i] = (uint8_t)i;
	SPI.onSelect(onSelect);
	SPI.begin(SPI_MODE_SLAVE, A2);
}

/* executes continuously after setup() runs */
void loop() {
	while (1) {
		while(select_state == 0);
		select_state = 0;

		transfer_state = 0;
		SPI.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), onTransferFinished);
		while(transfer_state == 0);
		if (SPI.available() > 0) {
			Serial.printf("Received %d bytes", SPI.available());
			Serial.println();
			for (int i = 0; i < SPI.available(); i++) {
				Serial.printf("%02x ", rx_buffer[i]);
			}
			Serial.println();
		}
	}
}

Arduino SPI Master Example

#include <SPI.h>

void setup (void)
{

  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on
  SPI.begin ();

  // Slow down the master a bit
  SPI.setClockDivider(SPI_CLOCK_DIV8);

}  // end of setup


void loop (void)
{

  char c;

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test string
  for (const char * p = "Hello, world!\n" ; c = *p; p++)
	SPI.transfer (c);

  // disable Slave Select
  digitalWrite(SS, HIGH);

  delay (1000);  // 1 seconds delay 
}  // end of loop

Any help is greatly appreciated!

Adding some debug statements in your receiver code might give you some clues what gets executed and what not.

But since you are using AUTOMATIC mode but your while(1) kills the cloud connection, I’d fix that first.

1 Like

After removing the while(1) loop and adding some print statements the receiver code, it seems that the receiver gets stuck in the while(select_state == 0) loop. After looking at the documentation for the SPI library it seems like the Electron is not reacting to the Slave Select pin being written low. I checked the SS pin with a multimeter and it is definitely writing HIGH and LOW voltages from the Arduino.

I'm not sure, but I'd suspect the SPI.onSelect() is hooking up a FALLING edge interrupt on that pin. So the function hooked up should be treated like any other ISR, which means all global variables manipulated therein have to be marked volatile as they can mutate out of normal code flow.

And in addition, not only your while(1) can pose a problem, but all your loops that might be running longer than 10 seconds. In such loops the least you need to have is a Particle.process() call.
e.g.

  while(!select_state) Particle.process();

BTW, AFAIK if you don't provide a callback function to SPI.transfer() the command will be executed synchronous.

https://docs.particle.io/reference/firmware/photon/#transfer-void-void-size_t-std-function-

Since your code waits for completion anyway, let this rather do the system, which does it best.

1 Like