diff --git a/core/archipelago/src/mesh/flash.rs b/core/archipelago/src/mesh/flash.rs index 9b6b66a9..fc2f2931 100644 --- a/core/archipelago/src/mesh/flash.rs +++ b/core/archipelago/src/mesh/flash.rs @@ -686,17 +686,27 @@ const ESPTOOL_CHIP: &str = "esp32s3"; /// first hiccup, retry once at a conservative baud before giving up. const ESPTOOL_FALLBACK_BAUD: &str = "115200"; +/// A standalone `erase_flash` (full-chip erase via a single ROM opcode) does +/// NOT work with --no-stub — confirmed live 2026-07-23 against a real +/// Heltec V4: "A fatal error occurred: ESP32-S3 ROM does not support +/// function erase_flash." The ESP32-S3 ROM bootloader only implements +/// per-sector erase (used internally as write_flash goes), not a bulk +/// full-chip erase opcode — that's a stub-firmware-only feature, and +/// Debian's esptool package has no stub (see esptool_global_args' doc +/// comment). `write_flash --erase-all` gets the same "erase everything +/// first" outcome our "always erase before write" default requires, but via +/// the per-sector mechanism the ROM bootloader actually supports, as one +/// esptool invocation instead of two. async fn esptool_erase_and_write(path: &str, image: &Path, job: &Arc) -> Result<()> { - job.set_stage(FlashStage::Erasing).await; - esptool_with_retry(path, &["erase_flash"], job) - .await - .context("esptool erase_flash failed")?; - job.set_stage(FlashStage::Writing).await; let image_str = image.to_string_lossy().to_string(); - esptool_with_retry(path, &["write_flash", "0x0", &image_str], job) - .await - .context("esptool write_flash failed")?; + esptool_with_retry( + path, + &["write_flash", "--erase-all", "0x0", &image_str], + job, + ) + .await + .context("esptool write_flash failed")?; Ok(()) }