Dear all, I have a problem that don't know how to fix and is driving me crazy! This is the story; I have two Arduinos (Nano) connected through SPI. The master is controlling a TFTscreen to control the system, and the slave is conected to some resistor-based sensors and to an ESP-01 as a webserver. The system can be controlled with the TFT or by the internet. Up to here everything is ok (if I only use the TFT or the Internet)
Now the problem; in the void loop of the slave, first I anlyze if there is any operation to be done requested by the master. If it is not the case, then it checks if there is any client connected to the ESP-01 to provide the HTML data. The problem is that, if the master is asking for meassures, lets say once a second, and then an user get connected to the ESP-01 at the same time, the system crashes.
How I tried to solved? I have a line SDRDY to let the master know that data is ready on the slave, so the first solution I thought was to use that line, so when the slave is checking for any client, this line is HIGH "suggesting" to the master not to send any instruction yet. It doesn't work... Second solution was to implement a variable (OperationOnGoing) that is true if the Master is requesting data from the Slave, so in theory, the slave should not check for any client...nothing. Third try was to use SPI.detachInterrupt when the slave starts checking the ESP-01 and then SPI.attachInterrupt() when it finishes, using a delay before check if a client is connectd trying to avoid a continuous attach/detach... In doesn't work either.
I'm usinf WiFiESP.h library to control the ESP-01. I don't know if is that this library has any kind of interrupt or something like that, but the point is that if the master is requesting data and a client request the connection, all the system crashes.
Is there any superengineer or erudite person who knows what is going on, or even better, tell me how to solve it?? Thankyou very much!
Don't use the SPI library in slave mode. Using SPI.transfer() inside an interrupt routine is particularly a bad idea because the call waits until the interrupt was called. That may end in nirvana.
Instead of
SPI.transfer(data);
just use
SPDR = data;
Also:
SPI.attachInterrupt(); // get ready for an interrupt
is the same as:
SPCR |= _BV(SPIE); // turn on interrupts
SPI.setClockDivider(SPI_CLOCK_DIV8);
isn't necessary because the clocking is done by the master.
Do you initialize the SS pin (D10) as INPUT?
Next time, please provide the complete code and not just excerpts, some variable definitions may be important. Please also provide a wiring schemata.
bokeauss:
The code is a little bit messy... I post the slave code.
Please post a complete program. As well as the unseen parts being important I am not going to take the risk of making mistakes while joining parts together.
I don't understand the relationship between the code in Reply #7 and that in #6 and #5?
In the code in Reply #5 why is your ISR longer than this
ISR (SPI_STC_vect)
{
byte c = SPDR; // grab byte from SPI Data Register
newSPIdata = true;
}
The rest of the stuff does not need to be in the ISR. And, especially, you should not be wasting time in an ISR with a delay.
On each occasion when you receive SPI data do you only expect a single byte - or are you expecting a message with a few bytes? If the latter I would write the program to receive all the bytes before analysing any of them.
Please provide a description of how your program is intended to work - what each part does (or should do).
The code on post #5 is the program on the slave, and the code on #6 and #7 (SPI subroutines on the master) the program of the master.
The system has two current sensors, two relays controlling one outlet each (each one connected to a current sensor) and on temp and Humidity sensor. On the ISR I have a Switch structure because in dependance of the request of the master, the answer is different. For instance, if i want to know if one channel is On or OFF, the answer is only 1 byte, but if I want to read the current, the answer is 4 bytes (4 ASCII characters)
bokeauss:
On the ISR I have a Switch structure because in dependance of the request of the master, the answer is different. For instance, if i want to know if one channel is On or OFF, the answer is only 1 byte, but if I want to read the current, the answer is 4 bytes (4 ASCII characters)
How should be then the transfer of information??
I can see the SWITCH structure but in every case is just seems to read 2 bytes - for example Tb or Db (where b is some byte). I don't see any code to receive 4 bytes.
When I asked, in Reply #8 for a description I was hoping you would provide something far more detailed - a step-by-step walk-through of the program.
Also I cannot place the code in Reply #5 in the context of the problem described in your Original Post.
I think a simple diagram showing the system you are trying to work with would also be a big help.
At the moment you know all about the project and I feel I only know a teeny bit about it - and maybe not the part that leads me to say "Ahhh ...."
Finally, if the code in Replies #6 and #7 are all part of one program please post it as a complete program.
Thanks Robin2 for your time. I think I've identified the problem, and it is not dealing with SPI interrupts but with SoftwareSerial interrupts (I didn't know this library uses interrupts...)
I suspect that the problem is related with SoftwareSerial because if I use noInterrupts() the part of the code corresponding to the Webserver get freeze. I found other thread where it seems that the problem was solved by including in SoftwareSerial library two soubroutines to enable and disable interrupts.
I think I've identified the problem, and it is not dealing with SPI interrupts but with SoftwareSerial interrupts (I didn't know this library uses interrupts...)
SoftwareSerial not only uses interrupts for the reception side it also blocks interrupts during sending of characters. I strongly suggest not using SoftwareSerial in your case. Connect the WiFi chip by hardware serial and your problems probably decrease. If you need a debugging possibility, use the AltSoftSerial library which uses a timer to send out characters and doesn't block interrupts for disastrous long periods as SoftwareSerial does (but is limited in pin choice).
First, I can confirm that the error is related with interrupts on SoftwareSerial library. I've been testing the solution proposed on reply #11 (stop interrputs on SoftwareSerial) and it works, but still not working really fine....
Now the problem is that if you connect to the IP when the SoftSerial port is "disabled", you loose that request, and when the SoftSerial is enabled it doesn't have have it.
I'm going to try next the solution using AltSoftSerial. Do any of you know if this will happen using this library also??
Second test, now using AltSoftSerial.h as it was suggested by pylon work really find. Now I dont need to "stop" serial interruptions, and also it seems that it is possible to send request when the system is doing other task and it is not "lost" as when using the other solution.
Thanks a lot to pylon how gave me the advice!!
Now I need to go deeper on wify connection because sometimes I get the message [wifi] TIMEOUT and don't understand yet why...