ESP8266-based web flasher for STM32 built-in ROM (System Memory) Bootloader over UART.
This library turns an ESP8266 into a standalone βbrowser flasherβ:
- Connect a target STM32 (UART + BOOT0 + NRST)
- Open a web UI in your browser
- Upload
update.binto ESP8266 LittleFS - Run bootloader commands (detect/connect, erase, program, jump to app)
- Browser-only workflow: upload + flash from any device on the same WiFi/LAN.
- Uses STM32 ROM bootloader USART protocol (ACK/NACK-based command frames).
- Embedded UI: firmware upload, control buttons, command log.
- mDNS access:
http://<mdns-host>.local/ - LittleFS storage: stores firmware file on ESP8266 (default
/update.bin). - Simple access control: username/password + session bound to client IP (LAN use).
- Supported: ESP8266 (Arduino core)
- ESP32: not supported as-is. It can be ported, but requires a separate implementation layer (different web server, mDNS, FS, and serial handling).
- ESP8266 TX β STM32 RX (cross)
- ESP8266 RX β STM32 TX (cross)
- GND β GND
- ESP8266 GPIO β STM32 BOOT0 (recommended with proper driver/level shifting)
- ESP8266 GPIO β STM32 NRST (recommended with proper driver/open-drain transistor)
- ESP8266 logic is 3.3V. Avoid direct 5V UART.
- Many STM32 boards need BOOT0 = 1 during reset to enter system bootloader.
- Many STM32 ROM bootloaders use 8E1 (8 data bits, even parity, 1 stop bit).
Put the library folder here (Windows): C:\Users\Documents\Arduino\libraries\STM32RomWebFlasher\
Inside it you should have:
STM32RomWebFlasher/
ββ library.properties
ββ examples/
ββ src/
- ZIP: Sketch β Include Library β Add .ZIP Libraryβ¦ (zip must contain the library root)
- Manual: copy the folder to
Documents/Arduino/libraries/ - Restart Arduino IDE after installing.
Create a sketch like this:
#include <STM32RomWebFlasher.h>
static const char* WIFI_SSID = "YOUR_SSID";
static const char* WIFI_PASS = "YOUR_PASS";
static const char* MDNS_HOST = "stm32flasher";
static const char* WEB_USER = "admin";
static const char* WEB_PASS = "admin";
STM32WebFlasherConfig cfg =
{
WIFI_SSID, // WiFi SSID
WIFI_PASS, // WiFi PASSWORD
MDNS_HOST, // Web Accessable Address http://MDNS_HOST.local
WEB_USER, // Webpage Login Username
WEB_PASS, // Webpage Login Password
80, // Port
D1, // STM32 Target BOOT0 Pin
D2, // STM32 Target Reset Pin
115200, // UART Baudrate
true, // UART Swap feature
1000, // Sync Timeout
"/update.bin" // Firmware Update Path
};
STM32WebFlasherESP8266 Flasher(Serial, cfg);
void setup()
{
if (!Flasher.begin())
{
while (true) delay(1000);
}
}
void loop()
{
Flasher.loop();
}- Via IP:
http://<esp-ip>/ - Via mDNS:
http://stm32flasher.local/
| Step | Description | Screenshot |
|---|---|---|
| 1 | Connection Page | |
| 2 | Login | ![]() |
| 3 | Main Control Panel | |
| 4 | Connect / Detect Target | |
| 5 | Device Information | |
| 6 | Logs / Error Handling | |
| 7 | Firmware Upload |
- Login
- Connect Target
- ESP8266 drives BOOT0/NRST and attempts ROM bootloader sync/detect
- Upload firmware
- Upload a
.binfile; it is saved to LittleFS as/update.bin
- Upload a
- Run commands
- Erase / Program / Full Update / Jump to App / Read Info
The UI sends: GET /cmd?c=<letter>
| Code | Button label | Meaning |
|---|---|---|
S |
Full Update | Erase + Program + Jump to app |
E |
Erase Only | Mass erase (if supported) |
U |
Program Only | Program /update.bin to flash |
J |
Reset to App | Exit bootloader / jump to user app |
G |
Read Chip ID | Reads device ID (implementation-dependent) |
R |
Bootloader Version | Reads ROM bootloader protocol version |
C |
Get Commands | Reads supported bootloader commands (implementation-dependent) |
T |
Test RAM Write | Writes a test block to RAM to verify link |
Returns the Login page or Main UI depending on session.
Body: user=<...>&pass=<...>
JSON:
{ "ok": true }{ "ok": false, "error": "..." }
Logs out and clears session.
Tries to enter ROM bootloader and detect target.
Exits bootloader / jumps to application.
JSON status (connected, hasFile, flashKB, devId, desc).
Multipart firmware upload β saved to LittleFS as /update.bin.
Runs command X.
Constructor:
STM32WebFlasherConfig(
const char* wifiSsid,
const char* wifiPass,
const char* mdnsHost,
const char* webUser,
const char* webPass,
uint16_t httpPort,
uint8_t boot0Pin,
uint8_t resetPin,
uint32_t uartBaud,
bool uartSwap,
uint32_t syncTimeoutMs,
const char* updatePath
);-
wifiSsid,wifiPass
Wi-Fi network credentials. -
mdnsHost
The.localmDNS host name (example:stm32flasherβstm32flasher.local). -
webUser,webPass
Web UI login credentials. -
httpPort
HTTP server port (usually80). -
boot0Pin
ESP GPIO pin connected to STM32 BOOT0 (controls boot mode). -
resetPin
ESP GPIO pin connected to STM32 NRST (controls reset). -
uartBaud
UART baud rate for STM32 ROM bootloader communication. -
uartSwap
ESP8266 UART pin swap enable/disable. -
syncTimeoutMs
Timeout for sync/ACK operations (milliseconds). -
updatePath
Firmware file path inside LittleFS (example:"/update.bin").
Constructor and main methods:
STM32WebFlasherESP8266(HardwareSerial& serial, const STM32WebFlasherConfig& cfg);
bool begin();
void loop();begin()configures WiFi, LittleFS, mDNS, web routes, and UART.loop()must be called continuously.
This is a protocol-level failure: the STM32 did not ACK the last expected step.
- BOOT0 not asserted correctly during reset
- NRST timing incorrect
- Wrong UART settings (many STM32 need 8E1 parity)
- TX/RX swapped or missing common GND
- Target not actually in system bootloader mode
- Baud mismatch (try
57600/38400)
- BOOT0 HIGH β pulse NRST β attempt sync
- Confirm correct STM32 bootloader UART pins for your MCU
- Confirm ESP UART config matches the bootloader (including parity)
- Validate hardware with STM32CubeProgrammer or
stm32flashfirst
-
STM32 ROM bootloader commands overview (ST Community):
https://community.st.com/t5/stm32-mcus/how-to-utilize-stm32-system-rom-bootloader-commands/ta-p/605286 -
AN3155 β USART protocol used in the STM32 bootloader (ST Application Note):
https://www.st.com/resource/en/application_note/an3155-usart-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf
