arduino-esp32
arduino-esp32 copied to clipboard
programming + reset issue with CDC/USB-JTAG on ESP32C3
Board
ESP32C3 custom board
Device Description
Custom ESP32C3 board ; The ESP32C3 is only connected to USB-C port, two 74HCT245D buffers (inputs only) and a tact switch (details below). This ESP32C3 design block, which follows the hardware design guide, has already been used in several boards and products without issue, there is however always differences between the designs on the pullup/pulldowns presents on the various GPIOs, nontheless all designs have pullup on 2 and 8 boot strap pins, this one is no exception.
Hardware Configuration
PIN MAP:
- 2, 3, 4, 5, 6, 7, 8, 10, 20, 21 to 74HCT245 inputs
- 9 to tact switch (no external pullup)
- 10K pullups on 2, 8 and 20
- RC reset on EN (10K pullup + 1uF to GND)
High quality 3.3V LDO with very low drop at max load and high PSRR. Sufficient decoupling all over (100nF 50V X7R class), Sufficient storage capacitors on the 3.3V rail with large derating (2*22uF 16V). Ferrite bead on 5V rail plus 3.3V rail filtering as per hardware design reference.
Version
v2.0.4
IDE Name
Arduino
Operating System
windows 10
Flash frequency
80M
PSRAM enabled
no
Upload speed
921600 (not relevant for CDC)
Description
- when plugged to USB, the board runs normally and the USB port is recognized normally
- when trying to program, the CDC does not manage to reset the board in programming mode, i get the follwing error
Connecting......................................
A fatal error occurred: Failed to connect to ESP32-C3: Wrong boot mode detected (0xc)! The chip needs to be in download mode.
The only way to program is to unplug, hold the tact switch (gpio9) plug USB and release tact to force PROG mode the programming then executes normally, however it does not manage to reset and run afterwards, a manual power cycle has to be executed.
Is there another bootstrap pin causing the issue? (other than 2 and 8 which are already pulled high) is it something with the RC reset? It is unclear to me how only the CDC reset fails but when i cold boot (aka plug USB) the board starts in the correct RUN mode, and when i use GPIO9 it starts in the correct PROG mode.
Note :
- the board does resets briefly a few time during programming attemps, so the CDC tries to reset, but fails to set the PROG mode.
- the issue is not related to the firmware itself, as the error can be reproduced with a test firmware doing nothing else than running printf + delay in the main loop.
Sketch
void setup() {
Serial.begin(115200);
while(!Serial) delay(1);
printf("init\n");
}
void loop() {
printf("test\n");
delay(500);
}
### Debug Message
```plain
Connecting......................................
A fatal error occurred: Failed to connect to ESP32-C3: Wrong boot mode detected (0xc)! The chip needs to be in download mode.
### Other Steps to Reproduce
HW setup with two buffer and pullups as described will reproduce the issue
### I have checked existing issues, online documentation and the Troubleshooting Guide
- [X] I confirm I have checked existing issues, online documentation and Troubleshooting guide.
The ESP32-C3-DEVKITC-1 schematics has the CP2102 DTR/RTS and connection to GPIO 9 (Boot).
The USB Serial/JTAG Controller is able to put the ESP32-C3 into download mode automatically. Simply flash as usual, but specify the USB Serial/JTAG Controller port on your system: idf.py flash -p PORT
where PORT
is the name of the proper port.
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/usb-serial-jtag-console.html https://docs.espressif.com/projects/esptool/en/latest/esp32c3/advanced-topics/boot-mode-selection.html
GPIO2, GPIO8, and GPIO9 are strapping pins of the ESP32-C3FN4 chip. These pins are used to control several chip functions depending on binary voltage values applied to the pins during chip power-up or system reset. For description and application of the strapping pins, please refer to Section Strapping Pins in ESP32-C3 Datasheet.
i am sorry but your two answers are quite out of touch, maybe you should read the issue again, No one asked the principle of using internal JTAG to flash, nor what bootstrap pins are, it is rather obvious that i already know since i designed the board to use native USB for programming and i mention several times the boot strap pins pullup configuration. That doesnt help a bit with the problem.
also, i use the C3F4H variant (but this changes nothing to the problem).
I'm sorry for not been of help. We deal with software here in this GitHub, not hardware.
What is the software issue, related to the ESP32 Arduino Core implementation, that you have?
CDC software layer must be loaded prior to being able to use it.
Thus, first upload any sketch using CDC enabled option from Arduino IDE in order to, in the next board reset, have CDC working and make it understand USB signaling for software upload and board reset.
Not sure if this has been already tried.
@SuGlider We do it this way for Tasmota and devices which "just" uses the CDC. Or to be more correct the USB/JTAG mode. Works like a charm. First time only needed to put manually in flash mode next time it does work like it has hardware reset circuitery. @0x0fe Take a look in Tasmota source code how it can be done ;-)
@SuGlider
the CDC is obviously enabled and used, you could have guessed it by the test sketch i gave and the fact i precised the board uses only native USB. I also precised that the "CDC reset" is working : I have confirmed the C3 does reset a few times, still it never manages to get into PROG mode.
I implemented that CDC reset mechanism on other MCUs years ago so i have a pretty good idea on how it works.
The problem here is not the CDC reset, its the setting to PROG mode, it stay stuck into RUN mode (0xc).
I havent looked into the details on how it is implemented here, but usually we write on a register / flash so that after the reset the bootloader goes into PROG mode, i assume it is done in a similar way here except with internal jtag and thus i have a very hard time understanding how the hardware could possibbly have any impact on this. But it does since the programming is failing on this specifc design.
On other design it works fine and i use it everyday, also that is the 7th production design with this ESP32C3 block so its not like we are starting with it.
@Jason2866 Not sure what you are talking about, CDC and internal JTAG are two different things, the CDC is used to reset into prog mode then the internal jtag block takes over for the reprogramming phase. Using CDC to trigger a reset is an old trick. This mechanism is already implemented in the arduino core and works fine, So, yes, that is how it works, what does it have to do with the issue?
The problem is that, on this particular board, this programming via CDC/JTAG just fails and it shouldnt. Something is preventing it to work correctly. As I shown in the log, the C3 is still stuck in RUN mode after being reset by the CDC, that is the issue.
Also, if we force PROG by booting with GPIO 9 low (and releasing it after power up) then the C3 become stuck in PROG mode, we can program it over and over but it never resets to RUN mode by itself, only a power cycle does. Which is also totally abnormal.
@0x0fe - where do you think the problem is?
Last 2 cents:
JTAG/CDC USB interface uses DTR/RTS bits to reset and enter in Boot Mode.
The way it works can change depending on the eFuses.
Maybe you may want to check it.
This information is in page 612 it the C3 TRM and eFuse is explained in the chapter 4 of the TRM.
Maybe the eFuses of your chip are wrong.
True, so i didnt get your problem. I thought it is to flash and run (after flash) the programmed firmware on the C3. If connected again to programm the device again and starting the firmware without any manual steps. This is working.
@SuGlider
where do you think the problem is?
At this point i am not sure, i thought it could be related to strapping pins latching at a time where they are in a wrong state, maybe due to a glich after reset on the GPIO controlling OE of the bufferr, but the problem with this theory is :i dont think strapping pins are taken into account after the CDC reset, what lead me to this conclusion : if i hold GPIO9 low while the system is trying to program with CDC reset it doesnt work either, which seems to prove GPIO9 state is not taken into account here.
During the chip’s system reset, the latches of the strapping pins sample the voltage level as strapping bits of ”0”
or ”1”, and hold these bits until the chip is powered down or shut down
I also thought it could be GPIO10 since it seems to be able to disable JTAG function, however, it would not lead to an error of boot mode (0xc), rather a failure to program. Besides, i added a pullup to force it high after reset and it did not help.
@Jason2866 no problem and sorry for the harsh tone, i appreciate you came to help.
Last 2 cents: JTAG/CDC USB interface uses DTR/RTS bits to reset and enter in Boot Mode. The way it works can change depending on the eFuses. Maybe you may want to check it. This information is in page 612 it the C3 TRM and eFuse is explained in the chapter 4 of the TRM. Maybe the eFuses of your chip are wrong.
OK i will check these control lines bits, good idea, i still fail to understand how pin map of non strapping pins could impact these.
So, BLOCK0 is all 0, the problem must be elsewhere
C:\TOOLS\esptool-v4.2.1-win64\espefuse.exe --chip esp32c3 --port COM42 dump
espefuse.py v4.2.1
Connecting...
BLOCK0 ( ) [0 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000
MAC_SPI_8M_0 (BLOCK1 ) [1 ] read_regs: 0366c570 000084f7 00000000 490c0000 00702141 0007d281
BLOCK_SYS_DATA (BLOCK2 ) [2 ] read_regs: 303a69f8 a3f4d5e4 4e703047 ad2c4ea8 99354a79 7af6438b 5e368163 00000009
BLOCK_USR_DATA (BLOCK3 ) [3 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_KEY0 (BLOCK4 ) [4 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_KEY1 (BLOCK5 ) [5 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_KEY2 (BLOCK6 ) [6 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_KEY3 (BLOCK7 ) [7 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_KEY4 (BLOCK8 ) [8 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_KEY5 (BLOCK9 ) [9 ] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK_SYS_DATA2 (BLOCK10 ) [10] read_regs: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
BLOCK0 ( ) [0 ] err__regs: 00000000 00000000 00000000 00000000 00000000 00000000
EFUSE_RD_RS_ERR0_REG 0x00000000
EFUSE_RD_RS_ERR1_REG 0x00000000
=== Run "dump" command ===
i removed the two buffers, so essentially the ESP32 is now only connected to USB receptacle and tact switch, the problem persists, the plot thickens... I will now replace the ESP32C3H4, maybe it is related to the chip itself (which was obviously new at assembly).
i replaced the ESP32C3, same problem, so there must be something wrong with what remains of the hardware once the two buffers removed.
the board has been stripped of anyting connected to GPIOs other than pull ups on GPIO2 and GPIO8, tact switchon GPIO9 and USB receptacle on D+ D-.
the ESP32C3 has been replaced with a brand new 3 times. The problem still persists, The cause is still unknown.
I noticed something very strange : GPIO9, measures 4.5V to 5V toward GND. GPIO9 is floating on the board (open tact switch, no PU, no cap) and so the only thing which can bring this trace to such voltage is the internal C3 pullup, i actually went as far as cutting the trace shortly after the C3, the voltage is still present on the remaining stub on C3 side.
The only other place where 5V can be found on this board now is the LDO input (output is 3.386V stable), of course the C3 only ever receives 3.38V on it VCCs and GPIOs, i did cut the 5V trace on the board at the LDO input to make sure leakge was not possible and 5V was not present anywhere on the board other than at the LDO input.
USB D- measures 4.5V varying,
This GPIO9 abnormal voltage seems pretty weak, it slowly discharges from 5V to about 4.2V and stays there but will increase back to 5V sometimes, i did not found a specific pattern, i assume it slowly regain 5V once i stop measring, so it would be very weak since the multimeter impedance is enough to slowly drop it until 4.2V .
I must say i am very confused by this, but maybe it is the same on other C3, i will verify one of the previous C3 designs later, by the way i also tested the programming setup with a baord from a previous design and it works perfectly fine, automatically enters and leave programming mode, runs automatically after prog, just as it should,
So, a little puzzled by the issue. It is clearly related to this particular board, but so far nothing makes much sense and despite the extensive testing no clue can be found except this abnormal voltage appearing on GPIO9.
the 40M crystal has been replaced for another brand (also 12pF 10ppm), the inductor to limit amplitude on the crustal trace has bee replaced with 24nH wirewound, GPIO2 / GPIO8 pullups values have been measured and found to be within tolerance (10K 1%). the whole board has been fully cleaned with isopropyl, reflowed on hot plate and inspected under binaucular microscope to rule out any cold joint, the problem persists. Additional storage caps have been added to the VCCs on ESP32 side, no effect (there was ample storage and decoupling already). The USB cable is shielded, shielding is of course connected to GND on one side only. Tested on USB 2 and USB 3 ports. Tested with an older version of ESPTool. The problem persists
so, there is some news on the issue:
I faced this issue again but with another design, which worked fine on last batch (with the previous revision of the core), so i tested another method and found something leading me to think it is related to arduino / ESPtool and not related to the hardware. Here is what i found :
- i connect an UART software, clear RTS, set DTR, set RTS, clear DTR, the C3 goes correctly in PROG mode
- i disconnect the UART software and start ESPTOOL V4.2.1, it successfully flashes AND resets to run mode,
- i re-connect the UART software and i can see the C3 is now in RUN mode, the firmware is working as it should
I tested it on both boards concerned by the issue, works for both. The UART software i used is UART Assistant V5.0.3 but any UART software providing control over DTR RTS should work. I used ESPTOOL V4.2.1.
So, now that the cause is identified if someone at espressif could look into the issue it would be appreciated, obviously such upload method dramatically impacts the development workflow and is just not viable. For remind both Arduino (esptool.py v3.3) and ESPTOOL V4.2.1 are failing to automatically upload when used directly. The only way to reflash as of now is to use the external UART software first and then ESPTOOL V4.2.1. So it seems whatever method (pyserial?) is used to set DTR and RTS sequence is not working anymore with CDC, at least in some cases.
IMHO It could be related to:
- pyserial
- windows default driver
- USB stack (CDC)
- ...
I am not sure, but the problem is very real, i dont know why it hasnt been reported yet, but most public dev boards are still using USB-UART bridges so they are not concerned by the issue, it only occurs with the USB CDC obviously, and it occured to me only on the last arduino core (may be coincidental).
Side note #1, another design does not exhibit the issue, it can be flashed and run automatically with last core in CDC mode, however its the exact same hardware regarding the C3 (same routing, same layout same parts, same bootstraps). The only difference is : it has been used before on an older version of Arduino core (without issue) so, that may mean the issue is also related to the bootloader... Where the two new boards would only ever have had a newer version of the bootloader and fail, and the older board still uses an older version of the bootloader, and works. THis theory is yet unverified, i dont know if i can even verify the bootloaders version, but that may be a clue.
Side note #2 i can confirm a voltage higher than VCC does appear on GPIO9, during the upload phase, in CDC mode, 3.8V to 4.0V, where the C3 only ever receives 3.3V at most on its VCC pins or GPIOs (except USB data lines). That is very strange for the least and confirmed on 3 board, of which two are different designs (but the C3 part is identical)
@SuGlider
@SuGlider
https://github.com/espressif/esptool/blob/2fb8d4539b39d109421581957a1ce6fb992786e7/esptool/loader.py#L500
i note that the custom sequence in esptool.py does not fully match what worked to go into PROG mode what i did : clear RTS, set DTR, set RTS, clear DTR what it does : clear RTS, clear DTR, set DTR, clear RTS(?), set RTS, clear DTR, set RTS, clear DTR(?), clear RTS
In esptool RTS is cleared after it was already clear, and DTR is also cleared after it was already clear, i dont really understand the logic of this sequence.
# Custom reset sequence, which is required when the device
# is connecting via its USB-JTAG-Serial peripheral
self._setRTS(False)
self._setDTR(False) # Idle
time.sleep(0.1)
self._setDTR(True) # Set IO0
self._setRTS(False)
time.sleep(0.1)
self._setRTS(True) # Reset. Note dtr/rts calls inverted to go through (1,1) instead of (0,0)
self._setDTR(False)
self._setRTS( True ) # Extra RTS set for RTS as Windows only propagates DTR on RTS setting
time.sleep(0.1)
self._setDTR(False)
self._setRTS(False)
so, i am onto something here, to get esptool working, i had to comment basically the whole block, i suspect it goes to the wrong branch of the condition, that is, it does not go to usb_jtag_serial when i use this, it works directly and it also seems faster (since there is alot less delays/toggling
so, theory confirmed, it works that way too, so it is a problem with the conditional statement, most likely somewhere in the new core the define usb_jtag_serial is not set, and thus it goes to the wrong branch here and runs the reset code for UART bridge instead of CDC
thanks espressif for not giving a fuck about a quite major issue
Great you found a way you get it going! One thing is unclear for me, how can esptool.py check if a define usb_jtag_serial
is set or not? Where is this info stored? How could it be set?
Great you found a way you get it going! One thing is unclear for me, how can esptool.py check if a
define usb_jtag_serial
is set or not? Where is this info stored? How could it be set?
i found the cause and a fix, but that does not resolve the issue, since arduino environement uses a compiled version of esptool which is not fixed, so for now it does not help very much, I have to copy the long arduino output (after a failed flashing) and paste it in cmd prompt, and redo that each time the temp directory where stuffs are build changes. OK for few days, but not quite right, i dont understand how espressif is letting this without chiming in for 10 whole days.
As for how this usb_jtag_serial is set, i have not idea yet either, i did not check deeply in this python mess, it does not seem to be passed as an argument to esptool from the arduino IDE, at least i did not notice it, maybe esptool is supposed to automagically detect wether the USB port used is a CDC or USB-UART bridge, but it seems dubious given how poor the uart port handling is on windows. If that is the case it would explain why one ESP32C3 still flashes normally and all others don't, maybe windows self assigned driver issue. Not sure yet.
mmh https://github.com/espressif/esptool/blob/2fb8d4539b39d109421581957a1ce6fb992786e7/esptool/loader.py#L623
usb_jtag_serial = (mode == "usb_reset") or (
self._get_pid() == self.USB_JTAG_SERIAL_PID
)
so, as expected, changing from default_reset to usb_reset fixes the issue
that also means the detection of CDC by pid/vid is not reliable (what a surprize).
I believe this argument can be altered in board. txt or some other arduino core configuration file
so, there is a way to do it from boards.txt but the whole menu structure has to be changed and this will require quite many changes. The only quick way is to force it in platform.txt for now
But of course it breaks the back compatibility to any C3 board fitted with USB-UART bridge (so most public boards).
I hope Espressif can understand the problem and at least add a menu where we can select between defaut reset and usb reset for the C3 module, since the CDC mode detection method they use in esptool is just not reliable