6
\$\begingroup\$

I'm trying unsuccessfully to make two Arduinos talk using SPI.

I found this great tutorial. The SPI Master send a constant string each second to the SPI Slave, which resends to the USART for depuration purpose. The problem is that nothing is printed on the Arduino's Serial Monitor.

The SPI Master is connected on a second computer and also sends the string to USART. The string arrives at the computer.

I tested all of Arduinos pins that I use and they're working (on both Arduinos).

My setup

  • Arduino Leonardo: SPI Master
  • Seeeduino: SPI Slave

    Leonardo_________Seeeduino
    (10) SS--------->(10) SS
    (11) MOSI------->(11) MOSI
    (12) MISO<-------(12) MISO
    (13) SCLK------->(13) SCLK

setup

The code used on the SPI MASTER:

#include <SPI.h>

void setup (void)
{
  Serial.begin(115200);
  digitalWrite(SS, HIGH);
  SPI.begin ();
  SPI.setClockDivider(SPI_CLOCK_DIV8);
}

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);
    Serial.print(c);
  }

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

  delay (1000);
}

And the code used on the SPI SLAVE:

#include <SPI.h>

char buf [100];
volatile byte pos;
volatile boolean process_it;

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

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

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

  // get ready for an interrupt 
  pos = 0;   // buffer empty
  process_it = false;

  // now turn on interrupts
  SPI.attachInterrupt();
}


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;  // grab byte from SPI Data Register
  if (pos < sizeof buf)
  {
    buf [pos++] = c;
    if (c == '\n')
      process_it = true;
  }
}

void loop (void)
{
  if (process_it)
  {
    buf [pos] = 0;  
    Serial.println (buf);
    pos = 0;
    process_it = false;
  } 
}

Is there something wrong on this project? How can I make it work?

\$\endgroup\$
3
  • \$\begingroup\$ It sure looks like you're doing everything right. Do you have access to a scope or logic analyzer to observe the activity on the pins? \$\endgroup\$
    – Dave Tweed
    Sep 26, 2012 at 21:22
  • \$\begingroup\$ @DaveTweed Unfortunately I don't have a logic analyser, but I do have an OLD oscilloscope: a Minipa's MO-1222. I've tried to use it to solve this problem but I couldn't see any signal. Despite having enough sampling frequency for that, I don't know how to configure it (triggers, etc.) to really get to analyze the signals. \$\endgroup\$
    – borges
    Sep 26, 2012 at 21:51
  • \$\begingroup\$ That looks like a pretty decent scope for this sort of thing (20 MHz, dual trace analog). It would be great if you could find someone to sit down with you for an hour or so to show you how to use it; unfortunately, it would be very difficult to do it through a forum like this. It's a skill you'll use throughout your career. \$\endgroup\$
    – Dave Tweed
    Sep 27, 2012 at 1:35

4 Answers 4

7
\$\begingroup\$

I took a quick look at the Arduino SPI library and couldn't find the attachInterrupt() function. I assume that you're using an extended library of some sort and I'll make the assumption that it works although I would like to see how it's implemented underneath.

A couple things that I saw:

  1. This compiles? if (pos < sizeof buf) - it probably needs to be if (pos < sizeof(buf))
  2. In the sample code on the forum, he has a key line right here that you're missing in your slave code:

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

Without this your receive interrupt probably won't fire. I also don't see where global interrupts are being enabled although I have no idea if Arduino takes care of that for you under the hood. I also haven't bothered to look up what any of those registers mean, I'm trying my best to go by memory of AVR's SPI registers.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Incredibly the code compiles! Despite this, I've modified it following your suggestion. About the SPI.attachInterrupt() function, I don't know why it is not documented, but it is implemented as we can see here. It does exactly what you said in the second point. Thank you for your help! It was because of you that could indirectly get the answer. \$\endgroup\$
    – borges
    Sep 27, 2012 at 20:30
  • \$\begingroup\$ @borges, cool. If it fixed your problem, feel free to mark your own answer as the accepted answer. \$\endgroup\$
    – Jon L
    Sep 27, 2012 at 20:35
  • \$\begingroup\$ For curious future visitors, looks like sizeof buf actually compiles. Tested on C++14: cpp.sh/2kl75 \$\endgroup\$ Mar 6, 2017 at 20:26
6
\$\begingroup\$

The problem is with the Arduino Leonardo. According to the official Arduino Leonardo website:

SPI: on the ICSP header. These pins support SPI communication using the SPI library. Note that the SPI pins are not connected to any of the digital I/O pins as they are on the Uno, They are only available on the ICSP connector. This means that if you have a shield that uses SPI, but does NOT have a 6-pin ICSP connector that connects to the Leonardo's 6-pin ICSP header, the shield will not work.

Now, the SPI pins are accessed only through the ICSP connector.

\$\endgroup\$
0
\$\begingroup\$

Or try setting your baud rate in Arduino serial debug screen to 115200.

In the SPI Slave example, from Nick Gammon's blog post you linked sets the baud rate to 115200 on line 13 of the Slave example. Change the baud rate setting in the Arduino debug environment ( watching for the Hello World! message ), and it will show correctly.

Alternatively, you can change the Serial.Begin() statement to 9600, but then it will delay the speed of the message display (debug), and possibly slow down the Arduino.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Can you explain further why you think that's the case? The code does set the speed at 115200 but I don't see any indication given the accepted answer that was the cause. \$\endgroup\$
    – PeterJ
    Jun 25, 2014 at 14:18
-2
\$\begingroup\$

You have to cross over your wires. Otherwise everyone is just talking on MOSI<->MOSI and everyone is just listening on MISO<->MISO.

(11) MOSI------->(11) MISO (12) MISO<-------(12) MOSI

\$\endgroup\$
2
  • \$\begingroup\$ This answer does not seem to add to the existing accepted answer. \$\endgroup\$
    – David
    Sep 30, 2014 at 22:25
  • \$\begingroup\$ It is even clearly wrong : MOSI and MISO stands for Master Out/In Slave In/Out. which is needed to be able to function as a bus. I one had to cross the wires, it would make it impossible to have multiple slaves with the same master. \$\endgroup\$
    – Camion
    Dec 13, 2021 at 12:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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