HowTo: Fix your ESP32 C3’s Bootloader after you messed it up

October 28, 2025 @ 01:26

When I was recently playing around with my CanGrow Firmware and trying to load it to ESP32 S2 and ESP32 C3 boards, i accidentally flashed the wrong firmware binary to my ESP32 C3. And to make things worse, I also wrote it at the very beginning of the flash and overwrote the existing bootloader living there.

The result: An ESP which I can flash with my program, but it wont boot it at all.

Verbindung zu /dev/ttyACM0 wird hergestellt. Abbrechen mit STRG-C.
ESP-ROM:esp32c3-api1-20210207
ESP-ROM:esp32c3-api1-20210207
Build:Feb  7 2021
rst:0x7 (TG0WDT_SYS_RST),boot:0xc (SPI_FAST_FLASH_BOOT)
Saved PC:0x40047ed2
Invalid chip id. Expected 5 read 3424. Bootloader for wrong chip?
ets_main.c 333 

The good news, there is an easy fix! In the “Released binaries” from Espressif, they deliver the standard bootloader as well. For the ESP32 C3 its this Page: https://docs.espressif.com/projects/esp-at/en/latest/esp32c3/AT_Binary_Lists/esp_at_binaries.html

In case you need the bootloader for a different ESP, just search for “Espressif Released firmware ESP32-XY” and the first hit should be yours:)

From there, download the AT Firmware, which filename should be like ESP32-C3-MINI-1-AT-V4.1.1.0.zip. Unzip it somewhere and now look for the file bootloader itself: bootloader.bin

$ unzip ESP32-C3-MINI-1-AT-V4.1.1.0.zip
$ cd ESP32-C3-MINI-1-AT-V4.1.1.0
$ find . -name "bootloader.bin"
./bootloader/bootloader.bin

If not already on your pc, install or download esptool. As a debian user, a simple apt install esptool works fine for me.

Now the moment of truth: uploading the bootloader. Ensure your bricked ESP is connected, every other ESP is disconnected and flash the bootloader to the ESP:

# erase the internal flash before, to wipe every garbage out
$ esptool erase_flash

Serial port /dev/ttyACM0
Connecting....
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (QFN32) (revision v0.4)
Features: WiFi, BLE, Embedded Flash 4MB (XMC)
Crystal is 40MHz
MAC: 20:6e:f1:6a:cf:b4
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 1.7s
Hard resetting via RTS pin...

# upload the new bootloader
$ esptool write_flash 0x0 bootloader/bootloader.bin 

Serial port /dev/ttyACM0
Connecting...
Detecting chip type... ESP32-C3
Chip is ESP32-C3 (QFN32) (revision v0.4)
Features: WiFi, BLE, Embedded Flash 4MB (XMC)
Crystal is 40MHz
MAC: 20:6e:f1:6a:cf:b4
Uploading stub...
Running stub...
Stub running...
Configuring flash size...
Flash will be erased from 0x00000000 to 0x00005fff...
Compressed 20960 bytes to 13155...
Wrote 20960 bytes (13155 compressed) at 0x00000000 in 0.2 seconds (effective 963.6 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting via RTS pin...

Now you can go to your Arduino IDE, set your ESP chip in the board settings, select the correct serial port (in my case /dev/ttyACM0) and upload the blink sketch or something else.

I want to play around again with my CanGrow firmware, so I go and upload this:

$ cd ~/git/CanGrow/
$ TTY=/dev/ttyACM0 BOARD="esp32:esp32:makergo_c3_supermini" ./cangrow.sh upload
:: Build and upload firmware 0.2-dev5 a75ec71-esp32_esp32c3-20251028002101 to /dev/ttyACM0
:: Minimize and compress static webserver files
:: - cangrow.js has not changed
:: - cangrow.css has not changed
:: - index.html has not changed
Der Sketch verwendet 1394206 Bytes (70%) des Programmspeicherplatzes. Das Maximum sind 1966080 Bytes.
Globale Variablen verwenden 46968 Bytes (14%) des dynamischen Speichers, 280712 Bytes für lokale Variablen verbleiben. Das Maximum sind 327680 Bytes.
esptool v5.1.0
Connected to ESP32-C3 on /dev/ttyACM0:
Chip type:          ESP32-C3 (QFN32) (revision v0.4)
Features:           Wi-Fi, BT 5 (LE), Single Core, 160MHz, Embedded Flash 4MB (XMC)
Crystal frequency:  40MHz
USB mode:           USB-Serial/JTAG
MAC:                20:6e:f1:6a:cf:b4

Stub flasher running.
Changing baud rate to 921600...
Changed.

Configuring flash size...
Flash will be erased from 0x00000000 to 0x00004fff...
Flash will be erased from 0x00008000 to 0x00008fff...
Flash will be erased from 0x0000e000 to 0x0000ffff...
Flash will be erased from 0x00010000 to 0x00164fff...
Wrote 19632 bytes (12677 compressed) at 0x00000000 in 0.2 seconds (940.1 kbit/s).
Hash of data verified.
Wrote 3072 bytes (146 compressed) at 0x00008000 in 0.0 seconds (1022.5 kbit/s).
Hash of data verified.
Wrote 8192 bytes (47 compressed) at 0x0000e000 in 0.0 seconds (1361.9 kbit/s).
Hash of data verified.
Wrote 1394352 bytes (831414 compressed) at 0x00010000 in 4.9 seconds (2295.0 kbit/s).
Hash of data verified.

Hard resetting via RTS pin...

$ TTY=/dev/ttyACM0 BOARD="esp32:esp32:makergo_c3_supermini" ./cangrow.sh monitor
:: Open serial monitor /dev/ttyACM0
Porteinstellunegn für Monitor:
  baudrate=115200
  bits=8
  dtr=off
  parity=none
  rts=off
  stop_bits=1

Verbindung zu /dev/ttyACM0 wird hergestellt. Abbrechen mit STRG-C.
420
:: CanGrow firmware v0.2-dev5 build a75ec71-esp32_makergo_c3_supermini-20251028002344 starting ::
!: [SETUP] To format / factory reset LittleFS, pull GPIO 8  (PinWIPE) to 0 - NOW! (2 seconds left)
:: [LittleFS:Init]
:: [LittleFS:LoadConfig] loading config from: /config.json
!! [LittleFS:LoadConfig] FAILED to load config: /config.json
...

And done, the ESP32 C3 now works again:)