Flashing ESP32 with another ESP32
Posted: Mon Dec 01, 2025 1:37 pm
Hello,
i want to flash an ESP32-WROOM-32UE (Target) with another ESP32-WROOM-32UE (Host) over a serial connection (Serial1 Host).
I connected both with eachother like following:
Host | Target
----------------------
Rx1 | Tx0
Tx1 | Rx0
IO25 | En
IO26 | IO0 (Reset)
My programm works like following:
1. Set Target into bootloader mode with (EN and IO0) (Working)
2. Send SYNC to the bootloader (no response from Target)
3. Send FLASH_BEGIN
4. Sending FLASH_DATA
5. Send FLASH_END
I have the problem that the bootloader isn't answering to my SYNC-paket. I used the espressif dokumentation for communikation [https://docs.espressif.com/projects/esp ... tocol.html] with the bootloader and tried to adapt it into the Arduino IDE. I also checked the communication when im flashing an ESP32 with the Arduino IDE and it looks the same besides the checksum bytes are all "0x00". (I tried both checksum variants and both didn't work)
The SYNC-paket looks like this:
0xc0 0x0 0x8 0x24 0x0 0x20 0x0 0x0 0x0 0x7 0x7 0x12 0x20 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0xc0
i want to flash an ESP32-WROOM-32UE (Target) with another ESP32-WROOM-32UE (Host) over a serial connection (Serial1 Host).
I connected both with eachother like following:
Host | Target
----------------------
Rx1 | Tx0
Tx1 | Rx0
IO25 | En
IO26 | IO0 (Reset)
My programm works like following:
1. Set Target into bootloader mode with (EN and IO0) (Working)
2. Send SYNC to the bootloader (no response from Target)
3. Send FLASH_BEGIN
4. Sending FLASH_DATA
5. Send FLASH_END
I have the problem that the bootloader isn't answering to my SYNC-paket. I used the espressif dokumentation for communikation [https://docs.espressif.com/projects/esp ... tocol.html] with the bootloader and tried to adapt it into the Arduino IDE. I also checked the communication when im flashing an ESP32 with the Arduino IDE and it looks the same besides the checksum bytes are all "0x00". (I tried both checksum variants and both didn't work)
The SYNC-paket looks like this:
0xc0 0x0 0x8 0x24 0x0 0x20 0x0 0x0 0x0 0x7 0x7 0x12 0x20 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0x55 0xc0
Code: Select all
// --------- Konfiguration ---------
// Programmer UART → Target-ESP32
#define TX_PIN 17
#define RX_PIN 16
// Bootloder Pins
#define EN_PIN 25 // Reset Pin for Targets
#define GPIO0_PIN 26 // Bootloader Pin for Targets
// Firmware Dummy
#define FW_SIZE 4096
uint8_t firmware[FW_SIZE];
void setup()
{
Serial.begin(115200);
Serial1.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN);
pinMode(EN_PIN, OUTPUT);
pinMode(GPIO0_PIN, OUTPUT);
// Dummy-Firmware
for(int i=0;i<FW_SIZE;i++) firmware[i] = i & 0xFF;
Serial.println("ESP32 Programmer starting...");
//set Target into Bootloader-mode
enterBootloader();
//Bootloader SYNC
if(!ESPsync()) { Serial.println("SYNC failed"); return; }
//FLASH_BEGIN
if(!flashBegin(FW_SIZE, 0x10000)) { Serial.println("FLASH_BEGIN failed"); return; }
//FLASH_DATA
if(!flashData()) { Serial.println("FLASH_DATA failed"); return; }
//FLASH_END
if(!flashEnd()) { Serial.println("FLASH_END failed"); return; }
Serial.println("Flashing completed!");
}
void loop() {}
// -------------------------
// Bootloader-Modus
void enterBootloader() {
Serial.println("Setting Target into Bootloader mode...");
digitalWrite(GPIO0_PIN, LOW);
digitalWrite(EN_PIN, LOW);
delay(100);
digitalWrite(EN_PIN, HIGH);
delay(200);
digitalWrite(GPIO0_PIN, HIGH);
}
// -------------------------
//SYNC
bool ESPsync()
{
Serial.println("SYNC...");
const uint8_t payloadLen = 36;
uint8_t payload[payloadLen + 1]; //payload + 0xC0
// Checksum: 0xEF XOR Payload Bytes
uint32_t checksum = 0xEF;
for(int i=0;i<payloadLen;i++) checksum ^= payload[i];
//Header
uint8_t header[9];
header[0] = 0xc0;
header[1] = 0x00;
header[2] = 0x08; // SYNC command
header[3] = 0x24;
header[4] = 0x00;
header[5] = checksum;
header[6] = (checksum >> 8) & 0xFF;
header[7] = (checksum >> 16) & 0xFF;
header[8] = (checksum >> 24) & 0xFF;
// Payload: 0x07 0x07 0x12 0x20 + Padding 0x55 x 32
payload[0] = 0x07;
payload[1] = 0x07;
payload[2] = 0x12;
payload[3] = 0x20;
for(int i=4;i<payloadLen;i++) payload[i] = 0x55;
payload[payloadLen] = 0xc0; //End with 0xC0
// RX-Puffer clear
while(Serial1.available()) Serial.printf("Bootloader Message: %02X\n", Serial1.read());
Serial.println("Sending SYNC packets...");
// send SYNC 8x
for(int i=0;i<8;i++){
Serial1.write(header,9);
Serial1.write(payload,payloadLen+1);
Serial1.flush();
delay(50);
}
// wait 2 secounds for response
unsigned long t0 = millis();
while(millis()-t0 < 2000)
{
if(Serial1.available())
{
uint8_t b = Serial1.read();
Serial.print("Bootloader Rx: 0x"); //print incomming data to test for a response
Serial.println(b, HEX);
//return true; //ESP32 response to SYNC
}
}
return false;
}