1

I have to interface an Arduino Mega as a slave with a SPI master running at 1 MHz SCK. The master will send and ask for two bytes in a single transaction. I tried using the following code for the Mega. Its intended functionality is to store the master's sent data in acc and return local data ret, which is simply an integer to be incremented every transaction.

However, while the master data is stored in acc (verified through serial output), the data returned to the master is not the value in ret. Instead, the first response byte is correct (MSB of ret) and the second response byte is just the first byte received by the Mega, which was the value already present in SPDR.

How do I send the second byte of ret as the second byte of the response? What am I doing wrong?

// SPI Slave

#include <SPI.h>

// return to master
volatile unsigned int ret;

// accept from master
volatile unsigned int acc;

// MSB/LSB indicator
volatile byte SB;

void setup(void)
{

  ret = 0;
  SB = 0;

  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // turn on interrupts
  SPCR |= _BV(SPIE);

  // set CPOL, CPHA modes
  // byte dataMode = 0;
  // SPCR = (SPCR & ~SPI_MODE_MASK) | dataMode;

}

// SPI interrupt routine
ISR(SPI_STC_vect)
{

  if(SB == 0) {
    acc = SPDR << 8;
    SPDR = ret;
    ret++;
  }
  else {
    acc += SPDR;
    SPDR = ret >> 8;
  }
  SB = (SB + 1) & 0x01;

}

void loop(void)
{
  // interrupt processing only
}

Edit Changed SCK from 16 MHz to 1 MHz

  • 1
    Have you done the timing math yet? – Ignacio Vazquez-Abrams Nov 30 '16 at 7:00
  • I don't know which timing you're asking for. Are you saying that the ISR is too long? – Sampooran Kalra Nov 30 '16 at 9:29
1

You might need to check the Arduino Mega/ATmega2560 product description and SPI slave mode.

In SPI Slave mode, the control logic will sample the incoming signal of the SCK pin. To ensure correct sampling of the clock signal, the minimum low and high periods should be: Low period: longer than 2 CPU clock cycles. High period: longer than 2 CPU clock cycles.

This implies the maximum SCK in slave mode. 16 MHz SCK would be too fast for an Arduino Mega (at 16 MHz).

Also there is a significant latency to the ISR. To achieve higher slave mode clock frequency:

  1. Time between slave mode chip select and clock must be stretched to compensate for the ISR latency.
  2. The ISR will need to busy wait for all data (as the Arduino SPI transfer() is implemented).

Cheers!

  • The master is running at 1 MHz. I'm sorry for the wrong info. Corrected the question. – Sampooran Kalra Nov 30 '16 at 14:27
  • Great! Now you need to show how you have verified the code. Please remember that Serial output in an ISR is not a very good idea. – Mikael Patel Nov 30 '16 at 15:11
  • I did use Serial output within the ISR for verification, but the final code is what I posted. The bytes returned to the master were extracted on the master side, which were the same in both cases with or without Serial. – Sampooran Kalra Nov 30 '16 at 22:30
1

I'm late to the party, but...

I experienced exactly the same issues having a Arduino Uno as a SPI slave communicating to a Arduino Mega as SPI master. My conclusion is that the slave must take some time to process the SPI transfer of the first byte (your code in the SPI interrupt handler), but the master is not waiting for it. So the transfer of the second byte starts before your handler is completely executed, so the master receives the same byte again.

In my case, I fixed this with an ugly sleep in the master before sending the second byte:

SPI.beginTransaction(spi_settings);
word input = 0;
digitalWrite(spi_devices[port].pin_ss, LOW);
input |= SPI.transfer(output >> 8) << 8;
delayMicroseconds(20); // Must give time to slave to read first byte
input |= SPI.transfer(output);
digitalWrite(spi_devices[port].pin_ss, HIGH);
SPI.endTransaction();

Not elegant, but it works.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.