Go Down

Topic: Arduino as SPI Master and Slave Demo Code (Read 43964 times) previous topic - next topic

LinhartR

Aug 26, 2013, 02:21 am Last Edit: May 11, 2015, 02:33 am by LinhartR
What a fun project this turned out to be! I feel like I just finished a good video game or something. I hope I'm not the only one who found the documentation for Arduino SPI challenging. For example the SPI library does not support SPI slave mode. This doesn't present too much of a problem but does require you to do a bit more of the "dirty work" yourself when working on the SPI slave sketch. I've attached my sketches for an Arduino SPI Master and Slave. The code is heavily documented and loaded with Serial.println output for debugging. Don't forget to make a Gnd connection between each Arduino. I'm hoping to have more Arduinos to work with and would enjoy testing a SPI master with two or more SPI slaves. My demo video can be seen on YouTube at http://youtu.be/A9oSX_dwJKQ

If you would like to help fund this and other projects please consider a donation to my PayPal account at https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=U48JEW8HSQFM2. Thank you!

nickgammon

http://www.gammon.com.au/spi

On that page:

http://www.gammon.com.au/forum/?id=10892&reply=1#reply1  ("How to make an SPI slave")
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

LinhartR

Hey Nick! Great reference! Most of what I did was actually based on this article. You are even credited in the sketches I uploaded. I appreciated but chose not to use an Interrupt Service Routine in my solution. I must have been viewing your article from a mirror site since I didn't see any of the follow up posts. Looks like I've got some more reading to do.
One thing I feel that I feel is significant in my example is controlling the MISO pin. Many of the examples I found ignored this important requirement when dealing with multiple slaves. You've inspired me to try implementing the SS as an interrupt. The biggest challenge I found was ensuring the slave had written it's data to the DR before the master begins the SPI transfer. I thought about using SS to signal each transfer and this would be much easier as an ISR.
I'm looking forward to purchasing a sensor board and SPI based sensor modules to learn more about the communication protocols used by these devices.

nickgammon

Quote

The biggest challenge I found was ensuring the slave had written it's data to the DR before the master begins the SPI transfer. I thought about using SS to signal each transfer and this would be much easier as an ISR.


I don't understand that bit. The master controls the timing (it sends the clock pulses). Once an SPI.transfer call completes the data is transferred. There is no waiting.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

LinhartR


Quote

The biggest challenge I found was ensuring the slave had written it's data to the DR before the master begins the SPI transfer. I thought about using SS to signal each transfer and this would be much easier as an ISR.


I don't understand that bit. The master controls the timing (it sends the clock pulses). Once an SPI.transfer call completes the data is transferred. There is no waiting.


If the master expects a reply from the slave, the slave has no way of knowing when the master is going start cycling the clock. It has to write each bit to the DR before the master tries to clock it out.

nickgammon

OK, I see what you mean. From page 171 of the datasheet:



Basically you set up (get the data ready) on the opposite edge to the sample one. An interesting question is: "when does the first bit get set up?". I presume the answer would be:


  • After SS is asserted; or

  • As soon as possible after a response is requested


Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

mr_pacheko

Hy Guys,

First of all, thanks for all the info, very good work!

I'm trying to do the same, but with a Master Arduino Due, and Slave Arduino Uno.

Colud be a problem with the SS pin to set the logical state if Due works in 3.3v and Uno in 5v?

Regards

LinhartR

I've always seen a level shifter used in cases like this.

Hy Guys,

First of all, thanks for all the info, very good work!

I'm trying to do the same, but with a Master Arduino Due, and Slave Arduino Uno.

Colud be a problem with the SS pin to set the logical state if Due works in 3.3v and Uno in 5v?

Regards

Adithyag91

In SlaveInit(),shouldn't the MISO pin be declared as OUTPUT?

ShapeShifter

In SlaveInit(),shouldn't the MISO pin be declared as OUTPUT?
Sorry, old question, but I just happened to see it.

No, it should be initialized as INPUT. It is set to OUTPUT when the slave select line is recognize as active (LOW), and returned to INPUT when the slave select line is recognized as inactive (HIGH.) The reason is that there could multiple slaves on the SPI bus, and only one of them (the one with the active slave select) should be trying to drive the bus at a time. The others should have their MISO outputs at high impedance. On the Arduino, you set an output to high impedance by making it an input.

gchiban

#10
Jul 20, 2015, 03:41 pm Last Edit: Jul 20, 2015, 03:42 pm by gchiban
Hi, I need to comunicate two Arduino Leonardo by SPI, but the Leonardo doesn't have the SS pin available to conect outside. I tried to define other digital pin (pin 10) as a SS one in both Arduino, but i couldnĀ“t comunicate them so far. I checked the code and i couldnĀ“t find anything wrong, i suppose that i didn't configure the Slave Arduino well.
If you have any information it will be really appreciated.
Thank you all!

MahtaE

#11
Aug 26, 2015, 03:39 pm Last Edit: Aug 26, 2015, 03:41 pm by MahtaE
Hi all, is there any way to use the ShiftIn command for using Arduino as the SPI slave?

ShapeShifter

Hi all, is there any way to use the ShiftIn command for using Arduino as the SPI slave?
No. ShiftIn() is a function that performs a software implementation (bit-banging) of a master device acting to shift data in on a pin. It generates the clock signal, and samples the input pin for the data.

Any slave implementation requires that the master generates the clock (and the slave select signal) while the slave listens for the select and shifts data out according to the clock signal.

Being an SPI master is easy, being the slave is a lot more complicated (hence the basis of the discussion here, if it were simple like using ShiftIn(), there wouldn't be this thread.)

Saha22

Hi,
I tried using the code posted with proteus using 2 arduino uno, I did not have errors during the simulation but the diodes do not work by clicking on the button.

Here is my schema on ISIS.
If someone can help me I will be really grateful.

fajarkholid

Chould you help me to make SPI comunication betwn 2 orduinoes to monitor value of ACD on Slave... please thank U...
 this is my code but it's not succes ...

MASTER:
void  initSPI_Master()  {
DDRB  |=  (1<<2)|(1<<3)|(1<<5);    //  SCK,  MOSI  dan  SS  menjadi  output
DDRB  &=  ~(1<<4);                  //  MISO  menjadi  input
SPCR  |=  (1<<MSTR);                //  SPI  sebagai  master
SPCR  |=  (1<<SPR0)|(1<<SPR1);      //  Pembagi  clock  =  128
SPCR  |=  (1<<SPE);                 //  Aktifkan  SPI
}
void  setup()  {
initSPI_Master();
Serial.begin(9600);
pinMode(2,  INPUT);pinMode(3,  INPUT); pinMode(4,  INPUT);
digitalWrite(2,HIGH);digitalWrite(3,  HIGH); digitalWrite(4,  HIGH);
}
void  loop()  {
//char adc =  String(analogRead(0), DEC);
int adc=analogRead(A0);
if(digitalRead(2)==LOW)
kirimData(5);
else  if(digitalRead(3)==LOW)
kirimData(10);
else  if(digitalRead(4)==LOW)
kirimData(adc);
Serial.print(adc);

}
void  kirimData(char  data)  {
SPDR  =  data;  //  Kirim  data
while(!(SPSR  &  (1<<SPIF)));    //  Tunggu  sampai  pengiriman
delay(500);
}


SLAVE:

unsigned  char  data;
void  initSPI_Slave()  {
DDRB  &=  ~((1<<2)|(1<<3)|(1<<5));      //  SCK,  MOSI  dan  SS  menjadi  input
DDRB  |=  (1<<4);  //  MISO  menjadi  output
SPCR  &=  ~(1<<MSTR);                                   //  SPI  sebagai  slave
SPCR  |=  (1<<SPR0)|(1<<SPR1);               //  Pembagi  clock  =  128
SPCR  |=  (1<<SPE);                                       //  Aktifkan  SPI
}
void  setup()  {
initSPI_Slave();
Serial.begin(9600);
}
void  loop()  {
while(!(SPSR  &  (1<<SPIF)));                 //  Tunggu  data  masuk
data  =  SPDR;

//  Menyimpan  isi  register  SPDR  ke  variabel  data
Serial.println("Data Receive  ==>    ");
Serial.println(data,HEX);
delay(1000);
}

Go Up