-
Notifications
You must be signed in to change notification settings - Fork 377
Open
Labels
Description
Bug description
It was observed on the ESP32-S3 that a software reset will not succeed if initiated while the CAN peripheral is actively attempting to transmit data without a connected receiver. The reset process is blocked at the transmit_async function call.
To Reproduce
- To create the project, run the following command:
esp-generate --chip esp32s3 writereset
- To use the master branch from GitHub, update the esp crate dependency in your Cargo.toml as follows. The current Cargo.toml content is:
[package]
edition = "2024"
name = "writereset"
rust-version = "1.88"
version = "0.1.0"
[[bin]]
name = "writereset"
path = "./src/bin/main.rs"
[dependencies]
esp-hal = { git = "https://github.com/esp-rs/esp-hal.git", features = [
"esp32s3",
"log-04",
"unstable",
] }
esp-rtos = { git = "https://github.com/esp-rs/esp-hal.git", features = [
"embassy",
"esp-alloc",
"esp32s3",
"log-04",
] }
esp-bootloader-esp-idf = { git = "https://github.com/esp-rs/esp-hal.git", features = [
"esp32s3",
"log-04",
] }
log = "0.4.27"
embassy-executor = { version = "0.9.1", features = ["log"] }
embassy-time = { version = "0.5.0", features = ["log"] }
embassy-futures = { version = "0.1.2", features = ["log"] }
embassy-sync = { version = "0.7.2", features = ["log"] }
esp-alloc = { git = "https://github.com/esp-rs/esp-hal.git" }
esp-println = { git = "https://github.com/esp-rs/esp-hal.git", features = [
"esp32s3",
"log-04",
] }
critical-section = "1.2.0"
static_cell = "2.1.1"
embedded-can = "0.4.1"
[profile.dev]
# Rust debug is too slow.
# For debug builds always builds with some optimization
opt-level = "s"
[profile.release]
codegen-units = 1 # LLVM can perform better optimizations using a single thread
debug = 2
debug-assertions = false
incremental = false
lto = 'fat'
opt-level = 's'
overflow-checks = false
- Shown below is the final structure of the project:
- The main.rs file is shown below:
#![no_std]
#![no_main]
#![deny(
clippy::mem_forget,
reason = "mem::forget is generally not safe to do with esp_hal types, especially those \
holding buffers for the duration of a data transfer."
)]
#![deny(clippy::large_stack_frames)]
use embassy_executor::Spawner;
use embassy_time::Timer;
use esp_hal::clock::CpuClock;
use esp_hal::interrupt::software::SoftwareInterruptControl;
use esp_hal::ram;
use esp_hal::timer::timg::TimerGroup;
use log::info;
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> ! {
loop {}
}
extern crate alloc;
// This creates a default app-descriptor required by the esp-idf bootloader.
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
esp_bootloader_esp_idf::esp_app_desc!();
#[allow(
clippy::large_stack_frames,
reason = "it's not unusual to allocate larger buffers etc. in main"
)]
#[esp_rtos::main]
async fn main(spawner: Spawner) -> ! {
// generator version: 1.1.0
esp_println::logger::init_logger_from_env();
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
let peripherals = esp_hal::init(config);
esp_alloc::heap_allocator!(#[ram(reclaimed)] size: 64 * 1024);
esp_alloc::heap_allocator!(size: 36 * 1024);
let timg0 = TimerGroup::new(peripherals.TIMG0);
let sw_int = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
esp_rtos::start(timg0.timer0, sw_int.software_interrupt0);
info!("Embassy initialized!");
let twai_config = esp_hal::twai::TwaiConfiguration::new(
peripherals.TWAI0,
peripherals.GPIO10,
peripherals.GPIO12,
esp_hal::twai::BaudRate::B250K,
esp_hal::twai::TwaiMode::Normal,
);
let _ = spawner.spawn(writereset::can::twai_can(twai_config));
let mut i = 0;
loop {
Timer::after_millis(1000).await;
writereset::can::send_message(2, [1, 2, 1, 1, 0, 0, 0, 0]).await;
i += 1;
info!("i = {}", i);
if i == 10 {
writereset::can::software_reset();
}
}
// for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v~1.0/examples
}
- The lib.rs file is shown below:
#![no_std]
pub mod can;
- The can.rs file is shown below:
use embassy_futures::select::Either3;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, signal::Signal};
use log::{error, info};
static MESSAGE_CHANNEL: embassy_sync::channel::Channel<CriticalSectionRawMutex, (u32, [u8; 8]), 8> =
embassy_sync::channel::Channel::new();
/// reset signal
static SIGNAL: Signal<CriticalSectionRawMutex, ()> = Signal::new();
#[embassy_executor::task]
pub async fn twai_can(twai_config: esp_hal::twai::TwaiConfiguration<'static, esp_hal::Blocking>) {
info!("init can bus");
let id = b"xxxxxxxxxxxxxxxxxxxxxxxxxxxx1";
let filter = esp_hal::twai::filter::SingleExtendedFilter::new(&id, b"x");
let mut twai_config = twai_config.into_async();
twai_config.set_filter(filter);
twai_config.set_error_warning_limit(1);
let twai = twai_config.start();
let (rx, tx) = twai.split();
match embassy_futures::select::select3(SIGNAL.wait(), twai_reader(rx), twai_writer(tx)).await {
Either3::First(_) => {}
Either3::Second(_) => {}
Either3::Third(_) => {}
}
info!("software reset");
embassy_time::Timer::after_secs(1).await;
esp_hal::system::software_reset();
}
async fn twai_reader(mut rx: esp_hal::twai::TwaiRx<'_, esp_hal::Async>) {
loop {
match rx.receive_async().await {
Ok(frame) => {
use embedded_can::Frame;
if !frame.is_data_frame() {
continue;
}
match frame.id() {
embedded_can::Id::Standard(id) => {
error!("standard id = {:?}", id);
}
embedded_can::Id::Extended(id) => {
info!("ext id = {:?}", id);
}
}
let data = frame.data();
let mut v = [0u8; 8];
let copy_len = core::cmp::min(data.len(), v.len());
v[..copy_len].copy_from_slice(&data[..copy_len]);
info!("msg = {:?}", v);
}
Err(err) => {
error!("err = {:?}", err);
}
}
}
}
async fn twai_writer(mut tx: esp_hal::twai::TwaiTx<'_, esp_hal::Async>) {
loop {
let (id, msg) = MESSAGE_CHANNEL.receive().await;
let Some(id) = esp_hal::twai::ExtendedId::new(id) else {
error!("ExtendedId::new fail");
continue;
};
let Some(frame) = esp_hal::twai::EspTwaiFrame::new(id, &msg) else {
error!("new frame fail");
continue;
};
info!("start transmit_async");
if let Err(err) = tx.transmit_async(&frame).await {
error!("transmit_async err = {:?}", err);
}
info!("end transmit_async");
}
}
pub async fn send_message(id: u32, msg: [u8; 8]) {
MESSAGE_CHANNEL.send((id, msg)).await;
}
pub fn software_reset() {
SIGNAL.signal(());
}
- After commenting out the following section in can.rs, the software_reset() function can be executed successfully.
if let Err(err) = tx.transmit_async(&frame).await {
error!("transmit_async err = {:?}", err);
}
- The log messages indicative of the issue are shown below:
[2025-12-21T00:50:23Z INFO ] Connecting...
[2025-12-21T00:50:24Z INFO ] Using flash stub
Chip type: esp32s3 (revision v0.2)
Crystal frequency: 40 MHz
Flash size: 4MB
Features: WiFi, BLE, Embedded Flash
MAC address: f0:9e:9e:43:99:3c
App/part. size: 145,072/4,128,768 bytes, 3.51%
[00:00:00] [========================================] 14/14 0x0 Skipped! (checksum matches) [00:00:00] [========================================] 1/1 0x8000 Skipped! (checksum matches)
[00:00:01] [========================================] 62/62 0x10000 Verifying... OK! [2025-12-21T00:50:25Z INFO ] Flashing has completed!
Commands:
CTRL+R Reset chip
CTRL+C Exit
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x29 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40378f0e
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fce2820,len:0x158c
load:0x403c8700,len:0xd24
load:0x403cb700,len:0x2f34
entry 0x403c8924
I (27) boot: ESP-IDF v5.5.1-838-gd66ebb86d2e 2nd stage bootloader
I (27) boot: compile time Nov 26 2025 12:27:56
I (27) boot: Multicore bootloader
I (29) boot: chip revision: v0.2
I (32) boot: efuse block revision: v1.3
I (35) boot.esp32s3: Boot SPI Speed : 40MHz
I (39) boot.esp32s3: SPI Mode : DIO
I (43) boot.esp32s3: SPI Flash Size : 4MB
I (47) boot: Enabling RNG early entropy source...
I (51) boot: Partition Table:
I (54) boot: ## Label Usage Type ST Offset Length
I (60) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (66) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (73) boot: 2 factory factory app 00 00 00010000 003f0000
I (80) boot: End of partition table
I (83) esp_image: segment 0: paddr=00010020 vaddr=3c000020 size=0c5d8h ( 50648) map
I (103) esp_image: segment 1: paddr=0001c600 vaddr=3fc89d10 size=022e8h ( 8936) load
I (106) esp_image: segment 2: paddr=0001e8f0 vaddr=40378000 size=01728h ( 5928) load
I (108) esp_image: segment 3: paddr=00020020 vaddr=42010020 size=1307ch ( 77948) map
I (133) esp_image: segment 4: paddr=000330a4 vaddr=40379728 size=005e8h ( 1512) load
I (135) boot: Loaded app from partition at offset 0x10000
I (136) boot: Disabling RNG early entropy source...
INFO - Embassy initialized!
INFO - init can bus
INFO - i = 1
INFO - start transmit_async
INFO - i = 2
INFO - i = 3
INFO - i = 4
INFO - i = 5
INFO - i = 6
INFO - i = 7
INFO - i = 8
INFO - i = 9
- After commenting out the transmission code, the program executed successfully. The log output is as follows:
Compiling writereset v0.1.0 (/home/chenjf/projects/writereset)
warning: unused variable: `tx`
--> src/can.rs:63:26
|
63 | async fn twai_writer(mut tx: esp_hal::twai::TwaiTx<'_, esp_hal::Async>) {
| ^^ help: if this is intentional, prefix it with an underscore: `_tx`
|
= note: `#[warn(unused_variables)]` on by default
warning: unused variable: `frame`
--> src/can.rs:70:18
|
70 | let Some(frame) = esp_hal::twai::EspTwaiFrame::new(id, &msg) else {
| ^^^^^ help: if this is intentional, prefix it with an underscore: `_frame`
warning: variable does not need to be mutable
--> src/can.rs:63:22
|
63 | async fn twai_writer(mut tx: esp_hal::twai::TwaiTx<'_, esp_hal::Async>) {
| ----^^
| |
| help: remove this `mut`
|
= note: `#[warn(unused_mut)]` on by default
warning: `writereset` (lib) generated 3 warnings (run `cargo fix --lib -p writereset` to apply 1 suggestion)
Finished `dev` profile [optimized + debuginfo] target(s) in 0.45s
Running `espflash flash --monitor --chip esp32s3 target/xtensa-esp32s3-none-elf/debug/writereset`
[2025-12-21T00:54:27Z INFO ] Serial port: '/dev/ttyACM0'
[2025-12-21T00:54:27Z INFO ] Connecting...
[2025-12-21T00:54:28Z INFO ] Using flash stub
Chip type: esp32s3 (revision v0.2)
Crystal frequency: 40 MHz
Flash size: 4MB
Features: WiFi, BLE, Embedded Flash
MAC address: f0:9e:9e:43:99:3c
App/part. size: 144,320/4,128,768 bytes, 3.50%
[00:00:00] [========================================] 14/14 0x0 Skipped! (checksum matches) [00:00:00] [========================================] 1/1 0x8000 Skipped! (checksum matches)
[00:00:01] [========================================] 62/62 0x10000 Verifying... OK! [2025-12-21T00:54:29Z INFO ] Flashing has completed!
Commands:
CTRL+R Reset chip
CTRL+C Exit
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x15 (USB_UART_CHIP_RESET),boot:0x29 (SPI_FAST_FLASH_BOOT)
Saved PC:0x40378eb7
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fce2820,len:0x158c
load:0x403c8700,len:0xd24
load:0x403cb700,len:0x2f34
entry 0x403c8924
I (27) boot: ESP-IDF v5.5.1-838-gd66ebb86d2e 2nd stage bootloader
I (27) boot: compile time Nov 26 2025 12:27:56
I (27) boot: Multicore bootloader
I (29) boot: chip revision: v0.2
I (32) boot: efuse block revision: v1.3
I (35) boot.esp32s3: Boot SPI Speed : 40MHz
I (39) boot.esp32s3: SPI Mode : DIO
I (43) boot.esp32s3: SPI Flash Size : 4MB
I (47) boot: Enabling RNG early entropy source...
I (51) boot: Partition Table:
I (54) boot: ## Label Usage Type ST Offset Length
I (60) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (66) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (73) boot: 2 factory factory app 00 00 00010000 003f0000
I (80) boot: End of partition table
I (83) esp_image: segment 0: paddr=00010020 vaddr=3c000020 size=0c550h ( 50512) map
I (103) esp_image: segment 1: paddr=0001c578 vaddr=3fc89d10 size=022f0h ( 8944) load
I (106) esp_image: segment 2: paddr=0001e870 vaddr=40378000 size=017a8h ( 6056) load
I (108) esp_image: segment 3: paddr=00020020 vaddr=42010020 size=12e0ch ( 77324) map
I (133) esp_image: segment 4: paddr=00032e34 vaddr=403797a8 size=00568h ( 1384) load
I (135) boot: Loaded app from partition at offset 0x10000
I (135) boot: Disabling RNG early entropy source...
INFO - Embassy initialized!
INFO - init can bus
INFO - i = 1
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 2
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 3
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 4
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 5
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 6
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 7
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 8
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 9
INFO - start transmit_async
INFO - end transmit_async
INFO - i = 10
INFO - software reset
INFO - i = 11
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x3 (RTC_SW_SYS_RST),boot:0x29 (SPI_FAST_FLASH_BOOT)
Saved PC:0x403795cb
SPIWP:0xee
mode:DIO, clock div:2
load:0x3fce2820,len:0x158c
load:0x403c8700,len:0xd24
load:0x403cb700,len:0x2f34
entry 0x403c8924
I (26) boot: ESP-IDF v5.5.1-838-gd66ebb86d2e 2nd stage bootloader
I (27) boot: compile time Nov 26 2025 12:27:56
I (27) boot: Multicore bootloader
I (28) boot: chip revision: v0.2
I (31) boot: efuse block revision: v1.3
I (35) boot.esp32s3: Boot SPI Speed : 40MHz
I (38) boot.esp32s3: SPI Mode : DIO
I (42) boot.esp32s3: SPI Flash Size : 4MB
I (46) boot: Enabling RNG early entropy source...
I (50) boot: Partition Table:
I (53) boot: ## Label Usage Type ST Offset Length
I (59) boot: 0 nvs WiFi data 01 02 00009000 00006000
I (66) boot: 1 phy_init RF data 01 01 0000f000 00001000
I (72) boot: 2 factory factory app 00 00 00010000 003f0000
I (79) boot: End of partition table
I (82) esp_image: segment 0: paddr=00010020 vaddr=3c000020 size=0c550h ( 50512) map
I (102) esp_image: segment 1: paddr=0001c578 vaddr=3fc89d10 size=022f0h ( 8944) load
I (105) esp_image: segment 2: paddr=0001e870 vaddr=40378000 size=017a8h ( 6056) load
I (108) esp_image: segment 3: paddr=00020020 vaddr=42010020 size=12e0ch ( 77324) map
I (132) esp_image: segment 4: paddr=00032e34 vaddr=403797a8 size=00568h ( 1384) load
I (135) boot: Loaded app from partition at offset 0x10000
I (135) boot: Disabling RNG early entropy source...
INFO - Embassy initialized!
Expected behavior
Regardless of the CAN bus configuration (transmitter-only with no receiver), a call to esp_hal::system::software_reset() is expected to succeed, not block at the transmit_async function.
Environment
- Target device: [e.g. ESP32-S3]
- Crate name and version: [e.g. esp-hal 1.0.0]
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Todo