Weird issue where serial comms stop working after USB is disconnected and rebooted

jcun4128

Member
I have a Teensy 4.0 connected to an ESP01 via the Teensy 4.0 Serial 5 (20, 21) and ESP01 Tx/Rx pins.

The Teensy and ESP-01 share the same ground. They're both turned on at the same time (not sure if that matters). Using 115200 baud rate on both sides.

If the Teensy is plugged into the computer by USB, the two-way communication between the two works. If I unplug the USB cable, this still continues to work as expected.

But on next reboot (Teensy and ESP-01) the Teensy can't communicate with the ESP-01 correctly anymore as in the Teensy writes to Serial5 but the ESP01 does not receive it. I'm not sure why...

I can provide more info as needed but that's the context.
 
I can, it's just a lot. Well a lot of parts anyway. I'm really trying to avoid that classic XY problem.

Context on ESP01, it's a websocket, it sends data to the Teensy from the web and vice versa.

The Serial.begin(115200); line on Teensy side was not originally there/just a thought maybe helps, doesn't seem to.

The WiFi related parts of the ESP01 are not there. The WiFi connection isn't an issue.

As mentioned the code does what it's supposed to while the USB cable is plugged into the Teensy. But after I remove it and reboot the two devices, it stops working.

The ESP is connected to the web page web socket but it doesn't get any messages from the Teensy.

Teensy
Code:
void setupSerial5() {
  Serial5.begin(115200);
}

void setup()
{
  Serial.begin(115200);
  setupSerial5();
}

void loop()
{
  Serial5.println("esp");
  delay(1000);
}


ESP01
Code:
bool clientActive = false;

void setup()
{
  Serial.begin(115200);
  // connects to wifi this is fine
} 

void loop()
{
  if (!clientActive)
  {
    auto client = socketServer.accept();
    clientActive = true;

    for (int i = 0; i < 1000; i++) // 1 second ESP to Web client connection poll
    {
      if (client.available())
      {
        auto msg = client.readBlocking();

        if (msg.data().length() > 0)
        {
          Serial.print(msg.data());
        }

        if (Serial.available())
        {
          client.send(Serial.readString());
        }
      }
      delay(1);
    }

    client.close();
    clientActive = false;
  }

  delay(50);
}
 
I wonder if it's related to the buffer somehow. I did notice if I speed up the main loop delay on the Teensy, it just doesn't work at all.

There was one time I saw this message across the serial monitor that I haven't seen before said something like "decode exception" long dashes across the screen.

It seemed to have crashed due too much stuff in the buffer or something (in serial print).

I wonder if while the USB is plugged in it reads some so it can work... I don't know I'm completely guessing here.

The "message" I'm sending is a string at least 42 char long.
 
I stripped out a bunch of my code. Also for good measure added a direct ground wire connection between the ESP-01 and Teensy 4.0
I also used the #define name Serial5 approach not sure if it matters. Tried different baud rates (didn't matter).

I think the main issue is serial buffer build up due to mismatch of timing.

Can see in the attachment (websocket data from browser dev tools) weird problems if green (sent by web to ESP) is not divided by the espesp lines (should actually only be one) that means it's failed/not communicating.

I am using serial flush/read thinking I am getting rid of it so it doesn't build up but maybe not. The longest thing I am sending is a 9-axis IMU sample which is 51char long.

But even right now with just sending "esp" I'm having this issue... the two I think makes sense I'm using 1000ms poll delay on the Teensy side and the websocket side (green) is also every second.

But this is good, means no problem with wiring just code needs work.

Part of the timing problem is the websocket sample code is a one-off, so once it does something it closes the connection. My mod keeps it open but syncing the two times is not working well apparently.

Might be an issue though where Teensy can't receive data from ESP01... idk. But I proved that bi-com works when USB is unplugged.

Actually could be false hope. Sometimes it doesn't "reset" all the way so it still works as if it was plugged into USB but after a few restarts it goes back to the bad state.

serial-build-up.png
 
Last edited:
Again hard to see what is going on without more code.

For example if your teensy code has something like:
Code:
while(!Serial) ;
in the setup function, it will hang at that point.

If you started first on USB it would have satisfied that and then later removing usb cable won't likely hit that code again.
 
Another completely blind guess... or really, just mentioning a problem we've seen from time to time when people build projects with serial-to-serial communication between microcontrollers.

If the transmitting side never pauses and always generates 100% bandwidth output, and if you start (or reboot / restart) the receiver while the transmitter is sending 100% output utilization, you can run into this problem where the receiver is unable to properly sync to the beginning of a byte.

https://forum.pjrc.com/threads/6745...r-1200-baud-rate-for-UART?p=281054#post281054

Not an issue if the receiver is started before the first transmission begins.

Also not an issue if the transmitter occasionally pauses, as the receiver will at worst hear "garbage" from where it started in the middle of a byte until the first time the transmitter leaves the line idle for 9+ bit times, and then all reception will be properly in sync with the actual bytes.
 
Again hard to see what is going on without more code.

Code:
while(!Serial) ;

I have seen that mentioned in some threads but I don't have one of those lines, not one that I added anyway.

If the transmitting side never pauses and always generates 100% bandwidth output...

Not an issue if the receiver is started before the first transmission begins.

...receiver will at worst hear "garbage"...

Both sides have a delay of some form. Oh man I don't have an O-scope ha, one thing I'm missing, need to add it to the list. I'm going to read up on that.

I could look into the "started before the first" bit... both microcontrollers are using the same power source/switch. I could solder on another switch and turn them on at different times.

The garbage bit does happen and then it starts streaming the expected sequence.

Thanks for the ideas. I'm just really hoping this project isn't partially doomed from this problem.

I will post a schematic and "full code" (commented out all other code except bare minimum) in another response.

It's also interesting if I let it run for a bit, it can "get out of sync" and you can see in the image what happenssomething-happens.JPG
 
So it looks like I just had to wait long enough for the first super-long-concatenated serial print to make it and then it starts working normally.

I have restarted it a few times so it's not that issue where it hasn't fully reset yet from when it was last plugged into a USB.

Teensy code

Code:
#define ESPSERIAL Serial5

void setupEspSerial()
{
  ESPSERIAL.begin(115200);
}

void setup()
{
  setupEspSerial();
}

loop()
{
  ESPSERIAL.print("esp");
  delay(1000);
}

ESP01 code

Code:
// using library https://github.com/gilmaimon/ArduinoWebsockets
#include <ArduinoWebsockets.h>
#include <ESP8266WiFi.h>

using namespace websockets;
WebsocketsServer socketServer;

bool clientActive = false;

void connectToWiFi()
{
  WiFi.begin("SSID", "PASS");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Waiting for connection");
  }

  Serial.println("Connected!");
  Serial.println("Starting socket server...");
  socketServer.listen(80);
}

void clearSerial()
{
  while (Serial.available())
  {
    Serial.read();
  }
}

void setup()
{
  Serial.begin(115200);
  connectToWiFi();
} 

void loop()
{
  if (!clientActive)
  {
    auto client = socketServer.accept();
    clientActive = true;

    for (int i = 0; i < 1000; i++) // 1 second ESP to Web client connection poll
    {
      if (client.available())
      {
        auto msg = client.readBlocking();

        if (msg.data().length() > 0)
        {
          Serial.print(msg.data());
        }

        if (Serial.available() > 0)
        {
          client.send(Serial.readString());
        }
      }
      delay(1);
    }

    client.close();
    clientActive = false;
  }

  delay(50);
}

Hmm I do have the connected junk in there

first-run.JPG

Sorry for this crappy schematicschematic.JPG
 
Last edited:
Oh there is one thing I wasn't sure yet if it was obvious.

When you do
Code:
Serial.readString();
does that clear the serial buffer/I don't have to immediately call a
Code:
clearSerial()
function?

It seems to be doing a lot better now. I wonder if it was just those stray wifi connect serial print calls on the ESP side.

It still bunches up on boot but then it frees up and functions faster.

Yeah the bunching still happens. I was throwing in serial clear calls wherever I could think of but doesn't seem to help.

Anyway I don't expect to be streaming real-time data it's supposed to be for minor remote commands and some telemetry to a web interface.
 
Oh there is one thing I wasn't sure yet if it was obvious.

I'm pretty sure the answer is yes, it almost certainly does remove those bytes from the buffer is it reads them.

But I hope you can understand this question is about about the precise behavior of an ESP8266 function. You're asking on a forum about Teensy.

Reading your code, admittedly only quickly and without much personal ESP8266 experience, the use of 2 delays seems like a strange choice. The common design practice with hardware serial is to use delays or other timing mechanisms only on the transmitter side, so the data is sent at a well defined rate of messages. Usually the receiving side is built without software delays and paces itself according to the rate of incoming messages. When timing code is used on the receive side, it's typically done as timeouts to give up or take some corrective action if data doesn't arrive within the expected time frame. Maybe you have a good reason for doing things differently. If so, that's (probably) fine. But if you're just experimenting & learning, I'd recommend following the common practice of delays or pacing only on the transmit side.
 
Reading your code, admittedly only quickly and without much personal ESP8266 experience, the use of 2 delays seems like a strange choice. The common design practice with hardware serial is to use delays or other timing mechanisms only on the transmitter side, so the data is sent at a well defined rate of messages. Usually the receiving side is built without software delays and paces itself according to the rate of incoming messages. When timing code is used on the receive side, it's typically done as timeouts to give up or take some corrective action if data doesn't arrive within the expected time frame. Maybe you have a good reason for doing things differently. If so, that's (probably) fine. But if you're just experimenting & learning, I'd recommend following the common practice of delays or pacing only on the transmit side.

Oh yeah I definitely don't have a reason for my choices other than trying to get it to work/hobby.

I will work on making those changes where everything is driven from the transmitting side.

Thanks. If there was one more i2c bus I would have been set ha... no having two was great I didn't have to deal with swapping devices.

Actually I probably would still have the same problem due to the mismatch in timing.

Edit: actually there is a 3rd bus but under the board dang.

Anyway I'm just glad nothings wrong/it should work as I expect because I already have everything soldered together/did not want to take it apart. I just happened to test while the USB was plugged in/threw me off.

Oh there is one thing I can try/add as well, checking if the previous data has been removed yet before adding more/trying to send more.
 
Last edited:
Back
Top