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
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.
-
My SPI communication is working fine because i also tried addition and subtraction between master and slave and the result was "ok "Alok Mishra– Alok Mishra2018年06月27日 12:05:21 +00:00Commented Jun 27, 2018 at 12:05
-
If your spi communication were working fine you wouldn't be here asking us for help...Majenko– Majenko2018年06月27日 12:34:49 +00:00Commented 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.Alok Mishra– Alok Mishra2018年06月27日 13:15:44 +00:00Commented 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– Majenko2018年06月27日 13:18:39 +00:00Commented 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"Alok Mishra– Alok Mishra2018年06月27日 13:37:11 +00:00Commented Jun 27, 2018 at 13:37
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