Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add list-ports command to list available serial ports. (#761)
- [cargo-espflash]: Add `write-bin` subcommand (#789)
- Add `--monitor` option to `write-bin`. (#783)
- Add `watchdog-reset` strategy to `--after` subcommand (#779)

### Changed

Expand Down
39 changes: 20 additions & 19 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cargo-espflash/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
.or(config.partition_table.as_deref());

let mut flasher = connect(&args.connect_args, config, false, false)?;
let chip = flasher.chip();
let partition_table = match partition_table {
Some(path) => Some(parse_partition_table(path)?),
None => None,
Expand All @@ -274,7 +275,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
erase_partitions(&mut flasher, partition_table, Some(args.erase_parts), None)?;
flasher
.connection()
.reset_after(!args.connect_args.no_stub)?;
.reset_after(!args.connect_args.no_stub, chip)?;

Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions espflash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ required-features = ["cli", "serialport"]
[dependencies]
addr2line = { version = "0.24.2", optional = true }
base64 = "0.22.1"
bitflags = "2.9.0"
bytemuck = { version = "1.21.0", features = ["derive"] }
clap = { version = "4.5.24", features = ["derive", "env", "wrap_help"], optional = true }
clap_complete = { version = "4.5.41", optional = true }
Expand Down
3 changes: 2 additions & 1 deletion espflash/src/bin/espflash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
}

let mut flasher = connect(&args.connect_args, config, false, false)?;
let chip = flasher.chip();
let partition_table = match args.partition_table {
Some(path) => Some(parse_partition_table(&path)?),
None => None,
Expand All @@ -193,7 +194,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
erase_partitions(&mut flasher, partition_table, Some(args.erase_parts), None)?;
flasher
.connection()
.reset_after(!args.connect_args.no_stub)?;
.reset_after(!args.connect_args.no_stub, chip)?;

info!("Specified partitions successfully erased!");

Expand Down
7 changes: 5 additions & 2 deletions espflash/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,10 +723,12 @@ pub fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> {
let mut flasher = connect(&args.connect_args, config, true, true)?;
info!("Erasing Flash...");

let chip = flasher.chip();

flasher.erase_flash()?;
flasher
.connection()
.reset_after(!args.connect_args.no_stub)?;
.reset_after(!args.connect_args.no_stub, chip)?;

info!("Flash has been erased!");

Expand All @@ -747,6 +749,7 @@ pub fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> {
}

let mut flasher = connect(&args.connect_args, config, true, true)?;
let chip = flasher.chip();

info!(
"Erasing region at 0x{:08x} ({} bytes)",
Expand All @@ -756,7 +759,7 @@ pub fn erase_region(args: EraseRegionArgs, config: &Config) -> Result<()> {
flasher.erase_region(args.address, args.size)?;
flasher
.connection()
.reset_after(!args.connect_args.no_stub)?;
.reset_after(!args.connect_args.no_stub, chip)?;

Ok(())
}
Expand Down
59 changes: 56 additions & 3 deletions espflash/src/connection/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ use self::{
UsbJtagSerialReset,
},
};
use crate::error::{ConnectionError, Error, ResultExt, RomError, RomErrorKind};
use crate::{
error::{ConnectionError, Error, ResultExt, RomError, RomErrorKind},
targets::Chip,
};

pub(crate) mod command;
pub(crate) mod reset;
Expand Down Expand Up @@ -274,7 +277,7 @@ impl Connection {
}

// Reset the device taking into account the reset after argument
pub fn reset_after(&mut self, is_stub: bool) -> Result<(), Error> {
pub fn reset_after(&mut self, is_stub: bool, chip: Chip) -> Result<(), Error> {
let pid = self.usb_pid();

match self.after_operation {
Expand All @@ -289,12 +292,62 @@ impl Connection {
info!("Staying in flasher stub");
Ok(())
}
ResetAfterOperation::WatchdogReset => {
info!("Resetting device with watchdog");

match chip {
Chip::Esp32c3 => {
if self.is_using_usb_serial_jtag() {
chip.into_rtc_wdt_reset()?.rtc_wdt_reset(self)?;
}
}
Chip::Esp32p4 => {
// Check if the connection is USB OTG
if chip.into_usb_otg()?.is_using_usb_otg(self)? {
chip.into_rtc_wdt_reset()?.rtc_wdt_reset(self)?;
}
}
Chip::Esp32s2 => {
// Check if the connection is USB OTG
if chip.into_usb_otg()?.is_using_usb_otg(self)? {
let target = chip.into_rtc_wdt_reset()?;

// Check the strapping register to see if we can perform RTC WDT
// reset
if target.can_rtc_wdt_reset(self)? {
target.rtc_wdt_reset(self)?;
}
}
}
Chip::Esp32s3 => {
if self.is_using_usb_serial_jtag()
|| chip.into_usb_otg()?.is_using_usb_otg(self)?
{
let target = chip.into_rtc_wdt_reset()?;

// Check the strapping register to see if we can perform RTC WDT
// reset
if target.can_rtc_wdt_reset(self)? {
target.rtc_wdt_reset(self)?;
}
}
}
_ => {
return Err(Error::UnsupportedFeature {
chip,
feature: "watchdog reset".into(),
})
}
}

Ok(())
}
}
}

// Reset the device to flash mode
pub fn reset_to_flash(&mut self, extra_delay: bool) -> Result<(), Error> {
if self.port_info.pid == USB_SERIAL_JTAG_PID {
if self.is_using_usb_serial_jtag() {
UsbJtagSerialReset.reset(&mut self.serial)
} else {
#[cfg(unix)]
Expand Down
2 changes: 2 additions & 0 deletions espflash/src/connection/reset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,4 +362,6 @@ pub enum ResetAfterOperation {
NoReset,
/// Leaves the chip in the stub bootloader, no reset is performed.
NoResetNoStub,
/// Hard-resets the chip by triggering an internal watchdog reset.
WatchdogReset,
}
5 changes: 3 additions & 2 deletions espflash/src/flasher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "serialport")]
use serialport::UsbPortInfo;
use strum::{Display, EnumIter, IntoEnumIterator, VariantNames};
#[cfg(feature = "serialport")]
use xmas_elf::ElfFile;

#[cfg(feature = "serialport")]
Expand All @@ -31,7 +32,7 @@ use crate::{
Connection,
Port,
},
error::{ConnectionError, ResultExt},
error::{ConnectionError, ElfError, ResultExt as _},
flasher::stubs::{
FlashStub,
CHIP_DETECT_MAGIC_REG_ADDR,
Expand All @@ -41,8 +42,8 @@ use crate::{
image_format::{ram_segments, rom_segments, Segment},
};
use crate::{
error::{ElfError, Error},
targets::{Chip, XtalFrequency},
Error,
};

#[cfg(feature = "serialport")]
Expand Down
19 changes: 19 additions & 0 deletions espflash/src/targets/esp32c3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,22 @@ impl Target for Esp32c3 {
]
}
}

#[cfg(feature = "serialport")]
impl super::RtcWdtReset for Esp32c3 {
fn wdt_wprotect(&self) -> u32 {
0x6000_80A8
}

fn wdt_config0(&self) -> u32 {
0x6000_8090
}

fn wdt_config1(&self) -> u32 {
0x6000_8094
}

fn can_rtc_wdt_reset(&self, _connection: &mut Connection) -> Result<bool, Error> {
Ok(true)
}
}
Loading
Loading