Go Down

Topic: Tutorial: Two Arduino SPI communication (Read 5138 times) previous topic - next topic

davyzhu

Two arduino communicate via SPI bus.

Master send data to slave, slave +1 to data and send back, then master
+1 and send to slave, and slave do +1 ... again and again.

Slave transmite data is initiated by Master. Master fake the
transmission by write 0x0 data to SPDR, which will generate SPI clock.

The most possible wrong in code is master should receive a data ready
signal from slave that slave have +1 data in SPDR(SPI data register),
or slave may return the data that received from master. The drawback
of SPI is it doesn't have signal like I2C's ack that two side don't
even know whether they have received the data.

Master
Code: [Select]

// spi master
//arduino spi pin
//10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK)

#include <SPI.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include "pins_arduino.h"

#define SDRDY 9 // slave data ready

#define mackPin PINB3

byte t=0;
byte r=0;
void setup() {
  pinMode(SDRDY, INPUT);
  SPI_MasterInit();
}

void loop() {
  digitalWrite(SS, LOW);
  t = r + 1;
  if (t>=16) t=0;
  t=SPI_MasterTransmit(t);

  //block when slave data is not ready (not write to SPDR yet) 
  while (digitalRead(SDRDY) == LOW)
   ;

  r = SPI_MasterReceive();

  digitalWrite(SS, HIGH);
}

// copy from http://arduino.googlecode.com/svn
// SPI.cpp, SPI.h
void SPI_MasterInit(void)
{
  pinMode(SCK, OUTPUT);
  pinMode(MOSI, OUTPUT);
  pinMode(SS, OUTPUT);

  digitalWrite(SCK, LOW);
  digitalWrite(MOSI, LOW);
  digitalWrite(SS, HIGH);

  // Warning: if the SS pin ever becomes a LOW INPUT then SPI
  // automatically switches to Slave, so the data direction of
  // the SS pin MUST be kept as OUTPUT.
  SPCR |= _BV(MSTR);
  SPCR |= _BV(SPE);
 
  //default SPI speed is osc/2 (in arduino uno, 4Mhz, too fast)
  //change it to osc/16
  setClockDivider(SPI_CLOCK_DIV32); 
}

byte SPI_MasterTransmit(byte cData)
{
  /* Start transmission */
  SPDR = cData;
  /* Wait for transmission complete */
  while(!(SPSR & (1<<SPIF)))
  ;
  return SPDR;
}

byte SPI_MasterReceive(void)
{
  SPDR = 0x00;
  /* Wait for reception complete */
  while(!(SPSR & (1<<SPIF)))
    ;
  /* Return Data Register */
  return SPDR; 
}

void setClockDivider(byte rate)
{
  SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
  SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | (rate & SPI_2XCLOCK_MASK);
}


Slave
Code: [Select]

// spi slave

//arduino spi pin
//10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK)
// arduino spi library only use arduino as master
//#include <SPI.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include "pins_arduino.h"

#define SDRDY 9 // slave data ready

byte t = 0;
byte r = 0;

void setup() {
   SPI_SlaveInit();
   pinMode(9, OUTPUT);
   digitalWrite(9, LOW);
   //Serial.begin(9600);
}

void loop() {
  r = SPI_SlaveReceive();

  t = SPI_SlaveTransmit(r+1);
}

void SPI_SlaveInit(void)
{
   pinMode(MISO, OUTPUT);
   digitalWrite(MISO, LOW);
   SPCR |= _BV(SPE);
}

char SPI_SlaveReceive(void)
{
  /* Wait for reception complete */
  while(!(SPSR & (1<<SPIF)))
    ;
  /* Return Data Register */
  return SPDR;
}

char SPI_SlaveTransmit(byte cData)
{
  /* Start transmission */
  SPDR = cData;
  // assert drdy signal(to master)
  digitalWrite(9, HIGH);
 
  /* Wait for transmission complete */
  while(!(SPSR & (1<<SPIF)))
  ;
 
  // deassert drdy signal
  digitalWrite(9, LOW);
 
  return SPDR; 
}



Waveform

Nauman048

how to test this code??? I tried this on arduino uno. I want to test it. Is it possible to see the output on serial either on slave or master side???
Thanx and regards

Go Up