mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 12:50:53 +00:00
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:
parent
63e498f3e1
commit
d6d5e0c86b
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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();
|
||||
|
@ -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 = []
|
@ -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
|
||||
"#,
|
||||
}
|
||||
|
@ -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"]
|
||||
|
88
esp32c2-hal/examples/direct-vectoring.rs
Normal file
88
esp32c2-hal/examples/direct-vectoring.rs
Normal 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)
|
||||
);
|
||||
}
|
@ -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"]
|
106
esp32c3-hal/examples/direct-vectoring.rs
Normal file
106
esp32c3-hal/examples/direct-vectoring.rs
Normal 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)
|
||||
);
|
||||
}
|
@ -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"]
|
||||
|
107
esp32c6-hal/examples/direct-vectoring.rs
Normal file
107
esp32c6-hal/examples/direct-vectoring.rs
Normal 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)
|
||||
);
|
||||
}
|
@ -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"]
|
||||
|
107
esp32h2-hal/examples/direct-vectoring.rs
Normal file
107
esp32h2-hal/examples/direct-vectoring.rs
Normal 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)
|
||||
);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user