SPI2.transfer(tx_buffer, rx_buffer, sizeof(rx_buffer), NULL); gives me hardware error

I think you’re getting a hard fault on the SPI slave device because you have a Particle.publish in your onSelect handler. The onSelect is an interrupt handler and you can’t call Particle.publish in it. I wouldn’t even recommend calling Serial.print. You should only set the select_state flag.

As far as I can tell, you can’t use a single byte SPI transfer in SPI slave mode. I never get valid data doing that. You need to use the multi-byte DMA transfer mode.

I prefer to structure my code differently than the slave example in the docs. If you do the slave read from loop, it’s quite possible that you’ll miss the first few bytes of data, because the master device will start sending data very quickly after taking SS low. The caveat is that you have to be careful about reentrancy if you call SPI.transfer from an ISR. It does work if you use it carefully, however.

Here’s my master code:

#include "Particle.h"

SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler;

const unsigned long SEND_PERIOD_MS = 1000;
const int SS_PIN = A2;
const size_t NUM_VALUES = 2;

unsigned long lastSend = 0;
uint32_t rcvdValues[NUM_VALUES];
uint32_t sendValues[NUM_VALUES];


void setup() {
	Serial.begin(9600);

	SPI.begin(SPI_MODE_MASTER, SS_PIN);
}

void loop() {
	if (millis() - lastSend >= SEND_PERIOD_MS) {
		lastSend = millis();

		digitalWrite(SS_PIN, LOW);

		for(size_t ii = 0; ii < NUM_VALUES; ii++) {
			sendValues[ii] = rand() % 256;
		}
		Log.info("sendValues[0]=0x%lx sendValues[1]=0x%lx", sendValues[0], sendValues[1]);

		SPI.transfer(sendValues, rcvdValues, NUM_VALUES * sizeof(uint32_t), 0);

		Log.info("rcvdValues[0]=0x%lx rcvdValues[1]=0x%lx", rcvdValues[0], rcvdValues[1]);

		digitalWrite(SS_PIN, HIGH);
	}
}

And slave code:

#include "Particle.h"

SYSTEM_THREAD(ENABLED);

SerialLogHandler logHandler;

void slaveSelect(uint8_t state);
void slaveCallback();

const int SS_PIN = A2;
const size_t NUM_VALUES = 2;

bool gotValue = false;

uint32_t rcvdValues[NUM_VALUES];
uint32_t sendValues[NUM_VALUES];

void setup() {
	Serial.begin(9600);

	for(size_t ii = 0; ii < NUM_VALUES; ii++) {
		sendValues[ii] = 0;
	}

	SPI.onSelect(slaveSelect);
	SPI.begin(SPI_MODE_SLAVE, SS_PIN);
}

void loop() {
	if (gotValue) {
		gotValue = false;

		Log.info("rcvdValues[0]=0x%lx rcvdValues[1]=0x%lx", rcvdValues[0], rcvdValues[1]);

		for(size_t ii = 0; ii < NUM_VALUES; ii++) {
			sendValues[ii] = rcvdValues[ii];
		}

	}
}

void slaveSelect(uint8_t state) {
	if (state) {
		SPI.transfer(sendValues, rcvdValues, NUM_VALUES * sizeof(uint32_t), slaveCallback);
	}
}

void slaveCallback() {
	gotValue = true;
}

3 Likes