fix(mesh): standalone erase_flash unsupported in --no-stub ROM mode
Real esptool output on a live Heltec V4 exposed the next layer of the --no-stub fix: "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 streams data), not a bulk full-chip-erase opcode — that's a stub-firmware-only feature, and Debian's esptool package ships without the stub (hence --no-stub in the first place). write_flash's own --erase-all flag gets the same "erase everything before writing" outcome our "always erase before write" default requires, but via the per-sector mechanism the ROM bootloader actually supports — one esptool invocation instead of a separate erase_flash + write_flash pair. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
76d14c3bf9
commit
0ca8f25b1b
@ -686,17 +686,27 @@ const ESPTOOL_CHIP: &str = "esp32s3";
|
|||||||
/// first hiccup, retry once at a conservative baud before giving up.
|
/// first hiccup, retry once at a conservative baud before giving up.
|
||||||
const ESPTOOL_FALLBACK_BAUD: &str = "115200";
|
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<FlashJob>) -> Result<()> {
|
async fn esptool_erase_and_write(path: &str, image: &Path, job: &Arc<FlashJob>) -> 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;
|
job.set_stage(FlashStage::Writing).await;
|
||||||
let image_str = image.to_string_lossy().to_string();
|
let image_str = image.to_string_lossy().to_string();
|
||||||
esptool_with_retry(path, &["write_flash", "0x0", &image_str], job)
|
esptool_with_retry(
|
||||||
.await
|
path,
|
||||||
.context("esptool write_flash failed")?;
|
&["write_flash", "--erase-all", "0x0", &image_str],
|
||||||
|
job,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("esptool write_flash failed")?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user