ESP8266 improving code to avoid crashes
Posted: Mon Feb 06, 2017 5:26 am
Hello to Everyone
This is gonna be my first post on this forum. I've posted same message on Github but they have directed me to your site, so...
I'm developing ESP-12E board. A SoftwareSerial to communicate with RFID reader and ESP acting as a Server and Client. If RFID antenna has a tag in range it sends ID via my SoftwareSerial to ESP with 1s intervals. When a tag is not present near the antenna it sends nothing.
Basically my program checks the availability RFID and when it notices change of the tag value from 0 to 'something' or from 'something' to 0 it sends it only once in a message to the master unit.
If RFID doesn't send anything during 2500ms program founds it that the tag is not present in the range of reader.
Master unit occassionally checks if the slave has 'something' in its range by sending message with "U" letter. Slave is responding with its current status.
I have the ESP-12E adapter board with 3V3 stabilizer. Everything is soldered and secured with ceramic 100nF decoupling condensator, and two 470uF electrolytic condensators: one before and one behind the 3V3 stabilizer. Everything is powered from 5V 6A supply. CH_E and RST pulled up to 3V3. GPIO0 and GPIO2 pulled up to 3V3, GPIO15 pulled to GND.
I would like my ESP work for a weeks without problems, but I know that is hard to achieve. I'm ok with occassionally resets but I wouldn't be pleased with freezes. I rather would like the wdt to reset my chip than it crash or completely freeze.
Today I've tested it for a couple of hours and it worked well without any failures but I want to be better safe than sorry. I'm not sure if I haven't add too many yields or delay(0)s. I've added yields and delays because I've just wanted to give the processor time to handle system tasks but I didn't mean to unnecessarily feed the wdt. I want the wdt to eventually handle the heap and restart chip.
I would like you to see my code and help me if there is anything I can do to improve it (especially RFID reading part) to prevent from dead loops or mistakes that could cause a freeze?
And the second question: Is it ok to callback the WiFiSend function inside the if(!client) ?
I don't want you to write code for me. I'm just looking for good advices about yielding and wdt (examples are very welcome ). I spent many hours searching the Internet for neccessary information but I didn't find too many concretes except generalities like:
"This is one of the most critical differences between the ESP8266 and a more classical Arduino microcontroller. The ESP8266 runs a lot of utility functions in the background – keeping WiFi connected, managing the TCP/IP stack, and performing other duties. Blocking these functions from running can cause the ESP8266 to crash and reset itself. To avoid these mysterious resets, avoid long, blocking loops in your sketch."
Is Ticker a good solution for me?
Sorry for the code mistakes but I'm not a professional programist.
Settings in IDE
Module: Generic ESP8266 Module
Flash Size: 4MB/1MB
CPU Frequency: 80Mhz
Flash Frequency: 40Mhz
Upload Using: SERIAL
Reset Method: ck
void loop() {
yield();
if (!client)
{delay(1);
WiFiClient client = server.available();
if (RFID.available() > 0)
{ yield();
previous=millis();
delay(0);
int c=RFID.read();
delay(0);
odczyty[r]=c; //storing reads in array in advance for future use
delay(0);
r++;
if (r>11) //r means number of read bytes
{
tag=odczyty[10]; //in my implementation tag id is .11 byte of readed RFID tag
delay(0);
RFID.flush();
delay(0);
tag1=tag;
delay(0);
Serial.println(tag1);
delay(0);
if (tag2!=tag1 && tag2==0)
{
WiFiSend(String(tag1), "C");
}
tag2=tag1;
tag=0;
r=0;
delay(0);
}
yield();
} else if ((millis()-previous)>2500)
{
tag=0;
tag1=tag;
r=0;
delay(0);
if (startup!=1)
{
if (tag2!=tag1 && tag1==0)
{
delay(0);
WiFiSend(String(tag2), "D"); //sending disconnected message
delay(0);
}} else //executing once after startup
{ delay(0);
RFID.flush();
r=0;
delay(0);
WiFiSend(String(tag1), "U"); //sending update message
RFID.flush();
delay(0);
startup=0;
r=0;
delay(0);
}
tag2=tag1;
previous=millis();
r=0;
}
return;
}
// Wait until the client sends some data
while (!client.available()) {
myDelay(1);
}
if (client.available())
{ yield();
myDelay(1);
transmission = 1;
previous=millis();
String req = client.readStringUntil('\r');
client.flush();
}
convert(req); //slices request of the client to the specific parts like crc, tag id, slave nr
if (last_char == "#" && cr.toInt()==crc) // if received message includes "#" symbol and the crc is correct then send "OK\r" reply
{ delay(0);
client.print("OK\r");
client.stop();
previous=millis();
} else
{ delay(0);
client.print("ERR\r");
client.stop();
previous=millis();
}
RFID.flush();
delay(0);
r=0;
if (last_char == "#" && transmission == 1 && cr.toInt()==crc ) //simply checks the crc and message syntax
{
if (event == "U") //if message contain "U" - send status update to master unit
{
WiFiSend(String(tag1),"U");
previous=millis();
}
if (event == "R") //if message contain "R" - restart the ESP
{
Serial.println("RESTART");
ESP.restart();
}
transmission = 0;
last_char = "";
delay(0);
}
yield();
}
void WiFiSend(String nr, String event)
{
delay(0);
if (client.connect(host, httpPort)) {
yield();
// This will send the request to the server
if (nr=="0")
{
msg = station_id + event + nr + "00" + "#" + "\r";
} else
{
msg = station_id + event + nr + "#" + "\r";
}
client.print(msg);
client.flush();
yield();
return;
}
unsigned long timeout = millis();
while (client.available() == 0) {
yield();
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
}
delay(0);
// Read all the lines of the reply from server and print them to Serial
if (client.available()) {
yield();
line = client.readStringUntil('\r');
client.flush();
if (line == "OK")
{
msg = "";
event = "";
}
}
if (!client.connected())
{
client.stop();
}
myDelay(10);
line = "";
n = 0;
previous=millis(); //when sending a message takes a while this line avoids the program to think that tag is not in the range of RFID reader
}
void myDelay(int time)
{
for (int z = 0; z < time; z++)
{
delay(1);
yield();
}
}
This is gonna be my first post on this forum. I've posted same message on Github but they have directed me to your site, so...
I'm developing ESP-12E board. A SoftwareSerial to communicate with RFID reader and ESP acting as a Server and Client. If RFID antenna has a tag in range it sends ID via my SoftwareSerial to ESP with 1s intervals. When a tag is not present near the antenna it sends nothing.
Basically my program checks the availability RFID and when it notices change of the tag value from 0 to 'something' or from 'something' to 0 it sends it only once in a message to the master unit.
If RFID doesn't send anything during 2500ms program founds it that the tag is not present in the range of reader.
Master unit occassionally checks if the slave has 'something' in its range by sending message with "U" letter. Slave is responding with its current status.
I have the ESP-12E adapter board with 3V3 stabilizer. Everything is soldered and secured with ceramic 100nF decoupling condensator, and two 470uF electrolytic condensators: one before and one behind the 3V3 stabilizer. Everything is powered from 5V 6A supply. CH_E and RST pulled up to 3V3. GPIO0 and GPIO2 pulled up to 3V3, GPIO15 pulled to GND.
I would like my ESP work for a weeks without problems, but I know that is hard to achieve. I'm ok with occassionally resets but I wouldn't be pleased with freezes. I rather would like the wdt to reset my chip than it crash or completely freeze.
Today I've tested it for a couple of hours and it worked well without any failures but I want to be better safe than sorry. I'm not sure if I haven't add too many yields or delay(0)s. I've added yields and delays because I've just wanted to give the processor time to handle system tasks but I didn't mean to unnecessarily feed the wdt. I want the wdt to eventually handle the heap and restart chip.
I would like you to see my code and help me if there is anything I can do to improve it (especially RFID reading part) to prevent from dead loops or mistakes that could cause a freeze?
And the second question: Is it ok to callback the WiFiSend function inside the if(!client) ?
I don't want you to write code for me. I'm just looking for good advices about yielding and wdt (examples are very welcome ). I spent many hours searching the Internet for neccessary information but I didn't find too many concretes except generalities like:
"This is one of the most critical differences between the ESP8266 and a more classical Arduino microcontroller. The ESP8266 runs a lot of utility functions in the background – keeping WiFi connected, managing the TCP/IP stack, and performing other duties. Blocking these functions from running can cause the ESP8266 to crash and reset itself. To avoid these mysterious resets, avoid long, blocking loops in your sketch."
Is Ticker a good solution for me?
Sorry for the code mistakes but I'm not a professional programist.
Settings in IDE
Module: Generic ESP8266 Module
Flash Size: 4MB/1MB
CPU Frequency: 80Mhz
Flash Frequency: 40Mhz
Upload Using: SERIAL
Reset Method: ck
void loop() {
yield();
if (!client)
{delay(1);
WiFiClient client = server.available();
if (RFID.available() > 0)
{ yield();
previous=millis();
delay(0);
int c=RFID.read();
delay(0);
odczyty[r]=c; //storing reads in array in advance for future use
delay(0);
r++;
if (r>11) //r means number of read bytes
{
tag=odczyty[10]; //in my implementation tag id is .11 byte of readed RFID tag
delay(0);
RFID.flush();
delay(0);
tag1=tag;
delay(0);
Serial.println(tag1);
delay(0);
if (tag2!=tag1 && tag2==0)
{
WiFiSend(String(tag1), "C");
}
tag2=tag1;
tag=0;
r=0;
delay(0);
}
yield();
} else if ((millis()-previous)>2500)
{
tag=0;
tag1=tag;
r=0;
delay(0);
if (startup!=1)
{
if (tag2!=tag1 && tag1==0)
{
delay(0);
WiFiSend(String(tag2), "D"); //sending disconnected message
delay(0);
}} else //executing once after startup
{ delay(0);
RFID.flush();
r=0;
delay(0);
WiFiSend(String(tag1), "U"); //sending update message
RFID.flush();
delay(0);
startup=0;
r=0;
delay(0);
}
tag2=tag1;
previous=millis();
r=0;
}
return;
}
// Wait until the client sends some data
while (!client.available()) {
myDelay(1);
}
if (client.available())
{ yield();
myDelay(1);
transmission = 1;
previous=millis();
String req = client.readStringUntil('\r');
client.flush();
}
convert(req); //slices request of the client to the specific parts like crc, tag id, slave nr
if (last_char == "#" && cr.toInt()==crc) // if received message includes "#" symbol and the crc is correct then send "OK\r" reply
{ delay(0);
client.print("OK\r");
client.stop();
previous=millis();
} else
{ delay(0);
client.print("ERR\r");
client.stop();
previous=millis();
}
RFID.flush();
delay(0);
r=0;
if (last_char == "#" && transmission == 1 && cr.toInt()==crc ) //simply checks the crc and message syntax
{
if (event == "U") //if message contain "U" - send status update to master unit
{
WiFiSend(String(tag1),"U");
previous=millis();
}
if (event == "R") //if message contain "R" - restart the ESP
{
Serial.println("RESTART");
ESP.restart();
}
transmission = 0;
last_char = "";
delay(0);
}
yield();
}
void WiFiSend(String nr, String event)
{
delay(0);
if (client.connect(host, httpPort)) {
yield();
// This will send the request to the server
if (nr=="0")
{
msg = station_id + event + nr + "00" + "#" + "\r";
} else
{
msg = station_id + event + nr + "#" + "\r";
}
client.print(msg);
client.flush();
yield();
return;
}
unsigned long timeout = millis();
while (client.available() == 0) {
yield();
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
}
delay(0);
// Read all the lines of the reply from server and print them to Serial
if (client.available()) {
yield();
line = client.readStringUntil('\r');
client.flush();
if (line == "OK")
{
msg = "";
event = "";
}
}
if (!client.connected())
{
client.stop();
}
myDelay(10);
line = "";
n = 0;
previous=millis(); //when sending a message takes a while this line avoids the program to think that tag is not in the range of RFID reader
}
void myDelay(int time)
{
for (int z = 0; z < time; z++)
{
delay(1);
yield();
}
}