From d6d5e0c86b5de0e8b8bdd58befade2f056b58d24 Mon Sep 17 00:00:00 2001 From: onsdagens <112828711+onsdagens@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:28:40 +0200 Subject: [PATCH] Adding direct vector table hooking support for RISC-V's (#621) * direct vectoring support added * provide minimal handlers for hooking the vector table directly * changed direct vectoring interrupt enable interface to map to CPU interrupt * direct vectoring interrupt nesting * removed unused dependency * added tentative c2 and c6 support for direct vector table hooking * added direct vectoring examples * added direct vectoring examples * updated changelog * added direct vectoring to CI * Added H2 support and example, moved helpers to esp-hal-common * Added H2 direct vectoring example to CI * Removed remnants of removed feature * C6 and H2 examples fixed * C6 and H2 examples fixed * C6 and H2 examples fixed * Comment fixed * Added preemption flag to RT --------- Co-authored-by: Scott Mabin --- .github/workflows/ci.yml | 8 + CHANGELOG.md | 1 + esp-hal-common/Cargo.toml | 4 +- esp-hal-common/src/interrupt/riscv.rs | 74 ++++--- esp-riscv-rt/Cargo.toml | 4 +- esp-riscv-rt/src/lib.rs | 269 ++++++++++++++++++++++- esp32c2-hal/Cargo.toml | 5 + esp32c2-hal/examples/direct-vectoring.rs | 88 ++++++++ esp32c3-hal/Cargo.toml | 6 +- esp32c3-hal/examples/direct-vectoring.rs | 106 +++++++++ esp32c6-hal/Cargo.toml | 6 +- esp32c6-hal/examples/direct-vectoring.rs | 107 +++++++++ esp32h2-hal/Cargo.toml | 6 +- esp32h2-hal/examples/direct-vectoring.rs | 107 +++++++++ 14 files changed, 756 insertions(+), 35 deletions(-) create mode 100644 esp32c2-hal/examples/direct-vectoring.rs create mode 100644 esp32c3-hal/examples/direct-vectoring.rs create mode 100644 esp32c6-hal/examples/direct-vectoring.rs create mode 100644 esp32h2-hal/examples/direct-vectoring.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78a2a8b25..7f8e4f69d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,6 +133,8 @@ jobs: run: cd esp32c2-hal/ && cargo +nightly check --example=embassy_i2c --features=embassy,embassy-time-systick,async - name: check esp32c2-hal (interrupt-preemption) run: cd esp32c2-hal/ && cargo check --example=interrupt_preemption --features=interrupt-preemption + - name: check esp32c2-hal (direct-vectoring) + run: cd esp32c2-hal/ && cargo check --example=direct-vectoring --features=direct-vectoring # Ensure documentation can be built - name: rustdoc run: cd esp32c2-hal/ && cargo doc --features=eh1 @@ -177,6 +179,8 @@ jobs: run: cd esp32c3-hal/ && cargo +nightly check --example=embassy_i2c --features=embassy,embassy-time-systick,async - name: check esp32c3-hal (interrupt-preemption) run: cd esp32c3-hal/ && cargo check --example=interrupt_preemption --features=interrupt-preemption + - name: check esp32c3-hal (direct-vectoring) + run: cd esp32c3-hal/ && cargo check --example=direct-vectoring --features=direct-vectoring # Ensure documentation can be built - name: rustdoc run: cd esp32c3-hal/ && cargo doc --features=eh1 @@ -219,6 +223,8 @@ jobs: run: cd esp32c6-hal/ && cargo +nightly check --example=embassy_i2c --features=embassy,embassy-time-systick,async - name: check esp32c6-hal (interrupt-preemption) run: cd esp32c6-hal/ && cargo check --example=interrupt_preemption --features=interrupt-preemption + - name: check esp32c6-hal (direct-vectoring) + run: cd esp32c6-hal/ && cargo check --example=direct-vectoring --features=direct-vectoring # Ensure documentation can be built - name: rustdoc run: cd esp32c6-hal/ && cargo doc --features=eh1 @@ -261,6 +267,8 @@ jobs: run: cd esp32h2-hal/ && cargo +nightly check --example=embassy_i2c --features=embassy,embassy-time-systick,async - name: check esp32h2-hal (interrupt-preemption) run: cd esp32h2-hal/ && cargo check --example=interrupt_preemption --features=interrupt-preemption + - name: check esp32h2-hal (direct-vectoring) + run: cd esp32h2-hal/ && cargo check --example=direct-vectoring --features=direct-vectoring # Ensure documentation can be built - name: rustdoc run: cd esp32h2-hal/ && cargo doc --features=eh1 diff --git a/CHANGELOG.md b/CHANGELOG.md index ecec4ae5e..74b01e852 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add a new RMT driver (#653, #667, #695) - Implemented calibrated ADC API for ESP32-S3 (#641) - Add MCPWM DeadTime configuration (#406) +- Add feature enabling directly hooking the interrupt vector table - Implement sleep with some wakeup methods for `esp32-s3` (#660, #689, #696) ### Changed diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 15549cad5..c6683cf66 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -103,7 +103,8 @@ embassy = ["embassy-time"] embassy-time-systick = [] embassy-time-timg0 = [] -interrupt-preemption = [] +interrupt-preemption = ["esp-riscv-rt/interrupt-preemption"] + # Architecture-specific features (intended for internal use) riscv = ["critical-section/restore-state-u8", "esp-riscv-rt", "esp-riscv-rt/zero-bss", "riscv-atomic-emulation-trap"] @@ -114,6 +115,7 @@ rv-init-data = ["esp-riscv-rt/init-data", "esp-riscv-rt/init-rw-text"] rv-zero-rtc-bss = ["esp-riscv-rt/zero-rtc-fast-bss"] rv-init-rtc-data = ["esp-riscv-rt/init-rtc-fast-data", "esp-riscv-rt/init-rtc-fast-text"] +direct-vectoring = ["esp-riscv-rt/direct-vectoring"] # Enable the `impl-register-debug` feature for the selected PAC debug = [ "esp32?/impl-register-debug", diff --git a/esp-hal-common/src/interrupt/riscv.rs b/esp-hal-common/src/interrupt/riscv.rs index 8584df935..34013a894 100644 --- a/esp-hal-common/src/interrupt/riscv.rs +++ b/esp-hal-common/src/interrupt/riscv.rs @@ -69,8 +69,7 @@ pub enum InterruptKind { Edge, } -/// Enumeration of available CPU interrupts -/// +/// Enumeration of available CPU interrupts. /// It is possible to create a handler for each of the interrupts. (e.g. /// `interrupt3`) #[repr(u32)] @@ -198,6 +197,7 @@ mod vectored { /// /// Note that interrupts still need to be enabled globally for interrupts /// to be serviced. + #[cfg(not(feature = "direct-vectoring"))] pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> { if matches!(level, Priority::None) { return Err(Error::InvalidInterruptPriority); @@ -210,6 +210,30 @@ mod vectored { } Ok(()) } + /// Enables an interrupt at a given priority, maps it to the given CPU + /// interrupt and assigns the given priority. + /// + /// This can be side-effectful since no guarantees can be made about the + /// CPU interrupt not already being in use. + /// + /// Note that interrupts still need to be enabled globally for interrupts + /// to be serviced. + #[cfg(feature = "direct-vectoring")] + pub unsafe fn enable( + interrupt: Interrupt, + level: Priority, + cpu_interrupt: CpuInterrupt, + ) -> Result<(), Error> { + if matches!(level, Priority::None) { + return Err(Error::InvalidInterruptPriority); + } + unsafe { + map(crate::get_core(), interrupt, cpu_interrupt); + set_priority(crate::get_core(), cpu_interrupt, level); + enable_cpu_interrupt(cpu_interrupt); + } + Ok(()) + } #[ram] unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) { @@ -368,7 +392,7 @@ pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) { handle_exception(pc, trap_frame); } else { #[cfg(feature = "interrupt-preemption")] - let interrupt_priority = handle_priority(); + let interrupt_priority = _handle_priority(); let code = mcause::read().code(); match code { 1 => interrupt1(trap_frame.as_mut().unwrap()), @@ -405,7 +429,7 @@ pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) { _ => DefaultHandler(), }; #[cfg(feature = "interrupt-preemption")] - restore_priority(interrupt_priority); + _restore_priority(interrupt_priority); } } @@ -532,7 +556,7 @@ pub fn _setup_interrupts() { } } -/// Disable the given peripheral interrupt +/// Disable the given peripheral interrupt. pub fn disable(_core: Cpu, interrupt: Interrupt) { unsafe { let interrupt_number = interrupt as isize; @@ -578,7 +602,7 @@ pub fn get_status(_core: Cpu) -> u128 { } } -/// Assign a peripheral interrupt to an CPU interrupt +/// Assign a peripheral interrupt to an CPU interrupt. /// /// Great care must be taken when using the `vectored` feature (enabled by /// default). Avoid interrupts 1 - 15 when interrupt vectoring is enabled. @@ -672,7 +696,7 @@ mod classic { /// Get interrupt priority #[inline] - pub(super) unsafe fn get_priority(cpu_interrupt: CpuInterrupt) -> Priority { + pub(super) unsafe extern "C" fn get_priority(cpu_interrupt: CpuInterrupt) -> Priority { let intr = &*crate::peripherals::INTERRUPT_CORE0::PTR; let intr_prio_base = intr.cpu_int_pri_0.as_ptr(); @@ -681,11 +705,10 @@ mod classic { .read_volatile(); core::mem::transmute(prio as u8) } - #[cfg(all(feature = "interrupt-preemption"))] - use procmacros::ram; - #[cfg(all(feature = "interrupt-preemption"))] - #[ram] - pub(super) unsafe fn handle_priority() -> u32 { + #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] + #[no_mangle] + #[link_section = ".trap"] + pub(super) unsafe extern "C" fn _handle_priority() -> u32 { use super::mcause; use crate::riscv; let interrupt_id: usize = mcause::read().code(); // MSB is whether its exception or interrupt. @@ -707,9 +730,10 @@ mod classic { } prev_interrupt_priority } - #[cfg(all(feature = "interrupt-preemption"))] - #[ram] - pub(super) unsafe fn restore_priority(stored_prio: u32) { + #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] + #[no_mangle] + #[link_section = ".trap"] + pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) { use crate::riscv; unsafe { riscv::interrupt::disable(); @@ -739,7 +763,7 @@ mod plic { const PLIC_MXINT_TYPE_REG: u32 = DR_REG_PLIC_MX_BASE + 0x4; const PLIC_MXINT_CLEAR_REG: u32 = DR_REG_PLIC_MX_BASE + 0x8; const PLIC_MXINT0_PRI_REG: u32 = DR_REG_PLIC_MX_BASE + 0x10; - #[cfg(feature = "interrupt-preemption")] + #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] const PLIC_MXINT_THRESH_REG: u32 = DR_REG_PLIC_MX_BASE + 0x90; /// Enable a CPU interrupt pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) { @@ -797,7 +821,7 @@ mod plic { /// Get interrupt priority #[inline] - pub(super) unsafe fn get_priority(cpu_interrupt: CpuInterrupt) -> Priority { + pub(super) unsafe extern "C" fn get_priority(cpu_interrupt: CpuInterrupt) -> Priority { let plic_mxint_pri_ptr = PLIC_MXINT0_PRI_REG as *mut u32; let cpu_interrupt_number = cpu_interrupt as isize; @@ -806,11 +830,10 @@ mod plic { .read_volatile(); core::mem::transmute(prio as u8) } - #[cfg(all(feature = "interrupt-preemption"))] - use procmacros::ram; - #[cfg(all(feature = "interrupt-preemption"))] - #[ram] - pub(super) unsafe fn handle_priority() -> u32 { + #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] + #[no_mangle] + #[link_section = ".trap"] + pub(super) unsafe extern "C" fn _handle_priority() -> u32 { use super::mcause; use crate::riscv; let plic_mxint_pri_ptr = PLIC_MXINT0_PRI_REG as *mut u32; @@ -829,9 +852,10 @@ mod plic { } prev_interrupt_priority } - #[cfg(all(feature = "interrupt-preemption"))] - #[ram] - pub(super) unsafe fn restore_priority(stored_prio: u32) { + #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] + #[no_mangle] + #[link_section = ".trap"] + pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) { use crate::riscv; unsafe { riscv::interrupt::disable(); diff --git a/esp-riscv-rt/Cargo.toml b/esp-riscv-rt/Cargo.toml index 5960efc0b..d1fd1be18 100644 --- a/esp-riscv-rt/Cargo.toml +++ b/esp-riscv-rt/Cargo.toml @@ -17,10 +17,12 @@ riscv-rt-macros = "0.2.0" panic-halt = "0.2.0" [features] +direct-vectoring = [] +interrupt-preemption = [] has-mie-mip = [] zero-bss = [] zero-rtc-fast-bss = [] init-data = [] init-rw-text = [] init-rtc-fast-data = [] -init-rtc-fast-text = [] +init-rtc-fast-text = [] \ No newline at end of file diff --git a/esp-riscv-rt/src/lib.rs b/esp-riscv-rt/src/lib.rs index bfba0f0bc..bfd91ff2e 100644 --- a/esp-riscv-rt/src/lib.rs +++ b/esp-riscv-rt/src/lib.rs @@ -464,7 +464,167 @@ _abs_start: .weak _start_trap29 .weak _start_trap30 .weak _start_trap31 - +"#, +#[cfg(feature="direct-vectoring")] +r#" +_start_trap1: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_1_handler + j _start_trap_direct +_start_trap2: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_2_handler + j _start_trap_direct +_start_trap3: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_3_handler + j _start_trap_direct +_start_trap4: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_4_handler + j _start_trap_direct +_start_trap5: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_5_handler + j _start_trap_direct +_start_trap6: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_6_handler + j _start_trap_direct +_start_trap7: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_7_handler + j _start_trap_direct +_start_trap8: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_8_handler + j _start_trap_direct +_start_trap9: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_9_handler + j _start_trap_direct +_start_trap10: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_10_handler + j _start_trap_direct +_start_trap11: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_11_handler + j _start_trap_direct +_start_trap12: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_12_handler + j _start_trap_direct +_start_trap13: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_13_handler + j _start_trap_direct +_start_trap14: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_14_handler + j _start_trap_direct +_start_trap15: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_15_handler + j _start_trap_direct +_start_trap16: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_16_handler + j _start_trap_direct +_start_trap17: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_17_handler + j _start_trap_direct +_start_trap18: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_18_handler + j _start_trap_direct +_start_trap19: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_19_handler + j _start_trap_direct +_start_trap20: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_20_handler + j _start_trap_direct +_start_trap21: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_21_handler + j _start_trap_direct +_start_trap22: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_22_handler + j _start_trap_direct +_start_trap23: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_23_handler + j _start_trap_direct +_start_trap24: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_24_handler + j _start_trap_direct +_start_trap25: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_25_handler + j _start_trap_direct +_start_trap26: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_26_handler + j _start_trap_direct +_start_trap27: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_27_handler + j _start_trap_direct +_start_trap28: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_28_handler + j _start_trap_direct +_start_trap29: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_29_handler + j _start_trap_direct +_start_trap30: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_30_handler + j _start_trap_direct +_start_trap31: + addi sp, sp, -40*4 + sw ra, 0(sp) + la ra, cpu_int_31_handler + j _start_trap_direct +"#, +#[cfg(not(feature="direct-vectoring"))] +r#" _start_trap1: _start_trap2: _start_trap3: @@ -497,10 +657,17 @@ _start_trap29: _start_trap30: _start_trap31: -_start_trap: +"#, +r#" +_start_trap: addi sp, sp, -40*4 - - sw ra, 0*4(sp) + sw ra, 0*4(sp)"#, +#[cfg(feature="direct-vectoring")] //for the directly vectored handlers the above is stacked beforehand +r#" + la ra, _start_trap_rust_hal #this runs on exception, use regular fault handler +_start_trap_direct: +"#, +r#" sw t0, 1*4(sp) sw t1, 2*4(sp) sw t2, 3*4(sp) @@ -543,8 +710,31 @@ _start_trap: sw s0, 30*4(sp) add a0, sp, zero + "#, + #[cfg(all(feature="interrupt-preemption", feature="direct-vectoring"))] //store current priority, set threshold, enable interrupts + r#" + addi sp, sp, -4 #build stack + sw ra, 0(sp) + jal ra, _handle_priority + lw ra, 0(sp) + sw a0, 0(sp) #reuse old stack, a0 is return of _handle_priority + addi a0, sp, 4 #the proper stack pointer is an argument to the HAL handler + "#, + #[cfg(not(feature="direct-vectoring"))] //jump to HAL handler + r#" jal ra, _start_trap_rust_hal - + "#, + #[cfg(feature="direct-vectoring")] //jump to handler loaded in direct handler + r#" + jalr ra, ra #jump to label loaded in _start_trapx + "#, + #[cfg(all(feature="interrupt-preemption", feature="direct-vectoring"))] //restore threshold + r#" + lw a0, 0(sp) #load stored priority + jal ra, _restore_priority + addi sp, sp, 4 #pop + "#, + r#" lw t1, 31*4(sp) csrrw x0, mepc, t1 @@ -641,4 +831,73 @@ _vector_table: .option pop "#, +#[cfg(feature="direct-vectoring")] +r#" +#this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user. +.section .trap, "ax" +.weak cpu_int_1_handler +.weak cpu_int_2_handler +.weak cpu_int_3_handler +.weak cpu_int_4_handler +.weak cpu_int_5_handler +.weak cpu_int_6_handler +.weak cpu_int_7_handler +.weak cpu_int_8_handler +.weak cpu_int_9_handler +.weak cpu_int_10_handler +.weak cpu_int_11_handler +.weak cpu_int_12_handler +.weak cpu_int_13_handler +.weak cpu_int_14_handler +.weak cpu_int_15_handler +.weak cpu_int_16_handler +.weak cpu_int_17_handler +.weak cpu_int_18_handler +.weak cpu_int_19_handler +.weak cpu_int_20_handler +.weak cpu_int_21_handler +.weak cpu_int_22_handler +.weak cpu_int_23_handler +.weak cpu_int_24_handler +.weak cpu_int_25_handler +.weak cpu_int_26_handler +.weak cpu_int_27_handler +.weak cpu_int_28_handler +.weak cpu_int_29_handler +.weak cpu_int_30_handler +.weak cpu_int_31_handler +cpu_int_1_handler: +cpu_int_2_handler: +cpu_int_3_handler: +cpu_int_4_handler: +cpu_int_5_handler: +cpu_int_6_handler: +cpu_int_7_handler: +cpu_int_8_handler: +cpu_int_9_handler: +cpu_int_10_handler: +cpu_int_11_handler: +cpu_int_12_handler: +cpu_int_13_handler: +cpu_int_14_handler: +cpu_int_15_handler: +cpu_int_16_handler: +cpu_int_17_handler: +cpu_int_18_handler: +cpu_int_19_handler: +cpu_int_20_handler: +cpu_int_21_handler: +cpu_int_22_handler: +cpu_int_23_handler: +cpu_int_24_handler: +cpu_int_25_handler: +cpu_int_26_handler: +cpu_int_27_handler: +cpu_int_28_handler: +cpu_int_29_handler: +cpu_int_30_handler: +cpu_int_31_handler: + la ra, abort #abort since proper handler is not defined, this could also just load the default _start_trap_rust_hal address and let the hal handle it. + jr ra +"#, } diff --git a/esp32c2-hal/Cargo.toml b/esp32c2-hal/Cargo.toml index 0d3061524..f1ba1562c 100644 --- a/esp32c2-hal/Cargo.toml +++ b/esp32c2-hal/Cargo.toml @@ -59,6 +59,7 @@ embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tic xtal26mhz = ["esp-hal-common/esp32c2_26mhz"] xtal40mhz = ["esp-hal-common/esp32c2_40mhz"] interrupt-preemption = ["esp-hal-common/interrupt-preemption"] +direct-vectoring = ["esp-hal-common/direct-vectoring"] [[example]] name = "spi_eh1_loopback" @@ -91,3 +92,7 @@ required-features = ["embassy", "async"] [[example]] name = "embassy_i2c" required-features = ["embassy", "async"] + +[[example]] +name = "direct-vectoring" +required-features = ["direct-vectoring"] diff --git a/esp32c2-hal/examples/direct-vectoring.rs b/esp32c2-hal/examples/direct-vectoring.rs new file mode 100644 index 000000000..d3bb36bcb --- /dev/null +++ b/esp32c2-hal/examples/direct-vectoring.rs @@ -0,0 +1,88 @@ +#![no_main] +#![no_std] +#![feature(naked_functions)] +use core::{arch::asm, cell::RefCell}; + +use critical_section::Mutex; +use esp32c2_hal::{ + clock::ClockControl, + peripherals::Peripherals, + prelude::*, + system::{SoftwareInterrupt, SoftwareInterruptControl}, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; + +static SWINT: Mutex>> = Mutex::new(RefCell::new(None)); +#[entry] +unsafe fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.SYSTEM.split(); + let clockctrl = system.clock_control; + let sw_int = system.software_interrupt_control; + let clocks = ClockControl::boot_defaults(clockctrl).freeze(); + + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + + critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int)); + unsafe { + asm!( + " + csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 + csrrwi x0, 0x7e1, 0 #disable counter + csrrwi x0, 0x7e2, 0 #reset counter + " + ); + } + esp_println::println!("MPC:{}", unsafe { fetch_performance_timer() }); + // interrupt is raised from assembly for max timer granularity. + unsafe { + asm!( + " + li t0, 0x600C0028 #FROM_CPU_INTR0 address + li t1, 1 #Flip flag + csrrwi x0, 0x7e1, 1 #enable timer + sw t1, 0(t0) #trigger FROM_CPU_INTR0 + " + ) + } + esp_println::println!("Returned"); + loop {} +} + +#[no_mangle] +fn cpu_int_1_handler() { + unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") } + critical_section::with(|cs| { + SWINT + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .reset(SoftwareInterrupt::SoftwareInterrupt0); + }); + esp_println::println!("Performance counter:{}", unsafe { + fetch_performance_timer() + }); +} +#[naked] +unsafe extern "C" fn fetch_performance_timer() -> i32 { + asm!( + " + csrr a0, 0x7e2 + jr ra + ", + options(noreturn) + ); +} diff --git a/esp32c3-hal/Cargo.toml b/esp32c3-hal/Cargo.toml index c15436de3..d0337464d 100644 --- a/esp32c3-hal/Cargo.toml +++ b/esp32c3-hal/Cargo.toml @@ -64,7 +64,7 @@ embassy = ["esp-hal-common/embassy"] embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"] embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"] interrupt-preemption = ["esp-hal-common/interrupt-preemption"] - +direct-vectoring = ["esp-hal-common/direct-vectoring"] [profile.dev] opt-level = 1 @@ -102,3 +102,7 @@ required-features = ["embassy", "async"] [[example]] name = "embassy_i2c" required-features = ["embassy", "async"] + +[[example]] +name = "direct-vectoring" +required-features = ["direct-vectoring"] \ No newline at end of file diff --git a/esp32c3-hal/examples/direct-vectoring.rs b/esp32c3-hal/examples/direct-vectoring.rs new file mode 100644 index 000000000..05d6c6806 --- /dev/null +++ b/esp32c3-hal/examples/direct-vectoring.rs @@ -0,0 +1,106 @@ +#![no_main] +#![no_std] +#![feature(naked_functions)] +use core::{arch::asm, cell::RefCell}; + +use critical_section::Mutex; +use esp32c3_hal::{ + clock::ClockControl, + interrupt::{ + CpuInterrupt, + {self}, + }, + peripherals::{self, Peripherals}, + prelude::*, + system::{SoftwareInterrupt, SoftwareInterruptControl}, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; + +static SWINT: Mutex>> = Mutex::new(RefCell::new(None)); +#[entry] +unsafe fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.SYSTEM.split(); + let clockctrl = system.clock_control; + let sw_int = system.software_interrupt_control; + let clocks = ClockControl::boot_defaults(clockctrl).freeze(); + + // Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT, + // the RTC WDT, and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int)); + interrupt::enable( + peripherals::Interrupt::FROM_CPU_INTR0, + interrupt::Priority::Priority3, + CpuInterrupt::Interrupt1, + ) + .unwrap(); + unsafe { + asm!( + " + csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 + csrrwi x0, 0x7e1, 0 #disable counter + csrrwi x0, 0x7e2, 0 #reset counter + " + ); + } + esp_println::println!("MPC:{}", unsafe { fetch_performance_timer() }); + // interrupt is raised from assembly for max timer granularity. + unsafe { + asm!( + " + li t0, 0x600C0028 #FROM_CPU_INTR0 address + li t1, 1 #Flip flag + csrrwi x0, 0x7e1, 1 #enable timer + sw t1, 0(t0) #trigger FROM_CPU_INTR0 + " + ) + } + esp_println::println!("Returned"); + loop {} +} + +#[no_mangle] +fn cpu_int_1_handler() { + unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") } + critical_section::with(|cs| { + SWINT + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .reset(SoftwareInterrupt::SoftwareInterrupt0); + }); + esp_println::println!("Performance counter:{}", unsafe { + fetch_performance_timer() + }); +} +#[naked] +unsafe extern "C" fn fetch_performance_timer() -> i32 { + asm!( + " + csrr a0, 0x7e2 + jr ra + ", + options(noreturn) + ); +} diff --git a/esp32c6-hal/Cargo.toml b/esp32c6-hal/Cargo.toml index 1a3e28563..de4897368 100644 --- a/esp32c6-hal/Cargo.toml +++ b/esp32c6-hal/Cargo.toml @@ -64,7 +64,7 @@ embassy = ["esp-hal-common/embassy"] embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"] embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"] interrupt-preemption = ["esp-hal-common/interrupt-preemption"] - +direct-vectoring = ["esp-hal-common/direct-vectoring"] [[example]] name = "spi_eh1_loopback" required-features = ["eh1"] @@ -96,3 +96,7 @@ required-features = ["embassy", "async"] [[example]] name = "embassy_i2c" required-features = ["embassy", "async"] + +[[example]] +name = "direct-vectoring" +required-features = ["direct-vectoring"] diff --git a/esp32c6-hal/examples/direct-vectoring.rs b/esp32c6-hal/examples/direct-vectoring.rs new file mode 100644 index 000000000..ceb5cb9b6 --- /dev/null +++ b/esp32c6-hal/examples/direct-vectoring.rs @@ -0,0 +1,107 @@ +#![no_main] +#![no_std] +#![feature(naked_functions)] +use core::{arch::asm, cell::RefCell}; + +use critical_section::Mutex; +use esp32c6_hal::{ + clock::ClockControl, + interrupt::{ + CpuInterrupt, + {self}, + }, + peripherals::{self, Peripherals}, + prelude::*, + system::{SoftwareInterrupt, SoftwareInterruptControl}, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; + +static SWINT: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clockctrl = system.clock_control; + let sw_int = system.software_interrupt_control; + let clocks = ClockControl::boot_defaults(clockctrl).freeze(); + + // Disable the watchdog timers. For the ESP32-C6, this includes the Super WDT, + // the RTC WDT, and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int)); + unsafe { + interrupt::enable( + peripherals::Interrupt::FROM_CPU_INTR0, + interrupt::Priority::Priority3, + CpuInterrupt::Interrupt1, + ) + .unwrap(); + asm!( + " + csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 + csrrwi x0, 0x7e1, 0 #disable counter + csrrwi x0, 0x7e2, 0 #reset counter + " + ); + } + esp_println::println!("MPC:{}", unsafe { fetch_performance_timer() }); + // interrupt is raised from assembly for max timer granularity. + unsafe { + asm!( + " + li t0, 0x600C5090 #FROM_CPU_INTR0 address + li t1, 1 #Flip flag + csrrwi x0, 0x7e1, 1 #enable timer + sw t1, 0(t0) #trigger FROM_CPU_INTR0 + " + ) + } + esp_println::println!("Returned"); + loop {} +} + +#[no_mangle] +fn cpu_int_1_handler() { + unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") } + critical_section::with(|cs| { + SWINT + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .reset(SoftwareInterrupt::SoftwareInterrupt0); + }); + esp_println::println!("Performance counter:{}", unsafe { + fetch_performance_timer() + }); +} +#[naked] +unsafe extern "C" fn fetch_performance_timer() -> i32 { + asm!( + " + csrr a0, 0x7e2 + jr ra + ", + options(noreturn) + ); +} diff --git a/esp32h2-hal/Cargo.toml b/esp32h2-hal/Cargo.toml index e41cf5b8a..5221bd376 100644 --- a/esp32h2-hal/Cargo.toml +++ b/esp32h2-hal/Cargo.toml @@ -64,7 +64,7 @@ embassy = ["esp-hal-common/embassy"] embassy-time-systick = ["esp-hal-common/embassy-time-systick", "embassy-time/tick-hz-16_000_000"] embassy-time-timg0 = ["esp-hal-common/embassy-time-timg0", "embassy-time/tick-hz-1_000_000"] interrupt-preemption = ["esp-hal-common/interrupt-preemption"] - +direct-vectoring = ["esp-hal-common/direct-vectoring"] [[example]] name = "spi_eh1_loopback" required-features = ["eh1"] @@ -96,3 +96,7 @@ required-features = ["async", "embassy"] [[example]] name = "interrupt_preemption" required-features = ["interrupt-preemption"] + +[[example]] +name = "direct-vectoring" +required-features = ["direct-vectoring"] diff --git a/esp32h2-hal/examples/direct-vectoring.rs b/esp32h2-hal/examples/direct-vectoring.rs new file mode 100644 index 000000000..bb615d890 --- /dev/null +++ b/esp32h2-hal/examples/direct-vectoring.rs @@ -0,0 +1,107 @@ +#![no_main] +#![no_std] +#![feature(naked_functions)] +use core::{arch::asm, cell::RefCell}; + +use critical_section::Mutex; +use esp32h2_hal::{ + clock::ClockControl, + interrupt::{ + CpuInterrupt, + {self}, + }, + peripherals::{self, Peripherals}, + prelude::*, + system::{SoftwareInterrupt, SoftwareInterruptControl}, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; + +static SWINT: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clockctrl = system.clock_control; + let sw_int = system.software_interrupt_control; + let clocks = ClockControl::boot_defaults(clockctrl).freeze(); + + // Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT, + // the RTC WDT, and the TIMG WDTs. + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int)); + unsafe { + interrupt::enable( + peripherals::Interrupt::FROM_CPU_INTR0, + interrupt::Priority::Priority3, + CpuInterrupt::Interrupt1, + ) + .unwrap(); + asm!( + " + csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 + csrrwi x0, 0x7e1, 0 #disable counter + csrrwi x0, 0x7e2, 0 #reset counter + " + ); + } + esp_println::println!("MPC:{}", unsafe { fetch_performance_timer() }); + // interrupt is raised from assembly for max timer granularity. + unsafe { + asm!( + " + li t0, 0x600C5090 #FROM_CPU_INTR0 address + li t1, 1 #Flip flag + csrrwi x0, 0x7e1, 1 #enable timer + sw t1, 0(t0) #trigger FROM_CPU_INTR0 + " + ) + } + esp_println::println!("Returned"); + loop {} +} + +#[no_mangle] +fn cpu_int_1_handler() { + unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") } + critical_section::with(|cs| { + SWINT + .borrow_ref_mut(cs) + .as_mut() + .unwrap() + .reset(SoftwareInterrupt::SoftwareInterrupt0); + }); + esp_println::println!("Performance counter:{}", unsafe { + fetch_performance_timer() + }); +} +#[naked] +unsafe extern "C" fn fetch_performance_timer() -> i32 { + asm!( + " + csrr a0, 0x7e2 + jr ra + ", + options(noreturn) + ); +}