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 <scott@mabez.dev>
This commit is contained in:
onsdagens 2023-08-01 17:28:40 +02:00 committed by GitHub
parent 63e498f3e1
commit d6d5e0c86b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 756 additions and 35 deletions

View File

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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();

View File

@ -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 = []

View File

@ -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
"#,
}

View File

@ -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"]

View File

@ -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<RefCell<Option<SoftwareInterruptControl>>> = 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)
);
}

View File

@ -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"]

View File

@ -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<RefCell<Option<SoftwareInterruptControl>>> = 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)
);
}

View File

@ -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"]

View File

@ -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<RefCell<Option<SoftwareInterruptControl>>> = 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)
);
}

View File

@ -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"]

View File

@ -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<RefCell<Option<SoftwareInterruptControl>>> = 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)
);
}