Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Xtensa: Something goes wrong when inside an exception handler and trying to use RTT + probe-rs #2064

Open
bjoernQ opened this issue Sep 2, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@bjoernQ
Copy link
Contributor

bjoernQ commented Sep 2, 2024

Discovered in #2061

When using DEFMT + RTT + probe-rs the exception handler isn't able to produce any output. I get a message like WARN probe_rs::util::rtt::client: RTT control block corrupted (write pointer is 1006700828 while buffer size is 1024 for up channel 0 (defmt)), re-attaching as soon as the exception handler is trying to write to RTT. Tested at least on ESP32-S3 - most probably it's like that on all the Xtensas (needs to get checked)

This might have worked before

This works fine on RISC-V (tested on ESP32-C6)

@MabezDev MabezDev added the bug Something isn't working label Sep 2, 2024
@bjoernQ
Copy link
Contributor Author

bjoernQ commented Sep 2, 2024

Ok maybe it's not a real issue but just "bad luck" on my side.

This is the code triggering the problem for me

#![no_std]
#![no_main]

use defmt_rtt as _;
use esp_backtrace as _;

use esp_hal::{
    clock::ClockControl,
    delay::Delay,
    interrupt::{self},
    peripherals::{Interrupt, Peripherals, TIMG0},
    prelude::*,
    system::SystemControl,
    timer::timg::{Timer, Timer0, TimerGroup},
};

use core::cell::RefCell;
use critical_section::Mutex;

static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>, esp_hal::Blocking>>>> =
    Mutex::new(RefCell::new(None));

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();
    let system = SystemControl::new(peripherals.SYSTEM);

    let clocks = ClockControl::max(system.clock_control).freeze();
    let delay = Delay::new(&clocks);

    let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let timer0 = timg0.timer0;
    timer0.set_interrupt_handler(tg0_t0_level);

    interrupt::enable(
        Interrupt::TG0_T0_LEVEL,
        esp_hal::interrupt::Priority::Priority1,
    )
    .unwrap();
    timer0.load_value(500u64.millis()).unwrap();
    timer0.start();
    timer0.listen();

    critical_section::with(|cs| {
        TIMER0.borrow_ref_mut(cs).replace(timer0);
    });

    loop {
        defmt::info!("staying alive");
        delay.delay_millis(500);
    }
}

#[handler]
fn tg0_t0_level() {
    let x = (esp_hal::time::current_time()
        .duration_since_epoch()
        .to_millis() as f32
        / 2f32) as u32;

    defmt::info!("x = {}", x);

    critical_section::with(|cs| {
        let mut timer0 = TIMER0.borrow_ref_mut(cs);
        let timer0 = timer0.as_mut().unwrap();

        timer0.clear_interrupt();
        timer0.load_value(500u64.millis()).unwrap();
        timer0.start();
    });
}

However this does work as expected (i.e. showing the output of esp-backtrace)

#![no_std]
#![no_main]

use defmt_rtt as _;
use esp_backtrace as _;

use esp_hal::{
    clock::ClockControl,
    delay::Delay,
    interrupt::{self},
    peripherals::{Interrupt, Peripherals, TIMG0},
    prelude::*,
    system::SystemControl,
    timer::timg::{Timer, Timer0, TimerGroup},
};

use core::cell::RefCell;
use critical_section::Mutex;

static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>, esp_hal::Blocking>>>> =
    Mutex::new(RefCell::new(None));

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();
    let system = SystemControl::new(peripherals.SYSTEM);

    let clocks = ClockControl::max(system.clock_control).freeze();
    let delay = Delay::new(&clocks);

    let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
    let timer0 = timg0.timer0;
    timer0.set_interrupt_handler(tg0_t0_level);

    interrupt::enable(
        Interrupt::TG0_T0_LEVEL,
        esp_hal::interrupt::Priority::Priority1,
    )
    .unwrap();
    timer0.load_value(500u64.millis()).unwrap();
    timer0.start();
    timer0.listen();

    critical_section::with(|cs| {
        TIMER0.borrow_ref_mut(cs).replace(timer0);
    });

    loop {
        defmt::info!("staying alive");
        delay.delay_millis(500);
    }
}

#[handler]
fn tg0_t0_level() {
    let x = (esp_hal::time::current_time()
        .duration_since_epoch()
        .to_millis() as f32
        / 2f32) as u32;

    unsafe {
        static mut FOO: u32 = 0u32;
        core::ptr::addr_of_mut!(FOO).write_volatile(x);
    }

    critical_section::with(|cs| {
        let mut timer0 = TIMER0.borrow_ref_mut(cs);
        let timer0 = timer0.as_mut().unwrap();

        timer0.clear_interrupt();
        timer0.load_value(500u64.millis()).unwrap();
        timer0.start();
    });
}

@bugadani
Copy link
Contributor

bugadani commented Sep 2, 2024

@bjoernQ please include your Cargo.toml, too, the features may be interesting for repro.

@bjoernQ
Copy link
Contributor Author

bjoernQ commented Sep 2, 2024

Sure - just forgot that 😄

[package]
name = "cp0"
version = "0.1.0"
edition = "2021"

[dependencies]
esp-backtrace = { version = "0.14.0", default-features = false, features = [
    "esp32s3",
    "exception-handler",
    "panic-handler",
    "defmt",
]}

esp-hal = { version = "0.20.1", features = [
    "esp32s3",
] }
defmt            = "0.3.8"
defmt-rtt = "0.4.1"

critical-section = "1.1.3"

[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

[patch.crates-io]
esp-hal = { path = "/projects/esp/esp-hal/esp-hal" }
esp-backtrace = { path = "/projects/esp/esp-hal/esp-backtrace" }
esp-println = { path = "/projects/esp/esp-hal/esp-println" }
xtensa-lx-rt = { path = "/projects/esp/esp-hal/xtensa-lx-rt" }

@MabezDev
Copy link
Member

I suppose we should transfer this to probe-rs, unless there is something specific in the hal that's messing things up?

@bugadani
Copy link
Contributor

We may, but it's unclear where the issue is and I have a suspicion who'll take this up so it probably doesn't matter where this issue lives :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants