Weird problem using ESP8266 Serial communication

Hi all,

I came across a very strange problem when using Serial communication between ESP8266 and a device measuring voltage, current and power. I've tried many things and here I briefly describe my problem and the experiments I've done. I'd appreciate any advice or help!

  1. About the measuring device (called "device" below)

The device ("power monitor") is an IM1281B, a module measuring current, voltage, power, frequency, ec and communicate with the MCU using UART protocol (with default baudrate 4800). The communication is simple: the MCU sends a UART command, the device does the task (e.g., measure certain quantities) and return a UART byte string consisting of the results. To show a simple example, here are some Python codes communicating with the device.

>>> from serial import Serial
>>> ser = Serial('/dev/ttyUSB0', 4800)
>>> b_command = b'\x01\x03\x00\x48\x00\x08\xc4\x1a'  # the command "measure all quantities"
>>> ser.write(b_command)  # send the command via serial port
>>> ser.read_all()
b'\x01\x03\x20\x00..........'

In the above code, a command is sent to the device from the serial port of the computer, and the device does what the command means, and returns the corresponding results. (It's a byte string of typical length 37.) How to interpret the returned bytes is not relevant here.

  1. Problem occurred when ESP8266 replaced the computer's serial port

So far so good with the computer. However, when I used the ESP8266 to send the command and receive the results, I no longer receive anything. Here are the Arduino IDE codes.

uint8_t command[8] = {0x01, 0x03, 0x00, 0x48, 0x00, 0x08, 0xC4, 0x1A}; // the command same as above


void setup()
{
  Serial.begin(4800); // Serial communicates with the device
  Serial1.begin(115200); // ESP8266's transmission-only port (GPIO2) used to display debugging info

  Serial.println();
  Serial1.println();
  delay(5000);  // wait a while before sending the command, to separate the command from the 
                      // annoying boot-up gibberish of ESP8266.
}


void loop()
{
  Serial.write(command, 8); // send command using UART
  Serial1.println("Command sent! Waiting for reply");
  
  while(!Serial.available()) // wait for incoming data from the device
  {
    Serial1.print("."); // the codes stuck in this loop
    delay(500);
  }
  Serial1.println("\nReceived data!");

  while(Serial.available()) // receive the bytes and print them to the debugging serial
  {
    Serial1.print(Serial.read(), HEX);
    Serial1.print('\t');
  }
  delay(10000); // wait for 10 secs before sending another command
}

Hardware wiring:

  • "TX" and "RX" pins of the ESP8266 devKit (GPIO1 and 3) connected to the device.
  • GPIO2 (Serial1's TX pin) connected to the computer via a UART/USB converter, to display the debug info.

Result: After printing "Command sent! Waiting for reply", the program always got stuck in the "while(!Serial.available())" loop, and printed "......" forever.

  1. Is the ESP8266's boot-up gibberish responsible for this problem?

No. In the setup function, I did a 5 secs delay, and the command will be sent to the device at least 5 secs after the boot-up. The device is fully capable to invalidate and ignore the boot-up gibberish. In fact, I've used Python to simulate this "Gibberish" --> 5 secs --> command data flow, and got the response from the device. Therefore, the ESP8266's boot-up gibberish, although annoying, is not responsible for this problem.

  1. Did we get stuck in sending the command, or receiving the results?

To see whether the device has received the command from the device and sent out the results, I did the following:

  • Connect ESP8266's TX pin to the device's RX pin.
  • Connect the device's TX pin to the UART/USB converter's RX pin.
  • Connect the converter's TX pin to ESP8266's RX pin.

That is, I used the computer's serial port as a UART relay. The relay codes are a simple piece of Python codes using PySerial:

from serial import Serial
ser = Serial('/dev/ttyUSB0', 4800)

while True:
  x = ser.read()
  ser.write(x)
  print(hex(ord(x))) # print the relayed data in HEX form

Result: The computer printed the results returned by the device and, what's more, ESP8266 now can print the results, too!

The moral of the story is: The device can receive the command from ESP8266, and produce results, but ESP8266 cannot receive the results directly from the device, although it can receive the results indirectly, from the computer's serial port, with the same data, and the same baudrate 4800.

I also tries the experiment where the computer's TX (or, the UART/USB converter's TX) connects to the device's RX, and the device's TX connects to ESP8266's RX. In this way, I can send the command directly from the computer, and I'm pretty sure that the device could receive the command and respond. However, the ESP8266 could not receive anything and got stuck in the same while loop. (.......... forever)

Although I can locate the problem, I cannot understand why it was like this. Is this related to any electrical property of the serial communication? What's the difference between the data sent by the computer and by the ESP8266 chip? Any other test do you think worth doing to solve the problem?

Thanks in advance for your help!

voltage difference on TTL 3.3 V v. 5 V

Hi. Thanks for your reply. I've considered this possibility. But my UART/USB converter gives 3.3V signal, and ESP8266 GPIOs are working on 3.3V voltage. The device accepts 3.3~5V signal, and I supplied 3.3V to its Vcc pin. I'm not sure where else this 3.3-5V difference issue can come in? Is there anything I was missing?

Thanks very much~

Juraj:
voltage difference on TTL 3.3 V v. 5 V

I've explicitly checked it. The voltage of the device's TX pin is 3.0V when not connected, and is 3.2V when connected to the ESP8266's RX pin. This seems to suggest that voltage difference is not an issue?

Use an UNO as a serial port relay. What happens ?

can you port the whole thing to an UNO ? and see if that can work ?

dave-in-nj:
Use an UNO as a serial port relay. What happens ?

can you port the whole thing to an UNO ? and see if that can work ?

Thanks for your response. Yes. It worked very well for UNO. Here's what I did:

Using UNO, providing 5V voltage to the measuring device from UNO. It worked gracefully and when I measured the voltage on TX and RX, both were close to 5V.

Using ESP8266's default hardware serial, providing 3.3V voltage to the measuring device. No data came, and when I measured the voltage on TX and RX, both were close to 3.3V. (That was why I don't think voltage difference was a problem here.)


Later, I tried ESP8266's software serial. Interestingly, it worked like a charm! That surprised me because I thought hardware serial should be more reliable than the software serial, and I don't know in this case, what's the difference between the hardware serial and the software serial.

By the way, after checking some example codes, I saw people put ser.flush(); (ser being the software serial) before sending the command, and put ser.enableTx(true); before sending data via ser.write(); and put ser.enableTx(false); immediately after sending data out. When receiving data, they used ser.enableRx(true); before looping to receive the incoming data. However, I guess this is not very relevant to my problem? My feeling is that the hardware serial should have enabled Tx and Rx by default?

Indeed, after commenting these lines away, the software serial still worked. So I think the difference still lies in the usage of software serial.

I'd appreciate any explanation on this!

it will be timing related. the exact baud rate can differ from requested

Juraj:
it will be timing related. the exact baud rate can differ from requested

That's possible. Is it true that the hardware serial, which depends on some hardware timer, does not work very well for baudrate = 4800, while the software serial, using CPU clock, does a better job here? That's also a bit strange for me since I expected both working well at such a low baudrate...

By the way, why did we use the conventional 115200 baudrate anyway? What if we choose 115000, for example? Is this only conventional, or does it have anything to do with any clock?

thales_liu:
By the way, why did we use the conventional 115200 baudrate anyway? What if we choose 115000, for example? Is this only conventional, or does it have anything to do with any clock?

Juraj:
What standard UART rates are there? - Electrical Engineering Stack Exchange

That's a pretty interesting and historical post. However, I still think 4800 baudrate should be low enough for both the device and the chip. I tried to visualize the signal, from both sources, and the difference of the pulse width is not visible over the entire range. :slight_smile: