Skip to content

Commit fa6b970

Browse files
Implement new USB Serial JTAG reset strategy (#779)
* Add watchdog reset experiment * changelog * Add bitflags dependency and cleanup * fix register values, ... again * Add P4 * reviews * move connection_is_usb_otg to Connection struct and rename it to is_using_usb_otg * fix ci * Use latest version of `bitflags` * Move and improve the `RtcWdtReset` trait * Introduce `UsbOtg` trait for targets * Fix some warnings * Cleanup --------- Co-authored-by: Jesse Braham <[email protected]>
1 parent ba14587 commit fa6b970

File tree

15 files changed

+310
-41
lines changed

15 files changed

+310
-41
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515
- Add list-ports command to list available serial ports. (#761)
1616
- [cargo-espflash]: Add `write-bin` subcommand (#789)
1717
- Add `--monitor` option to `write-bin`. (#783)
18+
- Add `watchdog-reset` strategy to `--after` subcommand (#779)
1819

1920
### Changed
2021

Cargo.lock

Lines changed: 20 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cargo-espflash/src/main.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
264264
.or(config.partition_table.as_deref());
265265

266266
let mut flasher = connect(&args.connect_args, config, false, false)?;
267+
let chip = flasher.chip();
267268
let partition_table = match partition_table {
268269
Some(path) => Some(parse_partition_table(path)?),
269270
None => None,
@@ -274,7 +275,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
274275
erase_partitions(&mut flasher, partition_table, Some(args.erase_parts), None)?;
275276
flasher
276277
.connection()
277-
.reset_after(!args.connect_args.no_stub)?;
278+
.reset_after(!args.connect_args.no_stub, chip)?;
278279

279280
Ok(())
280281
}

espflash/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ required-features = ["cli", "serialport"]
2727
[dependencies]
2828
addr2line = { version = "0.24.2", optional = true }
2929
base64 = "0.22.1"
30+
bitflags = "2.9.0"
3031
bytemuck = { version = "1.21.0", features = ["derive"] }
3132
clap = { version = "4.5.24", features = ["derive", "env", "wrap_help"], optional = true }
3233
clap_complete = { version = "4.5.41", optional = true }

espflash/src/bin/espflash.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
183183
}
184184

185185
let mut flasher = connect(&args.connect_args, config, false, false)?;
186+
let chip = flasher.chip();
186187
let partition_table = match args.partition_table {
187188
Some(path) => Some(parse_partition_table(&path)?),
188189
None => None,
@@ -193,7 +194,7 @@ pub fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
193194
erase_partitions(&mut flasher, partition_table, Some(args.erase_parts), None)?;
194195
flasher
195196
.connection()
196-
.reset_after(!args.connect_args.no_stub)?;
197+
.reset_after(!args.connect_args.no_stub, chip)?;
197198

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

espflash/src/cli/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,10 +723,12 @@ pub fn erase_flash(args: EraseFlashArgs, config: &Config) -> Result<()> {
723723
let mut flasher = connect(&args.connect_args, config, true, true)?;
724724
info!("Erasing Flash...");
725725

726+
let chip = flasher.chip();
727+
726728
flasher.erase_flash()?;
727729
flasher
728730
.connection()
729-
.reset_after(!args.connect_args.no_stub)?;
731+
.reset_after(!args.connect_args.no_stub, chip)?;
730732

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

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

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

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

761764
Ok(())
762765
}

espflash/src/connection/mod.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ use self::{
3333
UsbJtagSerialReset,
3434
},
3535
};
36-
use crate::error::{ConnectionError, Error, ResultExt, RomError, RomErrorKind};
36+
use crate::{
37+
error::{ConnectionError, Error, ResultExt, RomError, RomErrorKind},
38+
targets::Chip,
39+
};
3740

3841
pub(crate) mod command;
3942
pub(crate) mod reset;
@@ -274,7 +277,7 @@ impl Connection {
274277
}
275278

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

280283
match self.after_operation {
@@ -289,12 +292,62 @@ impl Connection {
289292
info!("Staying in flasher stub");
290293
Ok(())
291294
}
295+
ResetAfterOperation::WatchdogReset => {
296+
info!("Resetting device with watchdog");
297+
298+
match chip {
299+
Chip::Esp32c3 => {
300+
if self.is_using_usb_serial_jtag() {
301+
chip.into_rtc_wdt_reset()?.rtc_wdt_reset(self)?;
302+
}
303+
}
304+
Chip::Esp32p4 => {
305+
// Check if the connection is USB OTG
306+
if chip.into_usb_otg()?.is_using_usb_otg(self)? {
307+
chip.into_rtc_wdt_reset()?.rtc_wdt_reset(self)?;
308+
}
309+
}
310+
Chip::Esp32s2 => {
311+
// Check if the connection is USB OTG
312+
if chip.into_usb_otg()?.is_using_usb_otg(self)? {
313+
let target = chip.into_rtc_wdt_reset()?;
314+
315+
// Check the strapping register to see if we can perform RTC WDT
316+
// reset
317+
if target.can_rtc_wdt_reset(self)? {
318+
target.rtc_wdt_reset(self)?;
319+
}
320+
}
321+
}
322+
Chip::Esp32s3 => {
323+
if self.is_using_usb_serial_jtag()
324+
|| chip.into_usb_otg()?.is_using_usb_otg(self)?
325+
{
326+
let target = chip.into_rtc_wdt_reset()?;
327+
328+
// Check the strapping register to see if we can perform RTC WDT
329+
// reset
330+
if target.can_rtc_wdt_reset(self)? {
331+
target.rtc_wdt_reset(self)?;
332+
}
333+
}
334+
}
335+
_ => {
336+
return Err(Error::UnsupportedFeature {
337+
chip,
338+
feature: "watchdog reset".into(),
339+
})
340+
}
341+
}
342+
343+
Ok(())
344+
}
292345
}
293346
}
294347

295348
// Reset the device to flash mode
296349
pub fn reset_to_flash(&mut self, extra_delay: bool) -> Result<(), Error> {
297-
if self.port_info.pid == USB_SERIAL_JTAG_PID {
350+
if self.is_using_usb_serial_jtag() {
298351
UsbJtagSerialReset.reset(&mut self.serial)
299352
} else {
300353
#[cfg(unix)]

espflash/src/connection/reset.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,6 @@ pub enum ResetAfterOperation {
362362
NoReset,
363363
/// Leaves the chip in the stub bootloader, no reset is performed.
364364
NoResetNoStub,
365+
/// Hard-resets the chip by triggering an internal watchdog reset.
366+
WatchdogReset,
365367
}

espflash/src/flasher/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use serde::{Deserialize, Serialize};
1717
#[cfg(feature = "serialport")]
1818
use serialport::UsbPortInfo;
1919
use strum::{Display, EnumIter, IntoEnumIterator, VariantNames};
20+
#[cfg(feature = "serialport")]
2021
use xmas_elf::ElfFile;
2122

2223
#[cfg(feature = "serialport")]
@@ -31,7 +32,7 @@ use crate::{
3132
Connection,
3233
Port,
3334
},
34-
error::{ConnectionError, ResultExt},
35+
error::{ConnectionError, ElfError, ResultExt as _},
3536
flasher::stubs::{
3637
FlashStub,
3738
CHIP_DETECT_MAGIC_REG_ADDR,
@@ -41,8 +42,8 @@ use crate::{
4142
image_format::{ram_segments, rom_segments, Segment},
4243
};
4344
use crate::{
44-
error::{ElfError, Error},
4545
targets::{Chip, XtalFrequency},
46+
Error,
4647
};
4748

4849
#[cfg(feature = "serialport")]

espflash/src/targets/esp32c3.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,22 @@ impl Target for Esp32c3 {
114114
]
115115
}
116116
}
117+
118+
#[cfg(feature = "serialport")]
119+
impl super::RtcWdtReset for Esp32c3 {
120+
fn wdt_wprotect(&self) -> u32 {
121+
0x6000_80A8
122+
}
123+
124+
fn wdt_config0(&self) -> u32 {
125+
0x6000_8090
126+
}
127+
128+
fn wdt_config1(&self) -> u32 {
129+
0x6000_8094
130+
}
131+
132+
fn can_rtc_wdt_reset(&self, _connection: &mut Connection) -> Result<bool, Error> {
133+
Ok(true)
134+
}
135+
}

0 commit comments

Comments
 (0)