Error uploading to ESP32 on Raspberry Pi 4 (Linux Arm) but not on Windows

I am using PlatformIO core 5.0.0 to upload code on my ESP32 board. However the upload fails and I get an timeout error every time.
I have the exact same setup on my Windows x86 PC (latest PlatfromIO version as of today, embedded in VScode) with the same code, same USB cable, and same ESP32 board and the upload works all the time.
I am using a CP2104 USB to TTL adapter with the correct reset circuit.

Any ideas?

Building in release mode
Retrieving maximum program size .pio/build/featheresp32dev/my_project.elf
Checking size .pio/build/featheresp32dev/my_project.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [=         ]  11.5% (used 37704 bytes from 327680 bytes)
Flash: [========  ]  82.6% (used 1083051 bytes from 1310720 bytes)
Configuring upload protocol...
AVAILABLE: esp-prog, espota, esptool, iot-bus-jtag, jlink, minimodule, olimex-arm-usb-ocd, olimex-arm-usb-ocd-h, olimex-arm-usb-tiny-h, olimex-jtag-tiny, tumpa
CURRENT: upload_protocol = esptool
Looking for upload port...
Auto-detected: /dev/ttyUSB0
Uploading .pio/build/featheresp32dev/my_project.bin v2.6
Serial port /dev/ttyUSB0

A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header
*** [upload] Error 2
=========================================================================================== [FAILED] Took 36.98 seconds ===========================================================================================

Environment      Status    Duration
---------------  --------  ------------
featheresp32dev  FAILED    00:00:36.979

Have you tried putting the ESP32 explicitly in bootloader mode (hold FLASH, press RESET, release FLASH button) before flashing?

Have you tried setting a lower upload speed with upload_speed = 115200 in the platformio.ini?

Thanks for the tip, it works when I press the FLASH (GPIO 0) button. Any idea why I need to do this on Linux and not on Windows, with an identical setup? It’s not very convenient as I am using the system for a automated firmware flashing jig.

Have you tried the lower speed regardless?

If it isn’t affected by that, then there might be a problem with or the linux kernel driver. The reset circuit is driven by the RTS / DTR pins of the USB-Serial adapter to control RESET and FLASH. I’ve already seen some drivers inverting its wanted output level once so you had to specify the reverse, actually…

To be 100% sure it’s not PlatformIO you should pio run -t upload -v in the project and copy the complete invocation. Then execute that manually. If it now magically and reproducely works (without having previously reset the ESP32 to bootloader mode!), then it’s in PIO. If not, then can’t reset the ESP32 properly although being told to with some reset method = nodemcu flag or something. Then you can start and trace the signal on the DTR/RTS pin at your serial adapter to see if it’s signaling anything when you press flash.

If there is some signal activity but the ESP32 doesn’t reset then there’s something wrong in the reset circuitry and it doesn’t correctly get translated to a “reset while gpio0 is low, then release gpio0” action or the signal activity is wrong, e.g. inverted RTS/DTR levels.

If there’s no signal activity, then either is invoked in a wrong way and doesn’t attempt the reset signaling, or it does attempt it but the underlying layer screws up at giving the serial adapter the correct commands.

Lastly with ESP32 many problems can be related to power issues. The ESP32 may draw some current on reset and especially when it starts up its WiFi radio. So maybe if you press it manually, you just give it enough time to reset and be stable. More decoupling capacitors, a better power supply or shorter cables may help you there.

I have pio run -t upload -v, copied the invocation and tried it - same probem.

I looked at the FLASH and RESET line on the oscilloscope (You can see them on the screen shot attached, yellow is RESET, blue is FLASH ) and I can tell why it’s not working, the signals are not doing what they are supposed to do at all.
Then I tried inverting the signals in the def _setDTR(self, state) and def _setRTS(self, state) functions but still failed to upload.

As a work-around, I get my Rpi to hold FLASH LOW using RPi.GPIO, and that works reproducely.

I don’t have time to investigate why so I’ll have to keep it at that for now. Thansk for your help!

1 Like