I have recently been trying to send integers via SPI between two arduino Uno's. I am using the first example of Nick Gammons tutorial, and trying to modify it to get a basic understanding of how to communicate via SPI.
MASTER
// Written by Nick Gammon
// February 2011
#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
SLAVE - WITHOUT INTERRUPTS
// Written by Nick Gammon
// February 2011
#include <SPI.h>
char buf [100];
volatile byte pos;
volatile boolean process_it;
void setup (void)
{
Serial.begin (115200); // debugging
// turn on SPI in slave mode
SPCR |= bit (SPE);
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// get ready for an interrupt
pos = 0; // buffer empty
process_it = false;
// now turn on interrupts
SPI.attachInterrupt();
} // end of setup
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR; // grab byte from SPI Data Register
// add to buffer if room
if (pos < (sizeof (buf) - 1))
buf [pos++] = c;
// example: newline means time to process buffer
if (c == '\n')
process_it = true;
} // end of interrupt routine SPI_STC_vect
// main loop - wait for flag set in interrupt routine
void loop (void)
{
if (process_it)
{
buf [pos] = 0;
Serial.println (buf);
pos = 0;
process_it = false;
} // end of flag set
} // end of loop
SLAVE - WITH INTERRUPTS
// Written by Nick Gammon
// April 2011
// what to do with incoming data
byte command = 0;
// start of transaction, no command yet
void ss_falling ()
{
command = 0;
} // end of interrupt service routine (ISR) ss_falling
void setup (void)
{
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
// interrupt for SS falling edge
attachInterrupt (0, ss_falling, FALLING);
} // end of setup
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;
switch (command)
{
// no command? then this is the command
case 0:
command = c;
SPDR = 0;
break;
// add to incoming byte, return result
case 'a':
SPDR = c + 15; // add 15
break;
// subtract from incoming byte, return result
case 's':
SPDR = c - 8; // subtract 8
break;
} // end of switch
} // end of interrupt service routine (ISR) SPI_STC_vect
void loop (void)
{
// all done with interrupts
} // end of loop
ORIGINAL ISSUE - I am able to get this working, so the wiring is correct, however i am unable to get it to send anything other than a string. I can change the string and that works, but i am getting confused with pointers in C. Any code i have tried doesn't compile correctly, or doesn't send at all if it does compile. Could someone give me a clue as to where to start with this. My best effort is below
MASTER
#include <SPI.h>
int x = 10000;
int y = 20000;
int z = 30000;
byte High_x = highByte(x);
byte Low_x = lowByte(x);
byte High_y = highByte(y);
byte Low_y = lowByte(y);
byte High_z = highByte(z);
byte Low_z = lowByte(z);
int X = word(High_x<<8|Low_x);
int Y = word(High_y<<8|Low_y);
int Z = word(High_z<<8|Low_z);
byte myArray[7];
void setup (void)
{
Serial.begin(115200);
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);
myArray[0] = High_x;
myArray[1] = Low_x;
myArray[2] = High_y;
myArray[3] = Low_y;
myArray[4] = High_z;
myArray[5] = Low_z;
myArray[6] = 0;
Serial.println(X);
Serial.println(Y);
Serial.println(Z);
delay(2000);
}
void loop (void)
{
byte data;
// enable Slave Select
digitalWrite(SS, LOW); // SS is pin 10
// send test string
for (byte * p = myArray[0]; data = *p; p++)
SPI.transfer (data);
Serial.println("sending data");
// disable Slave Select
digitalWrite(SS, HIGH);
delay (1000); // 1 seconds delay
} // end of loop
SLAVE
#include <SPI.h>
byte buf [100];
volatile byte pos;
volatile boolean process_it;
void setup (void)
{
Serial.begin (115200); // debugging
// turn on SPI in slave mode
SPCR |= bit (SPE);
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// get ready for an interrupt
pos = 0; // buffer empty
process_it = false;
// now turn on interrupts
SPI.attachInterrupt();
Serial.println("End of Setup");
} // end of setup
// SPI interrupt routine
ISR (SPI_STC_vect)
{
Serial.println("Beginning of Interrupt Routine");
byte data = SPDR; // grab byte from SPI Data Register
// add to buffer if room
if (pos < (sizeof (buf) - 1))
buf [pos++] = data;
// example: newline means time to process buffer
if (data == '0')
process_it = true;
Serial.println("End of Interrupt Routine");
} // end of interrupt routine SPI_STC_vect
// main loop - wait for flag set in interrupt routine
void loop (void)
{
Serial.println("Beggining of Loop");
for(int i = 0; i < 100; i++)
if (process_it)
{
buf [pos] = 0;
Serial.println (buf[i]);
pos = 0;
process_it = false;
} // end of flag set
Serial.println("End of Loop");
} // end of loop
In the future i hope to send 10 16-bit integers over SPI from an arduino to an arduino or maybe arduino to a raspberry Pi.
Thanks
EDIT -I have started using the code that uses interrupts and managed to get the data i need sent across, however, i can only get the correct data by setting both the first and second element of the array to "High_x", otherwise it skips the first part of data?
NEW MASTER
#include <SPI.h>
int x = 10000;
int y = 20000;
int z = 30000;
byte High_x = highByte(x);
byte Low_x = lowByte(x);
byte High_y = highByte(y);
byte Low_y = lowByte(y);
byte High_z = highByte(z);
byte Low_z = lowByte(z);
int X = word(High_x<<8|Low_x);
int Y = word(High_y<<8|Low_y);
int Z = word(High_z<<8|Low_z);
byte myArray[8];
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);
myArray[0] = High_x;
myArray[1] = High_x;
myArray[2] = Low_x;
myArray[3] = High_y;
myArray[4] = Low_y;
myArray[5] = High_z;
myArray[6] = Low_z;
myArray[7] = 0;
Serial.print("wait for loop");
//Serial.println(X);
//Serial.println(Y);
//Serial.println(Z);
delay(2000);
}
void loop (void)
{
byte data;
// enable Slave Select
digitalWrite(SS, LOW); // SS is pin 10
// send test string
for (byte * p = &myArray[0]; data = *p; p++){
SPI.transfer (data);
}
// disable Slave Select
digitalWrite(SS, HIGH);
delay (1000); // 1 seconds delay
} // end of loop
NEW SLAVE
byte buf [100];
volatile byte pos;
// what to do with incoming data
byte command = 0;
// start of transaction, no command yet
void ss_falling ()
{
command = 0;
} // end of interrupt service routine (ISR) ss_falling
void setup (void)
{
Serial.begin(9600);
// have to send on master in, *slave out*
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
// interrupt for SS falling edge
attachInterrupt (0, ss_falling, FALLING);
} // end of setup
// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte data = SPDR;
// add to buffer if room
if (pos < (sizeof (buf) - 1))
buf [pos++] = data;
} // end of interrupt service routine (ISR) SPI_STC_vect
void loop (void)
{
for(int i = 0; i < 100; i++){
Serial.println (buf[i]);
pos = 0;
delay(1000);
}
} // end of loop
Any suggestions on why this is necessary? Is there some basic SPI idiosyncrasy I'm missing?
Thanks all
Ross