Out of the box my ESP32 dev board required me to hold down the BOOT button at the start of programming to get it to program from the Arduino IDE. The board has a pair of transistors to connect the DTR and RTS lines to EN and GPIO0. This is intended to enter programming mode automatically but seems to have timing problems. If I don't hold the button I get:
Fatal Error Occurred: “Failed to connect to ESP32: Timed out waiting for packet header”
Looking around the internet I found a recommendation to add a 10uF electrolytic capacitor between EN and ground. While this did work for programming it seemed to inhibit the board reset at the end of programming. I found 1uF worked better, which let me use a small ceramic SMT cap, which is a lot neater.
The nearest ground is the top right pin of the module and I could have angled it to reach that but I found it easier to just link it to the metal can.
Investigating why it doesn't work I found the setup and hold times for the strapping pins in the ESP32 datasheet:
To enter programming mode GPIO0 needs to be low as EN transitions to high and stay low for 1ms after that.This is the two transistor circuit on my board which is labelled ESP32 DEV KIT V1, which implements the truth table shown.
The truth table shows that EN and IO0 can't go low at the same time, so the zero setup time cannot be achieved unless both lines change together. Here is what it looks like on a scope after I added the capacitor.
My best guess is the transistor circuit is there to ensure random serial monitors don't put the board into programming mode if they assert both DTR and RTS. To work without a capacitor RTS and DTR would need to change state simultaneously. There is a long discussion about it here: https://github.com/espressif/esptool/issues/136.