I have two Arduinos communicating with SPI. The slave sends 12 bytes to the master and then goes to sleep until awakened by a pin interrupt (pin tied to SS).
I have this working fine, except that I have to add a 20 uS delay between each request from the master, as suggested by Nick Gammon on his page: http://www.gammon.com.au/spi
I'd like the transfer to happen as fast as possible, and the delay adds an overhead of 240 uS, which makes it very slow for SPI (almost as slow as I2C). My question is: Is there a way to reliably send/receive 12 bytes without adding delays? Here's my current working code:
Master (controller):
#include <SPI.h>
byte data[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
void setup(void) {
pinMode(2, OUTPUT);
digitalWrite(2, HIGH); // ensure SS stays high for now
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV32); //2 MHz for NRF52840
}
byte transferAndWait(const byte what) {
byte a = SPI.transfer(what);
delayMicroseconds(20);
return a;
}
void loop(void) {
digitalWrite(2, LOW);
transferAndWait(0);
for (byte i = 0; i < 12; i++) {
data[i] = transferAndWait(i + 1);
}
digitalWrite(2, HIGH);
for (byte i = 0; i < 12; i++) {
Serial.println(data[i]);
}
Serial.println("");
delay(50);
}
Slave (peripheral):
#include <SPI.h>
#include <avr/sleep.h>
#include <avr/power.h>
bool dataSent = false;
volatile byte data[] = { 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
void setup(void) {
Serial.begin(115200);
// turn on SPI in slave mode
SPCR |= bit(SPE);
pinMode(MISO, OUTPUT);
SPI.attachInterrupt();
pinMode(0, INPUT_PULLUP);
attachInterrupt(0, pinFall, FALLING);
}
void pinFall() { //just used to wake up MCU
}
// SPI interrupt routine
ISR(SPI_STC_vect) {
byte c = SPDR;
SPDR = data[c];
if (c == 12) {
delayMicroseconds(10); //needed for sending the last byte before sleeping
dataSent = true;
}
}
void loop(void) {
if (dataSent == true) {
dataSent = false;
set_sleep_mode(SLEEP_MODE_STANDBY);
cli(); //turn off interrupts
power_adc_disable(); //turn off the ADC to save a little more power
sleep_enable();
sei(); //turn on interrupts immediately before sleeping
sleep_cpu();
//sleeping__________________________________
sleep_disable(); //disable sleep after waking
power_adc_enable();
}
}