SPI - Arduino Uno & Esp8266

Hello again, I have a question, or maybe 2 questions, but first I will tell you what I have... I have an Arduino Uno and an Esp8266, both are connected via SPI, Esp8266 is the Master and the Arduino is the Slave. There is almost no information about SPI on the internet, much less related to Esp8266, but I found these two codes that allow me to send info from Esp8266 (Master) to Arduino (Slave).
It works well and there are no problems with it, but my problem comes when I want the Arduino (Slave) to send info to Esp8266, I DON'T KNOW HOW TO DO IT, I don't know why I can't find example codes about this (sorry if there are any, but I CAN'T FIND THEM), I tried to do it by myself with what little I knew, but it didn't work...

============
Code of UNO

#include <SPI.h>;

char buff[100];
volatile byte index;
volatile bool receivedone;

void setup(void) {
  Serial.begin(9600);
  SPCR |= bit(SPE);
  pinMode(MISO, OUTPUT);
  index = 0;
  receivedone = false;
  SPI.attachInterrupt();
}

void loop(void) {
  if (receivedone) {
    buff[index] = 0;
    Serial.println(buff);
    index = 0;
    receivedone = false;
  }
}

ISR (SPI_STC_vect) {
  uint8_t oldsrg = SREG;
  cli();
  char c = SPDR;
  if (index < sizeof buff) {
    buff[index++] = c;
    if (c == '\n') {
      receivedone = true;
    }
  }
  SREG = oldsrg;
}

===============
Code of Esp8266

#include <SPI.h>;

char buff[] = "Hello Slave\n";

void setup() {
  Serial.begin(9600);
  SPI.begin();
}

void loop() {
  for (int i = 0; i < sizeof buff; i++) {
    SPI.transfer(buff[i]);
  }
  Serial.println("Hello Slave__");
  delay(2000);
}

So my first question is how can I make the Arduino (Salve) send info to the Esp8266 (Master) (I know that when the Master activates the SS pin on a Slave, the Master info can be received by the Slave, but also I want the Slave to send info about his status)?

When I already know this, maybe I wouldn't have to ask my question because it could already be answered, but if not, then here goes... How can I control the Arduino and the SD reader at the same time? The SD reader also works with the SPI protocol, so they would share the Bus. And the problem is in this code...

===========
SD Reader

#include <SD.h>

File myFile;

void setup() {
  Serial.begin(9600);
  Serial.print("Starting SD...");
  if (!SD.begin(4)) {
    Serial.println("Could not start");
    return;
  }
  Serial.println("Successful initialization");
 
  myFile = SD.open("file.txt");
  if (myFile) {
    Serial.println("file.txt:");
    while (myFile.available()) {
    	Serial.write(myFile.read());
    }
    myFile.close();
  } else {
    Serial.println("Error");
  }
}

void loop() {}

At no time is it seen that the code sets the SS pin high or something (I think that is done in the SD library), nor in the Esp8266 code, and I would need that to control two Slaves...

Seriously, I would really appreciate it if you could help me, thanks!

it looks like you need the Uno to be the master.
slave can send only responses to requests from master.
the basic example is in IDE examples menu for the esp8266 SPISlave library.

How about using a standard serial connection between Arduino and ESP8266?

Do you have a high-speed-requirement for the communication? Of not I think a software serial on the arduino-side can be used to communicate.

Do you use some standard arduino-shields that are plugged into the Arduino-Board directly?
If not - in most cases - the ESP8266 is capable of doing all the functions of the Arduino Uno directly.

If you write a detailed description of your complete project I can answer if this would be possible.

best regards Stefan

Isn't the Slave supposed to send info too? If not, what is the use of having MISO and MOSI?

As soon as my Esp8266 activates the Arduino SS, my Esp8266 will send info to the Arduino, but also the Arduino will send info at the same time, and in the Esp8266 code I decide if I want to read it or not. That's what I want to do, plus my second question from the first post.

And no, I need the Esp8266 to be the Master because it will also control the SD reader to read and save data from a server.

Please I need help :frowning:

As mentioned previously, it would be a ton easier to use a different hardware protocol for ESP<->Arduino comms. Standard UART would be the easiest, especially if you use a communication library.

What exactly is your project and what are your requirements?

it is impossible or very complicated to act as SPI master and SPI slave with the same SPI peripheral. and Uno has only one. esp8266 has only one usable SPI too (other is used for the external flash memory).
so change your design

I did not understand, I can not use MISO and MOSI?

hiperdoo:
I did not understand, I can not use MISO and MOSI?

Yes, but only under control of the master. It's kind of funny, your fundamental problem is exactly the same as in this recent thread. Have a read:
https://forum.arduino.cc/index.php?topic=695565.0

Keep in mind what SPI is designed for - dumb peripherals.

hiperdoo:
It works well and there are no problems with it, but my problem comes when I want the Arduino (Slave) to send info to Esp8266, I DON'T KNOW HOW TO DO IT, I don't know why I can't find example codes about this (sorry if there are any, but I CAN'T FIND THEM), I tried to do it by myself with what little I knew, but it didn't work...

Check if the examples (esp. Section-7.3) of the attached pdf file help you to know the tricks how SPI Slave sends information to SPI Master.

Ch-7OnlineLec.pdf (291 KB)

@aarg According to what you sent, this person's problem is that he wants to be able to send the Slave info to the Master with a call with an extra pin, what is done in SPI is that the Master calls the Slave to send him info or receive or both, but the Slave cannot call itself, but it is what this person wants to achieve (it is what I understood).

But I want to achieve something more basic, something he already did, to be able to send and receive info from the Slave, but I only want him to do that when SS enables it (how SPI generally works). But there is no code in that link that you sent.

@GolamMostafa That works for the Arduino Uno, but I can't make the Esp8266 read the data that the Arduino (Slave) sends, and that problem is generated with this thing:

ISR(SPI_STC_vect)
{
myData = SPDR; //received bytes are kept in array
i++;
if(i == 2)
{
flag = true; //data received complete
i = 0; //array pointer is reset
}
It works on the Arduino, but not on the Esp8266

hiperdoo:
It works on the Arduino, but not on the Esp8266

Ok! I am going to try the sketch for ESP8266 (SPI-Master) and UNO (SPI-Slave) and see how the codes could be modified to make it work.

Thank you for the feedback.

@GolamMostafa Thank you very much, you would really help me a lot with that code, thanks bro!

I have run those codes of my referred document (Section-7.3) unchanged in ESP-SPIMaster and UNO-SPISlave, and they are working.

1. This is my hardware setup (Fig-1) between ESP8266-SPIMaster and UNO-SPISlave..


SPINodeUno.png
Figure-1:

2. This is the screen shot (Fig-2) of the Serial Monitor of ESP8266-SPIMaster.
smespxz.png
Figure-2:

3. ESP8266-SPIMaster Sketch

#include<SPI.h>
byte myData[] = {0x00, 0x00};//,
void setup()
{
  Serial.begin(115200);
  SPI.begin();
  delay(100);
  SPI.setClockDivider(SPI_CLOCK_DIV16);//1 MBits/s
  //pinMode(SS, OUTPUT);
  digitalWrite(SS, LOW);  //Slave is selected
  //--------------------
}

void loop()
{
  for (int i = 0; i < 2; i++)
  {
    myData[i] = SPI.transfer(myData[i]);
    delayMicroseconds(100); //allows Slave to process received byte/finish ISR overhead
    Serial.println(myData[i], HEX);  //shows: 0x34 and then 0x12 ; you know why?
  }
  int x = (int)myData[1] << 8 | (int)myData[0];
  Serial.println(x, HEX); //shows: 0x1234
  Serial.println("======================");
  delay(1000);  //test interval
}

4. UNO-SPISlave Sketch

#include<SPI.h>
int i = 0;
byte myData[] = {0x12, 0x34};//

void setup()
{
  Serial.begin(115200);
  //SPI.setClockDivider(SPI_CLOCK_DIV16);//
  pinMode(SS, INPUT_PULLUP);  // ensure SS stays high for now
  pinMode(MISO, OUTPUT);
  SPCR |= _BV(SPE);
  SPCR |= !(_BV(MSTR)); //Arduino is Slave
  SPI.attachInterrupt();   //interrupt logic is enabled
}

void loop()
{

}

ISR(SPI_STC_vect)
{
  SPDR = myData[i]; //places 0x12, then 0x34
  i++;
  if (i == 2)     //2-byte data are sent
  {
    i = 0;          //array pointer is reset
  }
}

SPINodeUno.png

smespxz.png

1 Like

I don't know why, but I can't see the Esp8266 code

Now I can, thanks bro, in 30mins i will test it because im in class :v, I will tell you what happen :smiley:

But I want to achieve something more basic, something he already did, to be able to send and receive info from the Slave, but I only want him to do that when SS enables it (how SPI generally works). But there is no code in that link that you sent.

The SS controls the hardware directly. Atmel datasheet:

19.3.1 Slave Mode
When the SPI is configured as a Slave, the Slave Select (SS) pin is always input. When SS is held low, the SPI
is activated, and MISO becomes an output if configured so by the user. All other pins are inputs. When SS is
driven high, all pins are inputs, and the SPI is passive, which means that it will not receive incoming data. Note
that the SPI logic will be reset once the SS pin is driven high.
The SS pin is useful for packet/byte synchronization to keep the slave bit counter synchronous with the master
clock generator. When the SS pin is driven high, the SPI slave will immediately reset the send and receive logic,
and drop any partially received data in the Shift Register.

SS cannot be used on a slave in the way you describe, by the Arduino SPI library because it's not supported:

Note about Slave Select (SS) pin on AVR based boards

All AVR based boards have an SS pin that is useful when they act as a slave controlled by an external master. Since this library supports only master mode, this pin should be set always as OUTPUT otherwise the SPI interface could be put automatically into slave mode by hardware, rendering the library inoperative.

It is, however, possible to use any pin as the Slave Select (SS) for the devices. For example, the Arduino Ethernet shield uses pin 4 to control the SPI connection to the on-board SD card, and pin 10 to control the connection to the Ethernet controller.

GolamMostafa Many thanks!!! It worked perfectly! I just have to couple your code to mine so that I can send the data I need, but thank you very much!

Good to know that it worked for you.