esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.06k stars 13.33k forks source link

SoftwareSerial: wdt reset #1426

Closed supersjimmie closed 5 years ago

supersjimmie commented 8 years ago

I use both SoftwareSerial and WiFiClient. During normal operations, it sometimes works for many hours but other times it gives a wdt reset. This looks like it has a relation between SoftwareSerial and WiFiClient.

If I use mySerial.enableRX(false) before starting the function with the WiFiClient, it seems to keep working, otherwise it looks like to crash on different places.

ets Jan 8 2013,rst cause:4, boot mode:(3,6) wdt reset This was during client.print() operations, the first client.print with the data succeeded, then just after that, only when sending an empty line with client.print("\r\n") it gave the wdt reset.

But earlier, it was just during receiving data on the SoftwareSerial: `ets Jan 8 2013,rst cause:4, boot mode:(1,6)``

And a couple of other times also during normal receiving on the serial: ets Jan 8 2013,rst cause:4, boot mode:(3,7)

So many different boot modes, they all seem only to occur if I don't use the mySerial.enableRX(false).

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

allene222 commented 7 years ago

I can post my sketch if that is what you mean. The sketch is minimal in the science that it is only doing the basic functions of what I need. UDP WiFi Tx and RX., Rx swSer, and prints some stuff out. Everything else is just stubs. There is also a web server but there is nothing but "hello world" there. The WiFi Tx is just a short fixed sentence sent once a second. The reason I know it is Software Serial is that if I modify the swSer routine to just output a dummy GPS message once a second keeping everything else the same, it doesn't crash.

I have implemented code as described by Luis and am testing it now. It has run for an hour without crashing so I am hopeful my problem is solved.

The reason I posted is I wanted to point out that this class still crashes at least for Luis and myself. We have almost identical applications that both dealing with the kind of data typical on a boat.

plerup commented 7 years ago

As you have a setup to test please try changing this line:

#define WAIT { while (ESP.getCycleCount()-start < wait); wait += m_bitTime; }

to

#define WAIT { while (ESP.getCycleCount()-start < wait) optimistic_yield(1); wait += m_bitTime; }

and see if it helps. If so this can be used for low baud rates

allene222 commented 7 years ago

@plerup Is that post directed at me? I am just using the version of swSerial that comes with the ESP8266 Arduino package. I am not really familiar with what you are asking.

plerup commented 7 years ago

Well, that is a line in the library file SoftwareSerial.cpp.

But after some testing I don't think it's the Rx interrupt which is the problem in low baud rates but the fact that interrupts are disabled for a long time in Tx. I will probably post an update which will only do this when the high speed is used.

allene222 commented 7 years ago

@plerup I am reading from a GPS chip. I don't write to it except once in setup() to initialize it. When the crashes or resets occur, there is no Tx going on.

plerup commented 7 years ago

Ok, then please try changing the lines as described above

allene222 commented 7 years ago

OK, I will but it might take me awhile to get to it. I have a work around and need to learn how to incorporate your code in my sketch. I am sure there are instructions somewhere but I can't find them. Also, it takes hours to make it crash. It once ran 6 hours error free. Sometimes it errors every 5 minutes. And of course, there are two failure modes. Very strange problem.

allene222 commented 7 years ago

Another 10 minutes on Google. I give up. Where are the instructions?

LuisVSa commented 7 years ago

@plerup

When I was getting crashes with Software Serial, I was only using it as a receiving UART. I read all this thread and I tried to understand your implementation. I know very little od C++ but I think that the following:

#define WAIT { while (ESP.getCycleCount()-start < wait); wait += m_bitTime; }

creates a loop with a duration equal to a bit time. For 4800 baud that means about 208 micro seconds and for the full character it is 10 times this. Therefore when a starting bit arrives there will be an interval of time of about 2 mili seconds without any delay() or yield(). Critical wifi operations need to wait for the full byte to arrive. For 300 baud these times will be much longer! I do not understand the optimistic_yield(1) that you propose but I think the idea is to give a chance for these operations to take place. I am not sure if a yield() placed inside the for next loop would also result.

However, unless I am making a terrible mistake in the understanding of your implementation, the CPU "does nothing" for the whole duration of the reception of a byte. Even if the crashes are avoided with your previous suggestions, I could not use Software Serial to receive Nmea 183 sentences which can be 80 characters long. When the falling edge of the starting bit of the first character of the sentence triggers the interrupt on the RX pin, the ESP8266 locked on successive WAIT while loops.

As I explained above I use a timer. When the interrupt of the start bit arrives the service to the interrupt sets a "one time" timer to act about 1,5 bit time later and disables the interrupt on the RX pin. The service to the "one time" timer reads the first bit and re programmes the timer to be a "periodic" timer with period equal to 1 bit time. Then the service to this "periodic" timer is just to get the following bits. When the last bit is received, the character goes to the buffer and the interrupt on the RX pin is enabled again.

Best Regards, Luis

devyte commented 7 years ago

A note from a corner in my brain, that may serve as guideline: code execution shouldn't take longer than 10ms without allowing for wifi stack servicing (i.e.: callback, loop code path until calling of yield()/delay(), etc), and interrupts should not be disabled for longer than 100us. If you go above this, you risk instability and odd crashes. This last could manifest only in environments with high wifi traffic, but not in quiet environments, which means it could be difficult to reproduce reliably. I don't remember where I got that info from, it was a while ago, maybe from some discussion in the Lua Nodemcu firmware repo issues.

axwell commented 6 years ago

Any updates on this ?

allene222 commented 6 years ago

From my end, I am using what Luis helped me with and have built 10 systems with many hours of testing and no crashes. I have not gone back and tried to use SWSerial. I use Serial1 for the Tx port and what Luis described for Rx. The app is no longer stubs and does not crash.

axwell commented 6 years ago

@allene222 can you provide step by step details / code ? and where to change? Or a merge request ? i'm that really good at c++. Thanks.

allene222 commented 6 years ago

I would suggest you try the changes suggested on October 14 by plerup. The code I used is not mine to share.

axwell commented 6 years ago

Those changes only lower the wdt resets. Still not reliable.

jeroenst commented 6 years ago

I also can confirm softwareserial is causing my esp to have watchdog timeouts every several hours.

It occurs with read and write of software serial.

logging: read_MHZ19() executing co2Serial.write(cmd,9) dev 1153

ets Jan 8 2013,rst cause:4, boot mode:(1,6)

wdt reset

alexgrauer commented 6 years ago

@jeroenst, do you still have issues when using SoftwareSerial?

I did what @LuisVSa recommended and it works like a charm. Until now, it has been working for more than 2 days in a row without any crash. Im using software serial library for Tx purposes thou, so its confusing what you are saying about your system also crashing when sending info. I config the serial software like this: SoftwareSerial SIM5320_Serial(-1, SIM5320_SERIAL_TX_PIN); which disables all rx functions from the library, and until now no problem.

Can you confirm that your system crashes also when sending? Thanks Alex

allene222 commented 6 years ago

@alexgrauer I use what @LuisVSa does for Rx and Serial2 for Tx. No software serial and no problems. My application is battery powered so it would never see 2 days in a row but I have built many units and have not seen a problem.

Allen

alexgrauer commented 6 years ago

Thanks @allene222. Do you think I should have any problem with using SoftwareSerial in Only TX mode?

My system is actually using Hardware Serial for debugging, and two different Software Serials two connect to different peripherals. So far, so good!

allene222 commented 6 years ago

@alexgrauer I don't know as I quit using SWSerial both Tx and Rx at the same time.

jeroenst commented 6 years ago

I switched to hardware serial which solved all my problems, I now have an uptime of 20 days.

alexgrauer commented 6 years ago

That's great @jeroenst. I don't have that option because I need 3 different serials. But until 2 days ago the system was rebooting every few hours, and now is still working so I will assume the problem has been solved.

jeroenst commented 6 years ago

That is great news!!

allene222 commented 6 years ago

@alexgrauer Perhaps I misread your post. You said it has been working for 2 weeks but the "until now" made me think it is no longer working. Working until now...

Perhaps you are saying it is working fine and has for 2 weeks.

Just to be clear, you are using the @LuisVSa for Rx and SW Serial for Tx and everything works fine.

I think I am out of IO pins so I will continue to share Serial 1 for debug and my Tx needs. But the next project might be different so I try and keep up on what works and what doesn't.

alexgrauer commented 6 years ago

@allene222, sorry about the confusion. Im a Spanish speaker trying to make sense in English, haha.

  1. it's 2 days, not 2 weeks (I'll let you know if I get there without issues)
  2. Yes its still working
  3. Im using @LuisVSa Rx solution, and SW_Serial for Tx only. The library says: // If only one tx or rx wanted then use this as parameter for the unused pin

    define SW_SERIAL_UNUSED_PIN -1

I read the entire file, and setting Rx to -1 makes every piece of code related to Rx not to run. So far, so good... and hopefully it continues this way.

tzanampeths commented 6 years ago

Hi everybody, I'm experiencing the wdt reset also. @alexgrauer is it possible to guide me to @LuisVSa solution please? I'm unable to find the code in this conversation. Thanks in advance!

alexgrauer commented 6 years ago

Hi @tzanampeths,

This is the way I've done it. Not sure if its the most efficient one, but it works. (BaudRate: 9600)

  1. SoftwareSerial SIM5320_Serial(-1, SIM5320_SERIAL_TX_PIN); Define SoftwareSerial to only use TX functions

  2. In the setup function: SIM5320_Serial.begin(9600);

pinMode(SIM5320_SERIAL_RX_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(SOFTWARE_Serial_Active_Pin), NODEMCU_External_Interrupt_Handle, FALLING);

timer1_attachInterrupt(onTimerISR); timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);

  1. Define variables to control de received info

define SOFTWARE_SERIAL_BUFFER_SIZE 500

char. SOFTWARE_Serial_Rx_Buffer[SOFTWARE_SERIAL_BUFFER_SIZE]; uint16_t SOFTWARE_Serial_Chars_Received_Counter = 0;

uint8_t SOFTWARE_Serial_Bits_Received = 0; byte SOFTWARE_Serial_Char_Received; boolean SOFTWARE_Serial_New_Data_Received = false;

  1. Create functions to manage external and timer_1 interruptions

void ICACHE_RAM_ATTR onTimerISR(){ bitWrite(SOFTWARE_Serial_Char_Received, SOFTWARE_Serial_Bits_Received, digitalRead(SOFTWARE_Serial_Active_Pin)); SOFTWARE_Serial_Bits_Received++; if(SOFTWARE_Serial_Bits_Received == 8){ timer1_detachInterrupt(); SOFTWARE_Serial_Bits_Received = 0; SOFTWARE_Serial_Rx_Buffer[SOFTWARE_Serial_Chars_Received_Counter] = SOFTWARE_Serial_Char_Received; SOFTWARE_Serial_Chars_Received_Counter++; SOFTWARE_Serial_New_Data_Received = true; if(SOFTWARE_Serial_Chars_Received_Counter >= SOFTWARE_SERIAL_BUFFER_SIZE){ SOFTWARE_Serial_Chars_Received_Counter = 0; } attachInterrupt(digitalPinToInterrupt(SOFTWARE_Serial_Active_Pin), NODEMCU_External_Interrupt_Handle, FALLING); } else{ timer1_write(520); //104ms } }

void NODEMCU_External_Interrupt_Handle() { timer1_attachInterrupt(onTimerISR); timer1_write(780); //156ms detachInterrupt(SIM5320_SERIAL_RX_PIN); }

Let me know if you have any doubt. Hope it helps

tzanampeths commented 6 years ago

Thank you very much @alexgrauer ! I've built my code using the h/w serial. But it's a pain... so I'll definitely give this a try. All the best!

mike89klein commented 6 years ago

Hi @tzanampeths,

This is the way I've done it. Not sure if its the most efficient one, but it works. (BaudRate: 9600)

  1. SoftwareSerial SIM5320_Serial(-1, SIM5320_SERIAL_TX_PIN); Define SoftwareSerial to only use TX functions
  2. In the setup function: SIM5320_Serial.begin(9600);

pinMode(SIM5320_SERIAL_RX_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(SOFTWARE_Serial_Active_Pin), NODEMCU_External_Interrupt_Handle, FALLING);

timer1_attachInterrupt(onTimerISR); timer1_enable(TIM_DIV16, TIM_EDGE, TIM_SINGLE);

  1. Define variables to control de received info

define SOFTWARE_SERIAL_BUFFER_SIZE 500

char. SOFTWARE_Serial_Rx_Buffer[SOFTWARE_SERIAL_BUFFER_SIZE]; uint16_t SOFTWARE_Serial_Chars_Received_Counter = 0;

uint8_t SOFTWARE_Serial_Bits_Received = 0; byte SOFTWARE_Serial_Char_Received; boolean SOFTWARE_Serial_New_Data_Received = false;

  1. Create functions to manage external and timer_1 interruptions

void ICACHE_RAM_ATTR onTimerISR(){ bitWrite(SOFTWARE_Serial_Char_Received, SOFTWARE_Serial_Bits_Received, digitalRead(SOFTWARE_Serial_Active_Pin)); SOFTWARE_Serial_Bits_Received++; if(SOFTWARE_Serial_Bits_Received == 8){ timer1_detachInterrupt(); SOFTWARE_Serial_Bits_Received = 0; SOFTWARE_Serial_Rx_Buffer[SOFTWARE_Serial_Chars_Received_Counter] = SOFTWARE_Serial_Char_Received; SOFTWARE_Serial_Chars_Received_Counter++; SOFTWARE_Serial_New_Data_Received = true; if(SOFTWARE_Serial_Chars_Received_Counter >= SOFTWARE_SERIAL_BUFFER_SIZE){ SOFTWARE_Serial_Chars_Received_Counter = 0; } attachInterrupt(digitalPinToInterrupt(SOFTWARE_Serial_Active_Pin), NODEMCU_External_Interrupt_Handle, FALLING); } else{ timer1_write(520); //104ms } }

void NODEMCU_External_Interrupt_Handle() { timer1_attachInterrupt(onTimerISR); timer1_write(780); //156ms detachInterrupt(SIM5320_SERIAL_RX_PIN); }

Let me know if you have any doubt. Hope it helps

Sorry for my miscommunication, but what mean "SOFTWARE_Serial_Active_Pin"? I use GPIO 13 as SIM5320_SERIAL_RX_PIN and GPIO15 as SIM5320_SERIAL_TX_PINK, but where active pin? Sorry for dummy question. I am a beginner.

alexgrauer commented 6 years ago

@mike89klein,

Sorry about that. The SOFTWARE_Serial_Active_Pin is there because I was trying to use this method for two different SoftwareSerial communications at the same time.

Change all occurences of SOFTWARE_Serial_Active_Pin for SIM5320_SERIAL_RX_PIN.

Good luck, and let me know if it worked.

mike89klein commented 6 years ago

@alexgrauer when I change Sowtware_active_pin on RxPin, but data transfer from the GPS module does not occur. Me only need to receive the data. Can you explain why?

alexgrauer commented 6 years ago

Hi @mike89klein.

  1. Its impossible to tell you the reason without seeing your code. I'll have a look if you send it to me.

  2. Which module are you using?

  3. This modules usually come with a baud rate of 115200, so for my code to work you should first look into changing the bajd rate to 9600 (check AT+IPREX command)

  4. You have to activate GPS funtionality and then ask the module to send the GPS information every x seconds. (Check AT+CGPS and AT+CGPSINFO commands)

mike89klein commented 6 years ago

Hi @alexgrauer 1.Unfortunately I can not show the code,it does not belong to me. The WiFi module is also working together with GPS. Work with WiFi and GPS data happens with help of ICACHE_RAM_ATTR. 2.NEO-6M 3.Baudrate 9600 4.Can you explaine how activate GPS funtionality?

alexgrauer commented 6 years ago

@mike89klein,

Have you tried using the NEO-6M module using the software serial library, without using my code? You should go for that first and get it working. Once that works go for my code. I have never used that module before, but google is full of info about it.

https://www.youtube.com/watch?v=iWd0gCOYsdo

https://www.instructables.com/id/How-to-Interface-GPS-Module-NEO-6m-With-Arduino/

mike89klein commented 6 years ago

@alexgrsuder Yes, I use this module early with library TinyGPS, but for my programm need parsing without special library. And when I create project and run the programm, after some time get error: rst cause 4, boot mode (1,6). I use your fix, but in line "SoftwareSerial SIM5320_Serial(-1, SIM5320_SERIAL_TX_PIN)" instead of "-1", I wet SIM5320_SERIAL_RX_PIN. I use one Softserial.

alexgrauer commented 6 years ago

You can not use: SoftwareSerial SIM5320_Serial(SIM5320_SERIAL_RX_PIN, SIM5320_SERIAL_TX_PIN) at the same time as my code.

If you want to use the code I've made, then you have to use SIM5320_Serial(-1, SIM5320_SERIAL_TX_PIN)

The code is actually doing the job of receiving the serial information instead of the library.

mike89klein commented 6 years ago

@alexgraurer you use code with SoftwareSerial library by plerup or Arduino integrated? And if eds dont receive information from gps with this code, then me need change some parametres NEO-6M?

alexgrauer commented 6 years ago

Honeslty, its hard to help without seeing any code. I understand you cant share it, but if you want, create a new code just testing the gps module, i will help you with that, and you can then include it in your real code. If not, it will be impossible.

mike89klein commented 6 years ago

@alexgraurer can I ask your mail?

alexgrauer commented 6 years ago

//edit by devyte alexgrauer a t gee ma il dot com

earlephilhower commented 5 years ago

@dok-net, @devyte - Do you think we can close this? The long trail seems to have wandered over a bunch of area, and now I know @dok-net and @plerup have updated SWSerial quite a few times since it was opened.

devyte commented 5 years ago

Agreed. Closing due to age. New SoftwareSerial issues should be tracked in the SoftwareSerial repo.