0

I am trying to send ADS 1115 data which is connected with Arduino mega_1 over I2C and arduino Mega_1 is connected with arduino Mega_0 over SPI. Arduino Mega_1 is act as a slave and send ADS 1115 data to master device.. I think my whole setup is working but i want to received actual data of ADS 1115 on master Arduino Here is screenshots of results of my codeenter image description here

master

#include <SPI.h>

void setup (void)
{
  Serial.begin (9600);
  Serial.println ();

  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

byte transferAndWait (const byte what)
{
  byte a = SPI.transfer (what);
  delayMicroseconds (20);
  return a;
} // end of transferAndWait

void loop (void)
{
byte a;

  // enable Slave Select
  digitalWrite(SS, LOW);    

  transferAndWait ('a');  // add command
a=transferAndWait (0);


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

  Serial.println ("results:");
  Serial.println (a);

  delay (1000);  // 1 second delay 
}  // end of loop

slave

#include <Wire.h>
#include <Adafruit_ADS1015.h>
int out_buf;
int adc0;

// Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
Adafruit_ADS1015 ads;
// what to do with incoming data
volatile byte command = 0;
void ss_falling ()
{
  command = 0;
} 
void setup (void)
{
 ads.begin();
 Serial.begin(9600);  
 //ads.startComparator_SingleEnded(0, 1000);
// 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);
 attachInterrupt (0, ss_falling, FALLING);

}

// 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 = out_buf; // add 15
    break;

  } // end of switch

}  // end of interrupt service routine (ISR) SPI_STC_vect


void loop (void)
{
adc0 = ads.readADC_SingleEnded(0);
Serial.print("AIN0: "); Serial.println(adc0);

out_buf=adc0;
//int buff = atoi(out_buf);
Serial.print("AIN1: "); Serial.println(out_buf);
delay(1000);
 }

i am sending 1570 but on Master side i received 35 i think ADS data is of 16 bits i.e 2 bytes and SPI received only 1 byte at a time i am stuck here please help me. Thank you in Advance

example enter image description here enter image description here

2 Answers 2

0

Implementing SPI slave mode is a little more tricky than you may think. The most important thing to remember is that it's not a "Give me X" -> "Ok, here is X" kind of protocol. It's actually a "Here's X" <=> "Here's Y" protocol.

That is, at the same time that the master sends X to the slave, the slave sends "Y" to the master.

The way you have it is that the master sends "a" as a command and discards what it receives. The slave remembers that "a" as the "command". Then the master sends 0, and remembers what it receives. The slave receives that 0 and thinks "Ah, I got the command last time, so it must want the value" and queues up the value to be sent the next time a transaction occurs. That then gets thrown away, since that occurs when the next "command" is sent.

You need to be a little more cunning, and implement a finite state machine to work out where in the stream you are.

  • When SS falls set a "byte counter" to 0.
  • When a byte is received examine the "byte counter":
    • Byte 0: If it's an "a" then place the first byte of the value in SPDR.
    • Byte 1: Place the second byte of the value in SPDR
    • Byte 3: Do nothing (or place 0 in SPDR)
  • Increment the byte counter

So the transaction goes something like this (1570 is 0x622 in hex, and I choose "little endian" since the AVR is naturally little endian):

Master Sends        Slave Queues          Master Receives
'a'                 0x22                  Rubbish
0                   0x06                  0x22
0                   0x00                  0x06

'a'                 0x22                  0x00
0                   0x06                  0x22
0                   0x00                  0x06

The important thing to remember is that the master receives what the slave queued on the next transfer.

8
  • My SPI communication is working fine because i also tried addition and subtraction between master and slave and the result was "ok " Jun 27, 2018 at 12:05
  • If your spi communication were working fine you wouldn't be here asking us for help...
    – Majenko
    Jun 27, 2018 at 12:34
  • dude read this lines "i am sending 1570 which is a ads1115 data but on Master side i received 35 i think ADS data is of 16 bits i.e 2 bytes and SPI received only 1 byte at a time." SPI is ok to me.... i think there is something missing like byte to char conversion or split 16 bit adc data into 8 bits and thn sent to master that is my real problem. Jun 27, 2018 at 13:15
  • 35 has no relation to 1570. The closest you could be receiving would be 34 (0x22). Fixing your code in the way I specify not only fixes the mess you made of the sending system, but also fixes the 16-bit issue. Oh, and make your out_buf volatile. Also the out_buf should be "captured" at the point you either queue the first byte, or when SS falls.
    – Majenko
    Jun 27, 2018 at 13:18
  • i added two more screenshots in which i send 10 and in return i received 20 "20=10 +10" Jun 27, 2018 at 13:37
0

My Problem is solved now, thanks to the almighty. I did few changed in code as: 1. Converted the received int type data from ADS to Char. 2. Stored it in an Array, to form a string.

Here is my Modified Slave Code:

#include <Wire.h>
#include <Adafruit_ADS1015.h>
Adafruit_ADS1015 ads;
void setup (void)
{
ads.begin();
 Serial.begin(9600);
  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

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

  // turn on interrupts
  SPCR |= bit(SPIE);
}  // end of setup

char buf[20];
volatile int pos;
volatile bool active;


// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;

  if (c == 1)  // starting new sequence?
    {
    active = true;
    pos = 0;
    SPDR = buf [pos++];   // send first byte
    return;
    }

  if (!active)
    {
    SPDR = 0;
    return;
    }

  SPDR = buf [pos];
  if (buf [pos] == 0 || ++pos >= sizeof (buf))
    active = false;
}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{
int adc0=0;
adc0 = ads.readADC_SingleEnded(0);
itoa(adc0,buf,10);
Serial.print("AIN1: "); Serial.println(buf);
delay(500);
}  // end of loop

On Master side

We are receiving string by sending one dummy value at a time. Here is modified master code:

#include <SPI.h>

void setup (void)
{
  Serial.begin (9600);
  Serial.println ("Starting");

  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 buf [20];

  // enable Slave Select
  digitalWrite(SS, LOW);    
  SPI.transfer (1);   // initiate transmission
  for (int pos = 0; pos < sizeof (buf) - 1; pos++)
    {
    delayMicroseconds (15);
    buf [pos] = SPI.transfer (0);
    if (buf [pos] == 0)
      {
      break;
      }
    }

  buf [sizeof (buf) - 1] = 0;  // ensure terminating null

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

  Serial.print ("We received: ");
  Serial.println (buf);

  delay (500); 
}  // end of loop

Your Answer

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

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