mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 14:44:42 +00:00
RISCV: remove the direct-vectoring
& interrupt-preemption
features and enable them by default (#1310)
* Remove the `direct-vectoring` feature * Enables the feature by default * renames the old direct_vectoring enable function `enable_direct` * Make enable_direct safe, move it out of vectored module * enable interrupt preemption by default for riscv * remove pub from cpu intr handlers * add enable_direct for Xtensa too * Fix flip-link feature * Fix up interrupt docs * changelog * fix clippy suggestions * Disable P4 workflow
This commit is contained in:
parent
1f155cf301
commit
a61ffef909
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -56,7 +56,7 @@ jobs:
|
|||||||
"esp32c3",
|
"esp32c3",
|
||||||
"esp32c6",
|
"esp32c6",
|
||||||
"esp32h2",
|
"esp32h2",
|
||||||
"esp32p4",
|
# "esp32p4",
|
||||||
# Xtensa devices:
|
# Xtensa devices:
|
||||||
"esp32",
|
"esp32",
|
||||||
"esp32s2",
|
"esp32s2",
|
||||||
@ -179,7 +179,7 @@ jobs:
|
|||||||
cargo xtask build-package --features=esp32c3 --target=riscv32imc-unknown-none-elf esp-hal
|
cargo xtask build-package --features=esp32c3 --target=riscv32imc-unknown-none-elf esp-hal
|
||||||
cargo xtask build-package --features=esp32c6 --target=riscv32imac-unknown-none-elf esp-hal
|
cargo xtask build-package --features=esp32c6 --target=riscv32imac-unknown-none-elf esp-hal
|
||||||
cargo xtask build-package --features=esp32h2 --target=riscv32imac-unknown-none-elf esp-hal
|
cargo xtask build-package --features=esp32h2 --target=riscv32imac-unknown-none-elf esp-hal
|
||||||
cargo xtask build-package --features=esp32p4 --target=riscv32imafc-unknown-none-elf esp-hal
|
# cargo xtask build-package --features=esp32p4 --target=riscv32imafc-unknown-none-elf esp-hal
|
||||||
- name: msrv (esp-lp-hal)
|
- name: msrv (esp-lp-hal)
|
||||||
run: |
|
run: |
|
||||||
cargo xtask build-package --features=esp32c6 --target=riscv32imac-unknown-none-elf esp-lp-hal
|
cargo xtask build-package --features=esp32c6 --target=riscv32imac-unknown-none-elf esp-lp-hal
|
||||||
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- ESP32-C6 / ESP32-H2: Implement `ETM` for general purpose timers (#1274)
|
- ESP32-C6 / ESP32-H2: Implement `ETM` for general purpose timers (#1274)
|
||||||
|
- `interrupt::enable` now has a direct CPU enable counter part, `interrupt::enable_direct` (#1310)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- Remove package-level type exports (#1275)
|
- Remove package-level type exports (#1275)
|
||||||
|
- Removed `direct-vectoring` & `interrupt-preemption` features, as they are now enabled by default (#1310)
|
||||||
|
|
||||||
## [0.16.1] - 2024-03-12
|
## [0.16.1] - 2024-03-12
|
||||||
|
|
||||||
|
@ -131,13 +131,9 @@ esp32s2 = ["dep:esp32s2", "xtensa", "portable-atomic/critical-section", "procmac
|
|||||||
esp32s3 = ["dep:esp32s3", "xtensa", "procmacros/has-ulp-core", "xtensa-lx/spin", "xtensa-lx-rt?/esp32s3", "usb-otg"]
|
esp32s3 = ["dep:esp32s3", "xtensa", "procmacros/has-ulp-core", "xtensa-lx/spin", "xtensa-lx-rt?/esp32s3", "usb-otg"]
|
||||||
|
|
||||||
#! ### RISC-V Exclusive Feature Flags
|
#! ### RISC-V Exclusive Feature Flags
|
||||||
## Enable direct interrupt vectoring.
|
|
||||||
direct-vectoring = ["esp-riscv-rt/direct-vectoring"]
|
|
||||||
## Move the stack to start of RAM to get zero-cost stack overflow protection
|
## Move the stack to start of RAM to get zero-cost stack overflow protection
|
||||||
## (ESP32-C6 and ESPS32-H2 only!).
|
## (ESP32-C6 and ESPS32-H2 only!).
|
||||||
flip-link = ["esp-riscv-rt/fix-sp"]
|
flip-link = ["esp-riscv-rt/fix-sp"]
|
||||||
## Enable interrupt preemption.
|
|
||||||
interrupt-preemption = ["esp-riscv-rt/interrupt-preemption"]
|
|
||||||
## Configuration for placing device drivers in the IRAM for faster access.
|
## Configuration for placing device drivers in the IRAM for faster access.
|
||||||
place-spi-driver-in-ram = []
|
place-spi-driver-in-ram = []
|
||||||
## Initialize the `.data` section of memory.
|
## Initialize the `.data` section of memory.
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use esp_metadata::{Arch, Chip, Config};
|
use esp_metadata::{Chip, Config};
|
||||||
|
|
||||||
// Macros taken from:
|
// Macros taken from:
|
||||||
// https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110
|
// https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110
|
||||||
@ -113,21 +113,13 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
panic!("The target does not support PSRAM");
|
panic!("The target does not support PSRAM");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't support "interrupt-preemption" and "direct-vectoring" on Xtensa and
|
|
||||||
// RISC-V with CLIC:
|
|
||||||
if (config.contains(&String::from("clic")) || config.arch() == Arch::Xtensa)
|
|
||||||
&& (cfg!(feature = "direct-vectoring") || cfg!(feature = "interrupt-preemption"))
|
|
||||||
{
|
|
||||||
panic!("The target does not support interrupt-preemption and direct-vectoring");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define all necessary configuration symbols for the configured device:
|
// Define all necessary configuration symbols for the configured device:
|
||||||
config.define_symbols();
|
config.define_symbols();
|
||||||
|
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut config_symbols = config.all();
|
let mut config_symbols = config.all();
|
||||||
#[cfg(feature = "flip-link")]
|
#[cfg(feature = "flip-link")]
|
||||||
config_symbols.push("flip-link");
|
config_symbols.push("flip-link".to_owned());
|
||||||
|
|
||||||
// Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these
|
// Place all linker scripts in `OUT_DIR`, and instruct Cargo how to find these
|
||||||
// files:
|
// files:
|
||||||
|
@ -42,12 +42,8 @@ macro_rules! from_cpu {
|
|||||||
panic!("FROM_CPU_{} is already used by a different executor.", $irq);
|
panic!("FROM_CPU_{} is already used by a different executor.", $irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsafe block because of direct-vectoring on riscv
|
|
||||||
#[allow(unused_unsafe)]
|
|
||||||
unsafe {
|
|
||||||
unwrap!(interrupt::enable(peripherals::Interrupt::[<FROM_CPU_INTR $irq>], priority));
|
unwrap!(interrupt::enable(peripherals::Interrupt::[<FROM_CPU_INTR $irq>], priority));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn number() -> usize {
|
fn number() -> usize {
|
||||||
$irq
|
$irq
|
||||||
|
@ -1,27 +1,18 @@
|
|||||||
//! # Interrupt support
|
//! # Interrupt support
|
||||||
//!
|
//!
|
||||||
//! ## Overview
|
//! Interrupt support functionality depends heavily on the features enabled.
|
||||||
//! The `interrupt` driver is a crucial module for ESP chips. Its primary
|
|
||||||
//! purpose is to manage and handle interrupts, which are asynchronous events
|
|
||||||
//! requiring immediate attention from the CPU. Interrupts are essential in
|
|
||||||
//! various applications, such as real-time tasks, I/O communications, and
|
|
||||||
//! handling external events like hardware signals.
|
|
||||||
//!
|
//!
|
||||||
//! The core functionality of the `interrupt` driver revolves around the
|
//! When the `vectored` feature is enabled, the
|
||||||
//! management of interrupts. When an interrupt occurs, it temporarily stops the
|
//! [`enable`] method will map interrupt to a CPU
|
||||||
//! ongoing CPU operations, saves its current state, and starts executing the
|
//! interrupt, and handle the `vector`ing to the peripheral interrupt, for
|
||||||
//! corresponding interrupt service routine (ISR). The interrupt service routine
|
//! example `UART0`.
|
||||||
//! is a user-defined function that performs the necessary actions to handle the
|
|
||||||
//! specific interrupt. Once the ISR is executed, the driver restores the saved
|
|
||||||
//! CPU state and resumes normal program execution.
|
|
||||||
//!
|
//!
|
||||||
//! In scenarios where multiple interrupts may occur simultaneously, the
|
//! It is also possible, but not recommended, to bind an interrupt directly to a
|
||||||
//! interrupt driver determines the `priority` of each interrupt. This
|
//! CPU interrupt. This can offer lower latency, at the cost of more complexity
|
||||||
//! prioritization ensures that critical or high-priority tasks are handled
|
//! in the interrupt handler.
|
||||||
//! first. It helps prevent delays in time-sensitive applications and allows the
|
|
||||||
//! system to allocate resources efficiently. This functionality is provided and
|
|
||||||
//! implemented by the `priority` enum.
|
|
||||||
//!
|
//!
|
||||||
|
//! The `vectored` reserves a number of CPU interrupts, which cannot be used see
|
||||||
|
//! [`RESERVED_INTERRUPTS`].
|
||||||
//!
|
//!
|
||||||
//! ## Example
|
//! ## Example
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
@ -30,12 +21,20 @@
|
|||||||
//! ...
|
//! ...
|
||||||
//! critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int));
|
//! critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int));
|
||||||
//!
|
//!
|
||||||
|
//! // enable the interrupt
|
||||||
//! interrupt::enable(
|
//! interrupt::enable(
|
||||||
//! peripherals::Interrupt::FROM_CPU_INTR0,
|
//! peripherals::Interrupt::FROM_CPU_INTR0,
|
||||||
//! interrupt::Priority::Priority1,
|
//! interrupt::Priority::Priority1,
|
||||||
//! )
|
//! )
|
||||||
//! .unwrap();
|
//! .unwrap();
|
||||||
//!
|
//!
|
||||||
|
//! // trigger the interrupt
|
||||||
|
//! SWINT
|
||||||
|
//! .borrow_ref_mut(cs)
|
||||||
|
//! .as_mut()
|
||||||
|
//! .unwrap()
|
||||||
|
//! .raise(SoftwareInterrupt::SoftwareInterrupt0);
|
||||||
|
//!
|
||||||
//! loop {}
|
//! loop {}
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
|
@ -29,6 +29,15 @@ use crate::{
|
|||||||
Cpu,
|
Cpu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Interrupt Error
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Error {
|
||||||
|
InvalidInterruptPriority,
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
CpuInterruptReserved,
|
||||||
|
}
|
||||||
|
|
||||||
/// Interrupt kind
|
/// Interrupt kind
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
pub enum InterruptKind {
|
pub enum InterruptKind {
|
||||||
@ -128,269 +137,7 @@ impl Priority {
|
|||||||
pub use vectored::*;
|
pub use vectored::*;
|
||||||
|
|
||||||
#[cfg(feature = "vectored")]
|
#[cfg(feature = "vectored")]
|
||||||
mod vectored {
|
pub const RESERVED_INTERRUPTS: &[usize] = INTERRUPT_TO_PRIORITY;
|
||||||
use procmacros::ram;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
// Setup interrupts ready for vectoring
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub(crate) unsafe fn init_vectoring() {
|
|
||||||
for (prio, num) in PRIORITY_TO_INTERRUPT.iter().enumerate() {
|
|
||||||
set_kind(
|
|
||||||
crate::get_core(),
|
|
||||||
core::mem::transmute(*num as u32),
|
|
||||||
InterruptKind::Level,
|
|
||||||
);
|
|
||||||
set_priority(
|
|
||||||
crate::get_core(),
|
|
||||||
core::mem::transmute(*num as u32),
|
|
||||||
core::mem::transmute((prio as u8) + 1),
|
|
||||||
);
|
|
||||||
enable_cpu_interrupt(core::mem::transmute(*num as u32));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the interrupts configured for the core
|
|
||||||
#[inline]
|
|
||||||
fn get_configured_interrupts(core: Cpu, mut status: u128) -> [u128; 16] {
|
|
||||||
unsafe {
|
|
||||||
let mut prios = [0u128; 16];
|
|
||||||
|
|
||||||
while status != 0 {
|
|
||||||
let interrupt_nr = status.trailing_zeros() as u16;
|
|
||||||
// safety: cast is safe because of repr(u16)
|
|
||||||
if let Some(cpu_interrupt) =
|
|
||||||
get_assigned_cpu_interrupt(core::mem::transmute(interrupt_nr))
|
|
||||||
{
|
|
||||||
let prio = get_priority_by_core(core, cpu_interrupt);
|
|
||||||
prios[prio as usize] |= 1 << (interrupt_nr as usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
status &= !(1u128 << interrupt_nr);
|
|
||||||
}
|
|
||||||
|
|
||||||
prios
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Interrupt Error
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum Error {
|
|
||||||
InvalidInterruptPriority,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enables a interrupt at a given priority
|
|
||||||
///
|
|
||||||
/// 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);
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
let cpu_interrupt =
|
|
||||||
core::mem::transmute(PRIORITY_TO_INTERRUPT[(level as usize) - 1] as u32);
|
|
||||||
map(crate::get_core(), interrupt, cpu_interrupt);
|
|
||||||
enable_cpu_interrupt(cpu_interrupt);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Bind the given interrupt to the given handler
|
|
||||||
pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn() -> ()) {
|
|
||||||
let ptr = &peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler as *const _
|
|
||||||
as *mut unsafe extern "C" fn() -> ();
|
|
||||||
ptr.write_volatile(handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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) {
|
|
||||||
let status = get_status(crate::get_core());
|
|
||||||
|
|
||||||
// this has no effect on level interrupts, but the interrupt may be an edge one
|
|
||||||
// so we clear it anyway
|
|
||||||
clear(crate::get_core(), cpu_intr);
|
|
||||||
|
|
||||||
let configured_interrupts = get_configured_interrupts(crate::get_core(), status);
|
|
||||||
let mut interrupt_mask =
|
|
||||||
status & configured_interrupts[INTERRUPT_TO_PRIORITY[cpu_intr as usize - 1]];
|
|
||||||
while interrupt_mask != 0 {
|
|
||||||
let interrupt_nr = interrupt_mask.trailing_zeros();
|
|
||||||
// Interrupt::try_from can fail if interrupt already de-asserted:
|
|
||||||
// silently ignore
|
|
||||||
if let Ok(interrupt) = peripherals::Interrupt::try_from(interrupt_nr as u8) {
|
|
||||||
handle_interrupt(interrupt, context)
|
|
||||||
}
|
|
||||||
interrupt_mask &= !(1u128 << interrupt_nr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[ram]
|
|
||||||
unsafe fn handle_interrupt(interrupt: Interrupt, save_frame: &mut TrapFrame) {
|
|
||||||
extern "C" {
|
|
||||||
// defined in each hal
|
|
||||||
fn EspDefaultHandler(interrupt: Interrupt);
|
|
||||||
}
|
|
||||||
|
|
||||||
let handler = peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler;
|
|
||||||
|
|
||||||
if core::ptr::eq(
|
|
||||||
handler as *const _,
|
|
||||||
EspDefaultHandler as *const unsafe extern "C" fn(),
|
|
||||||
) {
|
|
||||||
EspDefaultHandler(interrupt);
|
|
||||||
} else {
|
|
||||||
let handler: fn(&mut TrapFrame) = core::mem::transmute(handler);
|
|
||||||
handler(save_frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt1(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt1, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt2(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt2, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt3(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt3, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt4(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt4, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt5(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt5, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt6(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt6, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt7(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt7, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt8(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt8, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt9(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt9, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt10(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt10, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt11(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt11, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt12(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt12, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt13(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt13, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt14(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt14, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt15(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt15, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(plic)]
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt16(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt16, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(plic)]
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt17(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt17, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(plic)]
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt18(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt18, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(plic)]
|
|
||||||
#[no_mangle]
|
|
||||||
#[ram]
|
|
||||||
pub unsafe fn interrupt19(context: &mut TrapFrame) {
|
|
||||||
handle_interrupts(CpuInterrupt::Interrupt19, context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
@ -399,125 +146,14 @@ mod vectored {
|
|||||||
#[link_section = ".trap.rust"]
|
#[link_section = ".trap.rust"]
|
||||||
#[export_name = "_start_trap_rust_hal"]
|
#[export_name = "_start_trap_rust_hal"]
|
||||||
pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) {
|
pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) {
|
||||||
// User code shouldn't usually take the mutable TrapFrame or the TrapFrame in
|
assert!(
|
||||||
// general. However this makes things like preemtive multitasking easier in
|
mcause::read().is_exception(),
|
||||||
// future
|
"Arrived into _start_trap_rust_hal but mcause is not an exception!"
|
||||||
extern "C" {
|
);
|
||||||
fn interrupt1(frame: &mut TrapFrame);
|
|
||||||
fn interrupt2(frame: &mut TrapFrame);
|
|
||||||
fn interrupt3(frame: &mut TrapFrame);
|
|
||||||
fn interrupt4(frame: &mut TrapFrame);
|
|
||||||
fn interrupt5(frame: &mut TrapFrame);
|
|
||||||
fn interrupt6(frame: &mut TrapFrame);
|
|
||||||
fn interrupt7(frame: &mut TrapFrame);
|
|
||||||
fn interrupt8(frame: &mut TrapFrame);
|
|
||||||
fn interrupt9(frame: &mut TrapFrame);
|
|
||||||
fn interrupt10(frame: &mut TrapFrame);
|
|
||||||
fn interrupt11(frame: &mut TrapFrame);
|
|
||||||
fn interrupt12(frame: &mut TrapFrame);
|
|
||||||
fn interrupt13(frame: &mut TrapFrame);
|
|
||||||
fn interrupt14(frame: &mut TrapFrame);
|
|
||||||
fn interrupt15(frame: &mut TrapFrame);
|
|
||||||
fn interrupt16(frame: &mut TrapFrame);
|
|
||||||
fn interrupt17(frame: &mut TrapFrame);
|
|
||||||
fn interrupt18(frame: &mut TrapFrame);
|
|
||||||
fn interrupt19(frame: &mut TrapFrame);
|
|
||||||
fn interrupt20(frame: &mut TrapFrame);
|
|
||||||
fn interrupt21(frame: &mut TrapFrame);
|
|
||||||
fn interrupt22(frame: &mut TrapFrame);
|
|
||||||
fn interrupt23(frame: &mut TrapFrame);
|
|
||||||
fn interrupt24(frame: &mut TrapFrame);
|
|
||||||
fn interrupt25(frame: &mut TrapFrame);
|
|
||||||
fn interrupt26(frame: &mut TrapFrame);
|
|
||||||
fn interrupt27(frame: &mut TrapFrame);
|
|
||||||
fn interrupt28(frame: &mut TrapFrame);
|
|
||||||
fn interrupt29(frame: &mut TrapFrame);
|
|
||||||
fn interrupt30(frame: &mut TrapFrame);
|
|
||||||
fn interrupt31(frame: &mut TrapFrame);
|
|
||||||
|
|
||||||
// Defined in `esp-riscv-rt`
|
|
||||||
pub fn DefaultHandler();
|
|
||||||
}
|
|
||||||
|
|
||||||
let cause = mcause::read();
|
|
||||||
if cause.is_exception() {
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn ExceptionHandler(tf: *mut TrapFrame);
|
fn ExceptionHandler(tf: *mut TrapFrame);
|
||||||
}
|
}
|
||||||
ExceptionHandler(trap_frame);
|
ExceptionHandler(trap_frame);
|
||||||
} else {
|
|
||||||
#[cfg(feature = "interrupt-preemption")]
|
|
||||||
let interrupt_priority = _handle_priority();
|
|
||||||
|
|
||||||
let code = mcause::read().code();
|
|
||||||
|
|
||||||
// with CLIC the MCAUSE register changed
|
|
||||||
// 31: Interrupt flag (same as before)
|
|
||||||
//
|
|
||||||
// 30: MINHV: Used to indicate whether the processor is fetching the vector
|
|
||||||
// interrupt entry address. This bit will be set high when the processor
|
|
||||||
// responds to the vector interrupt. Cleared to 0 after successfully obtaining
|
|
||||||
// the vector interrupt service routine entry address
|
|
||||||
//
|
|
||||||
// 29-28: MPP: This bit is the mirror image of MSTATUS.MPP[1:0], that is,
|
|
||||||
// reading and writing MCAUSE.MPP will produce the same result as
|
|
||||||
// reading and writing MSTATUS.MPP.
|
|
||||||
//
|
|
||||||
// 27: MPIE: This bit mirrors MSTATUS.MPIE
|
|
||||||
//
|
|
||||||
// 23-16: MPIL: This bit saves the interrupt priority level before the
|
|
||||||
// processor enters the interrupt service routine, that is, the MINTSTATUS.MIL
|
|
||||||
// bit is copied to this bit. When executing the MRET instruction and returning
|
|
||||||
// from an interrupt, the processor copies the MPIL bit to the MIL bit in the
|
|
||||||
// MINTSTATUS register.
|
|
||||||
//
|
|
||||||
// 11-0: Exception code: When the processor is configured in CLIC mode, this
|
|
||||||
// bit field is expanded to 12 bits, supporting up to 4096 interrupt ID number
|
|
||||||
// records.
|
|
||||||
//
|
|
||||||
// So we need to mask out bits other than > 12. We currently only support
|
|
||||||
// external interrupts so we subtract EXTERNAL_INTERRUPT_OFFSET
|
|
||||||
#[cfg(clic)]
|
|
||||||
let code = (code & 0b1111_1111_1111) - EXTERNAL_INTERRUPT_OFFSET as usize;
|
|
||||||
|
|
||||||
match code {
|
|
||||||
1 => interrupt1(trap_frame.as_mut().unwrap()),
|
|
||||||
2 => interrupt2(trap_frame.as_mut().unwrap()),
|
|
||||||
3 => interrupt3(trap_frame.as_mut().unwrap()),
|
|
||||||
4 => interrupt4(trap_frame.as_mut().unwrap()),
|
|
||||||
5 => interrupt5(trap_frame.as_mut().unwrap()),
|
|
||||||
6 => interrupt6(trap_frame.as_mut().unwrap()),
|
|
||||||
7 => interrupt7(trap_frame.as_mut().unwrap()),
|
|
||||||
8 => interrupt8(trap_frame.as_mut().unwrap()),
|
|
||||||
9 => interrupt9(trap_frame.as_mut().unwrap()),
|
|
||||||
10 => interrupt10(trap_frame.as_mut().unwrap()),
|
|
||||||
11 => interrupt11(trap_frame.as_mut().unwrap()),
|
|
||||||
12 => interrupt12(trap_frame.as_mut().unwrap()),
|
|
||||||
13 => interrupt13(trap_frame.as_mut().unwrap()),
|
|
||||||
14 => interrupt14(trap_frame.as_mut().unwrap()),
|
|
||||||
15 => interrupt15(trap_frame.as_mut().unwrap()),
|
|
||||||
16 => interrupt16(trap_frame.as_mut().unwrap()),
|
|
||||||
17 => interrupt17(trap_frame.as_mut().unwrap()),
|
|
||||||
18 => interrupt18(trap_frame.as_mut().unwrap()),
|
|
||||||
19 => interrupt19(trap_frame.as_mut().unwrap()),
|
|
||||||
20 => interrupt20(trap_frame.as_mut().unwrap()),
|
|
||||||
21 => interrupt21(trap_frame.as_mut().unwrap()),
|
|
||||||
22 => interrupt22(trap_frame.as_mut().unwrap()),
|
|
||||||
23 => interrupt23(trap_frame.as_mut().unwrap()),
|
|
||||||
24 => interrupt24(trap_frame.as_mut().unwrap()),
|
|
||||||
25 => interrupt25(trap_frame.as_mut().unwrap()),
|
|
||||||
26 => interrupt26(trap_frame.as_mut().unwrap()),
|
|
||||||
27 => interrupt27(trap_frame.as_mut().unwrap()),
|
|
||||||
28 => interrupt28(trap_frame.as_mut().unwrap()),
|
|
||||||
29 => interrupt29(trap_frame.as_mut().unwrap()),
|
|
||||||
30 => interrupt30(trap_frame.as_mut().unwrap()),
|
|
||||||
31 => interrupt31(trap_frame.as_mut().unwrap()),
|
|
||||||
_ => DefaultHandler(),
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "interrupt-preemption")]
|
|
||||||
_restore_priority(interrupt_priority);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -554,6 +190,33 @@ pub fn _setup_interrupts() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enable an interrupt by directly binding it to a available CPU interrupt
|
||||||
|
///
|
||||||
|
/// Unless you are sure, you most likely want to use [`enable`] with the
|
||||||
|
/// `vectored` feature enabled instead.
|
||||||
|
///
|
||||||
|
/// When the `vectored` feature is enabled, trying using a reserved interrupt
|
||||||
|
/// from [`RESERVED_INTERRUPTS`] will return an error.
|
||||||
|
pub fn enable_direct(
|
||||||
|
interrupt: Interrupt,
|
||||||
|
level: Priority,
|
||||||
|
cpu_interrupt: CpuInterrupt,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
if RESERVED_INTERRUPTS.contains(&(cpu_interrupt as _)) {
|
||||||
|
return Err(Error::CpuInterruptReserved);
|
||||||
|
}
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Disable the given peripheral interrupt.
|
/// Disable the given peripheral interrupt.
|
||||||
pub fn disable(_core: Cpu, interrupt: Interrupt) {
|
pub fn disable(_core: Cpu, interrupt: Interrupt) {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -628,8 +291,9 @@ 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
|
/// Great care must be taken when using the `vectored` feature,
|
||||||
/// default). Avoid interrupts 1 - 15 when interrupt vectoring is enabled.
|
/// do not use CPU interrupts in the [`RESERVED_INTERRUPTS`] when
|
||||||
|
/// the `vectored` feature is enabled.
|
||||||
pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
|
pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
|
||||||
let interrupt_number = interrupt as isize;
|
let interrupt_number = interrupt as isize;
|
||||||
let cpu_interrupt_number = which as isize;
|
let cpu_interrupt_number = which as isize;
|
||||||
@ -660,6 +324,238 @@ unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option<CpuInterrup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
mod vectored {
|
||||||
|
use procmacros::ram;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
// Setup interrupts ready for vectoring
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub(crate) unsafe fn init_vectoring() {
|
||||||
|
for (prio, num) in PRIORITY_TO_INTERRUPT.iter().enumerate() {
|
||||||
|
set_kind(
|
||||||
|
crate::get_core(),
|
||||||
|
core::mem::transmute(*num as u32),
|
||||||
|
InterruptKind::Level,
|
||||||
|
);
|
||||||
|
set_priority(
|
||||||
|
crate::get_core(),
|
||||||
|
core::mem::transmute(*num as u32),
|
||||||
|
core::mem::transmute((prio as u8) + 1),
|
||||||
|
);
|
||||||
|
enable_cpu_interrupt(core::mem::transmute(*num as u32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the interrupts configured for the core
|
||||||
|
#[inline]
|
||||||
|
fn get_configured_interrupts(core: Cpu, mut status: u128) -> [u128; 16] {
|
||||||
|
unsafe {
|
||||||
|
let mut prios = [0u128; 16];
|
||||||
|
|
||||||
|
while status != 0 {
|
||||||
|
let interrupt_nr = status.trailing_zeros() as u16;
|
||||||
|
// safety: cast is safe because of repr(u16)
|
||||||
|
if let Some(cpu_interrupt) =
|
||||||
|
get_assigned_cpu_interrupt(core::mem::transmute(interrupt_nr))
|
||||||
|
{
|
||||||
|
let prio = get_priority_by_core(core, cpu_interrupt);
|
||||||
|
prios[prio as usize] |= 1 << (interrupt_nr as usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
status &= !(1u128 << interrupt_nr);
|
||||||
|
}
|
||||||
|
|
||||||
|
prios
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enables a interrupt at a given priority
|
||||||
|
///
|
||||||
|
/// Note that interrupts still need to be enabled globally for interrupts
|
||||||
|
/// to be serviced.
|
||||||
|
pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
|
||||||
|
if matches!(level, Priority::None) {
|
||||||
|
return Err(Error::InvalidInterruptPriority);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let cpu_interrupt =
|
||||||
|
core::mem::transmute(PRIORITY_TO_INTERRUPT[(level as usize) - 1] as u32);
|
||||||
|
map(crate::get_core(), interrupt, cpu_interrupt);
|
||||||
|
enable_cpu_interrupt(cpu_interrupt);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bind the given interrupt to the given handler
|
||||||
|
pub unsafe fn bind_interrupt(interrupt: Interrupt, handler: unsafe extern "C" fn() -> ()) {
|
||||||
|
let ptr = &peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler as *const _
|
||||||
|
as *mut unsafe extern "C" fn() -> ();
|
||||||
|
ptr.write_volatile(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ram]
|
||||||
|
unsafe fn handle_interrupts(cpu_intr: CpuInterrupt, context: &mut TrapFrame) {
|
||||||
|
let status = get_status(crate::get_core());
|
||||||
|
|
||||||
|
// this has no effect on level interrupts, but the interrupt may be an edge one
|
||||||
|
// so we clear it anyway
|
||||||
|
clear(crate::get_core(), cpu_intr);
|
||||||
|
|
||||||
|
let configured_interrupts = get_configured_interrupts(crate::get_core(), status);
|
||||||
|
let mut interrupt_mask =
|
||||||
|
status & configured_interrupts[INTERRUPT_TO_PRIORITY[cpu_intr as usize - 1]];
|
||||||
|
while interrupt_mask != 0 {
|
||||||
|
let interrupt_nr = interrupt_mask.trailing_zeros();
|
||||||
|
// Interrupt::try_from can fail if interrupt already de-asserted:
|
||||||
|
// silently ignore
|
||||||
|
if let Ok(interrupt) = peripherals::Interrupt::try_from(interrupt_nr as u8) {
|
||||||
|
handle_interrupt(interrupt, context)
|
||||||
|
}
|
||||||
|
interrupt_mask &= !(1u128 << interrupt_nr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ram]
|
||||||
|
unsafe fn handle_interrupt(interrupt: Interrupt, save_frame: &mut TrapFrame) {
|
||||||
|
extern "C" {
|
||||||
|
// defined in each hal
|
||||||
|
fn EspDefaultHandler(interrupt: Interrupt);
|
||||||
|
}
|
||||||
|
|
||||||
|
let handler = peripherals::__EXTERNAL_INTERRUPTS[interrupt as usize]._handler;
|
||||||
|
|
||||||
|
if core::ptr::eq(
|
||||||
|
handler as *const _,
|
||||||
|
EspDefaultHandler as *const unsafe extern "C" fn(),
|
||||||
|
) {
|
||||||
|
EspDefaultHandler(interrupt);
|
||||||
|
} else {
|
||||||
|
let handler: fn(&mut TrapFrame) = core::mem::transmute(handler);
|
||||||
|
handler(save_frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_1_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt1, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_2_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt2, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_3_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt3, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_4_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt4, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_5_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt5, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_6_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt6, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_7_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt7, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_8_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt8, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_9_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt9, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_10_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt10, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_11_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt11, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_12_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt12, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_13_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt13, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_14_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt14, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_15_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt15, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(plic)]
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_16_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt16, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(plic)]
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_17_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt17, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(plic)]
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_18_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt18, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(plic)]
|
||||||
|
#[no_mangle]
|
||||||
|
#[ram]
|
||||||
|
unsafe fn cpu_int_19_handler(context: &mut TrapFrame) {
|
||||||
|
handle_interrupts(CpuInterrupt::Interrupt19, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(any(plic, clic)))]
|
#[cfg(not(any(plic, clic)))]
|
||||||
mod classic {
|
mod classic {
|
||||||
use super::{CpuInterrupt, InterruptKind, Priority};
|
use super::{CpuInterrupt, InterruptKind, Priority};
|
||||||
@ -669,11 +565,11 @@ mod classic {
|
|||||||
|
|
||||||
pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 0;
|
pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 0;
|
||||||
|
|
||||||
pub(super) const PRIORITY_TO_INTERRUPT: [usize; 15] =
|
pub(super) const PRIORITY_TO_INTERRUPT: &[usize] =
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
|
||||||
pub(super) const INTERRUPT_TO_PRIORITY: [usize; 15] =
|
pub(super) const INTERRUPT_TO_PRIORITY: &[usize] =
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
|
||||||
/// Enable a CPU interrupt
|
/// Enable a CPU interrupt
|
||||||
pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
|
pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
|
||||||
@ -749,7 +645,6 @@ mod classic {
|
|||||||
.read_volatile();
|
.read_volatile();
|
||||||
core::mem::transmute(prio as u8)
|
core::mem::transmute(prio as u8)
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".trap"]
|
#[link_section = ".trap"]
|
||||||
pub(super) unsafe extern "C" fn _handle_priority() -> u32 {
|
pub(super) unsafe extern "C" fn _handle_priority() -> u32 {
|
||||||
@ -759,7 +654,7 @@ mod classic {
|
|||||||
let interrupt_priority = intr
|
let interrupt_priority = intr
|
||||||
.cpu_int_pri_0()
|
.cpu_int_pri_0()
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
.offset(interrupt_id as isize)
|
.add(interrupt_id)
|
||||||
.read_volatile();
|
.read_volatile();
|
||||||
|
|
||||||
let prev_interrupt_priority = intr.cpu_int_thresh().read().bits();
|
let prev_interrupt_priority = intr.cpu_int_thresh().read().bits();
|
||||||
@ -773,7 +668,6 @@ mod classic {
|
|||||||
}
|
}
|
||||||
prev_interrupt_priority
|
prev_interrupt_priority
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".trap"]
|
#[link_section = ".trap"]
|
||||||
pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) {
|
pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) {
|
||||||
@ -795,10 +689,10 @@ mod plic {
|
|||||||
// don't use interrupts reserved for CLIC (0,3,4,7)
|
// don't use interrupts reserved for CLIC (0,3,4,7)
|
||||||
// for some reason also CPU interrupt 8 doesn't work by default since it's
|
// for some reason also CPU interrupt 8 doesn't work by default since it's
|
||||||
// disabled after reset - so don't use that, too
|
// disabled after reset - so don't use that, too
|
||||||
pub(super) const PRIORITY_TO_INTERRUPT: [usize; 15] =
|
pub(super) const PRIORITY_TO_INTERRUPT: &[usize] =
|
||||||
[1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
|
&[1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
|
||||||
|
|
||||||
pub(super) const INTERRUPT_TO_PRIORITY: [usize; 19] = [
|
pub(super) const INTERRUPT_TO_PRIORITY: &[usize] = &[
|
||||||
1, 2, 0, 0, 3, 4, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
1, 2, 0, 0, 3, 4, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -807,7 +701,6 @@ mod plic {
|
|||||||
const PLIC_MXINT_TYPE_REG: u32 = DR_REG_PLIC_MX_BASE + 0x4;
|
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_MXINT_CLEAR_REG: u32 = DR_REG_PLIC_MX_BASE + 0x8;
|
||||||
const PLIC_MXINT0_PRI_REG: u32 = DR_REG_PLIC_MX_BASE + 0x10;
|
const PLIC_MXINT0_PRI_REG: u32 = DR_REG_PLIC_MX_BASE + 0x10;
|
||||||
#[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))]
|
|
||||||
const PLIC_MXINT_THRESH_REG: u32 = DR_REG_PLIC_MX_BASE + 0x90;
|
const PLIC_MXINT_THRESH_REG: u32 = DR_REG_PLIC_MX_BASE + 0x90;
|
||||||
/// Enable a CPU interrupt
|
/// Enable a CPU interrupt
|
||||||
pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
|
pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) {
|
||||||
@ -883,13 +776,12 @@ mod plic {
|
|||||||
.read_volatile();
|
.read_volatile();
|
||||||
core::mem::transmute(prio as u8)
|
core::mem::transmute(prio as u8)
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".trap"]
|
#[link_section = ".trap"]
|
||||||
pub(super) unsafe extern "C" fn _handle_priority() -> u32 {
|
pub(super) unsafe extern "C" fn _handle_priority() -> u32 {
|
||||||
use super::mcause;
|
use super::mcause;
|
||||||
let plic_mxint_pri_ptr = PLIC_MXINT0_PRI_REG as *mut u32;
|
let plic_mxint_pri_ptr = PLIC_MXINT0_PRI_REG as *mut u32;
|
||||||
let interrupt_id: isize = mcause::read().code().try_into().unwrap(); // MSB is whether its exception or interrupt.
|
let interrupt_id: isize = unwrap!(mcause::read().code().try_into()); // MSB is whether its exception or interrupt.
|
||||||
let interrupt_priority = plic_mxint_pri_ptr.offset(interrupt_id).read_volatile();
|
let interrupt_priority = plic_mxint_pri_ptr.offset(interrupt_id).read_volatile();
|
||||||
|
|
||||||
let thresh_reg = PLIC_MXINT_THRESH_REG as *mut u32;
|
let thresh_reg = PLIC_MXINT_THRESH_REG as *mut u32;
|
||||||
@ -904,7 +796,6 @@ mod plic {
|
|||||||
}
|
}
|
||||||
prev_interrupt_priority
|
prev_interrupt_priority
|
||||||
}
|
}
|
||||||
#[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))]
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[link_section = ".trap"]
|
#[link_section = ".trap"]
|
||||||
pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) {
|
pub(super) unsafe extern "C" fn _restore_priority(stored_prio: u32) {
|
||||||
@ -923,11 +814,11 @@ mod clic {
|
|||||||
|
|
||||||
pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 16;
|
pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 16;
|
||||||
|
|
||||||
pub(super) const PRIORITY_TO_INTERRUPT: [usize; 15] =
|
pub(super) const PRIORITY_TO_INTERRUPT: &[usize] =
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
|
||||||
pub(super) const INTERRUPT_TO_PRIORITY: [usize; 15] =
|
pub(super) const INTERRUPT_TO_PRIORITY: &[usize] =
|
||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
&[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
||||||
|
|
||||||
// The memory map for interrupt registers is on a per-core basis,
|
// The memory map for interrupt registers is on a per-core basis,
|
||||||
// base points to the current core interrupt register,
|
// base points to the current core interrupt register,
|
||||||
|
@ -9,6 +9,14 @@ use crate::{
|
|||||||
Cpu,
|
Cpu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum Error {
|
||||||
|
InvalidInterrupt,
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
CpuInterruptReserved,
|
||||||
|
}
|
||||||
|
|
||||||
/// Enumeration of available CPU interrupts
|
/// Enumeration of available CPU interrupts
|
||||||
///
|
///
|
||||||
/// It's possible to create one handler per priority level. (e.g
|
/// It's possible to create one handler per priority level. (e.g
|
||||||
@ -52,16 +60,41 @@ pub enum CpuInterrupt {
|
|||||||
Interrupt31EdgePriority5,
|
Interrupt31EdgePriority5,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const RESERVED_INTERRUPTS: &[usize] = &[
|
||||||
|
CpuInterrupt::Interrupt1LevelPriority1 as _,
|
||||||
|
CpuInterrupt::Interrupt19LevelPriority2 as _,
|
||||||
|
CpuInterrupt::Interrupt23LevelPriority3 as _,
|
||||||
|
CpuInterrupt::Interrupt10EdgePriority1 as _,
|
||||||
|
CpuInterrupt::Interrupt22EdgePriority3 as _,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Enable an interrupt by directly binding it to a available CPU interrupt
|
||||||
|
///
|
||||||
|
/// Unless you are sure, you most likely want to use [`enable`] with the
|
||||||
|
/// `vectored` feature enabled instead.
|
||||||
|
///
|
||||||
|
/// When the `vectored` feature is enabled, trying using a reserved interrupt
|
||||||
|
/// from [`RESERVED_INTERRUPTS`] will return an error.
|
||||||
|
pub fn enable_direct(interrupt: Interrupt, cpu_interrupt: CpuInterrupt) -> Result<(), Error> {
|
||||||
|
#[cfg(feature = "vectored")]
|
||||||
|
if RESERVED_INTERRUPTS.contains(&(cpu_interrupt as _)) {
|
||||||
|
return Err(Error::CpuInterruptReserved);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
map(crate::get_core(), interrupt, cpu_interrupt);
|
||||||
|
|
||||||
|
xtensa_lx::interrupt::enable_mask(
|
||||||
|
xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Assign a peripheral interrupt to an CPU interrupt
|
/// Assign a peripheral interrupt to an CPU interrupt
|
||||||
///
|
///
|
||||||
/// Great care **must** be taken when using this function with interrupt
|
/// Great care **must** be taken when using this function with interrupt
|
||||||
/// vectoring (enabled by default). Avoid the following CPU interrupts:
|
/// vectoring (enabled by default). Avoid the interrupts listed in
|
||||||
/// - Interrupt1LevelPriority1
|
/// [`RESERVED_INTERRUPTS`] as they are preallocated for interrupt vectoring.
|
||||||
/// - Interrupt19LevelPriority2
|
|
||||||
/// - Interrupt23LevelPriority3
|
|
||||||
/// - Interrupt10EdgePriority1
|
|
||||||
/// - Interrupt22EdgePriority3
|
|
||||||
/// As they are preallocated for interrupt vectoring.
|
|
||||||
///
|
///
|
||||||
/// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt
|
/// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt
|
||||||
/// still needs to be enabled afterwards
|
/// still needs to be enabled afterwards
|
||||||
@ -196,12 +229,6 @@ mod vectored {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::get_core;
|
use crate::get_core;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
|
||||||
pub enum Error {
|
|
||||||
InvalidInterrupt,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Interrupt priority levels.
|
/// Interrupt priority levels.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
@ -35,22 +35,14 @@ zero-bss = []
|
|||||||
## Zero the `.rtc_fast.bss` section.
|
## Zero the `.rtc_fast.bss` section.
|
||||||
zero-rtc-fast-bss = []
|
zero-rtc-fast-bss = []
|
||||||
|
|
||||||
#! ### Interrupt Feature Flags
|
|
||||||
## Enable direct interrupt vectoring.
|
|
||||||
direct-vectoring = []
|
|
||||||
## Enable interrupt preemption.
|
|
||||||
interrupt-preemption = []
|
|
||||||
|
|
||||||
# This feature is intended for testing; you probably don't want to enable it:
|
# This feature is intended for testing; you probably don't want to enable it:
|
||||||
ci = [
|
ci = [
|
||||||
"direct-vectoring",
|
|
||||||
"fix-sp",
|
"fix-sp",
|
||||||
"has-mie-mip",
|
"has-mie-mip",
|
||||||
"init-data",
|
"init-data",
|
||||||
"init-rtc-fast-data",
|
"init-rtc-fast-data",
|
||||||
"init-rtc-fast-text",
|
"init-rtc-fast-text",
|
||||||
"init-rw-text",
|
"init-rw-text",
|
||||||
"interrupt-preemption",
|
|
||||||
"zero-bss",
|
"zero-bss",
|
||||||
"zero-rtc-fast-bss",
|
"zero-rtc-fast-bss",
|
||||||
]
|
]
|
||||||
|
@ -442,7 +442,7 @@ _abs_start:
|
|||||||
_start_trap_rust, then restores all saved registers before `mret`
|
_start_trap_rust, then restores all saved registers before `mret`
|
||||||
*/
|
*/
|
||||||
.section .trap, "ax"
|
.section .trap, "ax"
|
||||||
.weak _start_trap
|
.weak _start_trap /* Exceptions call into _start_trap in vectored mode */
|
||||||
.weak _start_trap1
|
.weak _start_trap1
|
||||||
.weak _start_trap2
|
.weak _start_trap2
|
||||||
.weak _start_trap3
|
.weak _start_trap3
|
||||||
@ -475,8 +475,40 @@ _abs_start:
|
|||||||
.weak _start_trap30
|
.weak _start_trap30
|
||||||
.weak _start_trap31
|
.weak _start_trap31
|
||||||
"#,
|
"#,
|
||||||
#[cfg(feature="direct-vectoring")]
|
|
||||||
r#"
|
r#"
|
||||||
|
_start_trap: // Handle exceptions in vectored mode
|
||||||
|
"#,
|
||||||
|
#[cfg(feature="fix-sp")]
|
||||||
|
r#"
|
||||||
|
// move SP to some save place if it's pointing below the RAM
|
||||||
|
// otherwise we won't be able to do anything reasonable
|
||||||
|
// (since we don't have a working stack)
|
||||||
|
//
|
||||||
|
// most probably we will just print something and halt in this case
|
||||||
|
// we actually can't do anything else
|
||||||
|
csrw mscratch, t0
|
||||||
|
la t0, _stack_end
|
||||||
|
bge sp, t0, 1f
|
||||||
|
|
||||||
|
// use the reserved exception cause 14 to signal we detected a stack overflow
|
||||||
|
li t0, 14
|
||||||
|
csrw mcause, t0
|
||||||
|
|
||||||
|
// set SP to the start of the stack
|
||||||
|
la sp, _stack_start
|
||||||
|
li t0, 4 // make sure stack start is in RAM
|
||||||
|
sub sp, sp, t0
|
||||||
|
andi sp, sp, -16 // Force 16-byte alignment
|
||||||
|
|
||||||
|
1:
|
||||||
|
csrr t0, mscratch
|
||||||
|
// now SP is in RAM - continue
|
||||||
|
"#,
|
||||||
|
r#"
|
||||||
|
addi sp, sp, -40*4
|
||||||
|
sw ra, 0(sp)
|
||||||
|
la ra, _start_trap_rust_hal /* Load the HAL trap handler */
|
||||||
|
j _start_trap_direct
|
||||||
_start_trap1:
|
_start_trap1:
|
||||||
addi sp, sp, -40*4
|
addi sp, sp, -40*4
|
||||||
sw ra, 0(sp)
|
sw ra, 0(sp)
|
||||||
@ -632,77 +664,7 @@ _start_trap31:
|
|||||||
sw ra, 0(sp)
|
sw ra, 0(sp)
|
||||||
la ra, cpu_int_31_handler
|
la ra, cpu_int_31_handler
|
||||||
j _start_trap_direct
|
j _start_trap_direct
|
||||||
"#,
|
la ra, _start_trap_rust_hal /* this runs on exception, use regular fault handler */
|
||||||
#[cfg(not(feature="direct-vectoring"))]
|
|
||||||
r#"
|
|
||||||
_start_trap1:
|
|
||||||
_start_trap2:
|
|
||||||
_start_trap3:
|
|
||||||
_start_trap4:
|
|
||||||
_start_trap5:
|
|
||||||
_start_trap6:
|
|
||||||
_start_trap7:
|
|
||||||
_start_trap8:
|
|
||||||
_start_trap9:
|
|
||||||
_start_trap10:
|
|
||||||
_start_trap11:
|
|
||||||
_start_trap12:
|
|
||||||
_start_trap13:
|
|
||||||
_start_trap14:
|
|
||||||
_start_trap15:
|
|
||||||
_start_trap16:
|
|
||||||
_start_trap17:
|
|
||||||
_start_trap18:
|
|
||||||
_start_trap19:
|
|
||||||
_start_trap20:
|
|
||||||
_start_trap21:
|
|
||||||
_start_trap22:
|
|
||||||
_start_trap23:
|
|
||||||
_start_trap24:
|
|
||||||
_start_trap25:
|
|
||||||
_start_trap26:
|
|
||||||
_start_trap27:
|
|
||||||
_start_trap28:
|
|
||||||
_start_trap29:
|
|
||||||
_start_trap30:
|
|
||||||
_start_trap31:
|
|
||||||
|
|
||||||
"#,
|
|
||||||
r#"
|
|
||||||
_start_trap:
|
|
||||||
"#,
|
|
||||||
#[cfg(feature="fix-sp")]
|
|
||||||
r#"
|
|
||||||
// move SP to some save place if it's pointing below the RAM
|
|
||||||
// otherwise we won't be able to do anything reasonable
|
|
||||||
// (since we don't have a working stack)
|
|
||||||
//
|
|
||||||
// most probably we will just print something and halt in this case
|
|
||||||
// we actually can't do anything else
|
|
||||||
csrw mscratch, t0
|
|
||||||
la t0, _stack_end
|
|
||||||
bge sp, t0, 1f
|
|
||||||
|
|
||||||
// use the reserved exception cause 14 to signal we detected a stack overflow
|
|
||||||
li t0, 14
|
|
||||||
csrw mcause, t0
|
|
||||||
|
|
||||||
// set SP to the start of the stack
|
|
||||||
la sp, _stack_start
|
|
||||||
li t0, 4 // make sure stack start is in RAM
|
|
||||||
sub sp, sp, t0
|
|
||||||
andi sp, sp, -16 // Force 16-byte alignment
|
|
||||||
|
|
||||||
1:
|
|
||||||
csrr t0, mscratch
|
|
||||||
// now SP is in RAM - continue
|
|
||||||
"#,
|
|
||||||
r#"
|
|
||||||
addi sp, sp, -40*4
|
|
||||||
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:
|
_start_trap_direct:
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
@ -749,7 +711,7 @@ r#"
|
|||||||
|
|
||||||
add a0, sp, zero
|
add a0, sp, zero
|
||||||
"#,
|
"#,
|
||||||
#[cfg(all(feature="interrupt-preemption", feature="direct-vectoring"))] //store current priority, set threshold, enable interrupts
|
// store current priority, set threshold, enable interrupts
|
||||||
r#"
|
r#"
|
||||||
addi sp, sp, -4 #build stack
|
addi sp, sp, -4 #build stack
|
||||||
sw ra, 0(sp)
|
sw ra, 0(sp)
|
||||||
@ -758,15 +720,11 @@ r#"
|
|||||||
sw a0, 0(sp) #reuse old stack, a0 is return of _handle_priority
|
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
|
addi a0, sp, 4 #the proper stack pointer is an argument to the HAL handler
|
||||||
"#,
|
"#,
|
||||||
#[cfg(not(feature="direct-vectoring"))] //jump to HAL handler
|
// jump to handler loaded in direct handler
|
||||||
r#"
|
|
||||||
jal ra, _start_trap_rust_hal
|
|
||||||
"#,
|
|
||||||
#[cfg(feature="direct-vectoring")] //jump to handler loaded in direct handler
|
|
||||||
r#"
|
r#"
|
||||||
jalr ra, ra #jump to label loaded in _start_trapx
|
jalr ra, ra #jump to label loaded in _start_trapx
|
||||||
"#,
|
"#,
|
||||||
#[cfg(all(feature="interrupt-preemption", feature="direct-vectoring"))] //restore threshold
|
// restore threshold
|
||||||
r#"
|
r#"
|
||||||
lw a0, 0(sp) #load stored priority
|
lw a0, 0(sp) #load stored priority
|
||||||
jal ra, _restore_priority
|
jal ra, _restore_priority
|
||||||
@ -866,10 +824,8 @@ _vector_table:
|
|||||||
j _start_trap29
|
j _start_trap29
|
||||||
j _start_trap30
|
j _start_trap30
|
||||||
j _start_trap31
|
j _start_trap31
|
||||||
|
|
||||||
.option pop
|
.option pop
|
||||||
"#,
|
"#,
|
||||||
#[cfg(feature="direct-vectoring")]
|
|
||||||
r#"
|
r#"
|
||||||
#this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user.
|
#this is required for the linking step, these symbols for in-use interrupts should always be overwritten by the user.
|
||||||
.section .trap, "ax"
|
.section .trap, "ax"
|
||||||
|
@ -27,5 +27,8 @@ rustflags = [
|
|||||||
# "-C", "linker=rust-lld",
|
# "-C", "linker=rust-lld",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[env]
|
||||||
|
ESP_LOGLEVEL = "info"
|
||||||
|
|
||||||
[unstable]
|
[unstable]
|
||||||
build-std = ["alloc", "core"]
|
build-std = ["alloc", "core"]
|
||||||
|
@ -23,9 +23,9 @@ embedded-hal-bus = "0.1.0"
|
|||||||
embedded-io-async = "0.6.1"
|
embedded-io-async = "0.6.1"
|
||||||
esp-alloc = "0.3.0"
|
esp-alloc = "0.3.0"
|
||||||
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
|
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
|
||||||
esp-hal = { version = "0.16.0", path = "../esp-hal" }
|
esp-hal = { version = "0.16.0", path = "../esp-hal", features = ["log"] }
|
||||||
esp-hal-smartled = { version = "0.9.0", path = "../esp-hal-smartled", optional = true }
|
esp-hal-smartled = { version = "0.9.0", path = "../esp-hal-smartled", optional = true }
|
||||||
esp-println = "0.9.1"
|
esp-println = { version = "0.9.1", features = ["log"] }
|
||||||
heapless = "0.8.0"
|
heapless = "0.8.0"
|
||||||
hex-literal = "0.4.1"
|
hex-literal = "0.4.1"
|
||||||
hmac = { version = "0.12.1", default-features = false }
|
hmac = { version = "0.12.1", default-features = false }
|
||||||
@ -39,6 +39,7 @@ ssd1306 = "0.8.4"
|
|||||||
static_cell = { version = "2.0.0", features = ["nightly"] }
|
static_cell = { version = "2.0.0", features = ["nightly"] }
|
||||||
usb-device = "0.3.2"
|
usb-device = "0.3.2"
|
||||||
usbd-serial = "0.2.1"
|
usbd-serial = "0.2.1"
|
||||||
|
log = "0.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
esp32 = ["esp-hal/esp32", "esp-backtrace/esp32", "esp-println/esp32", "esp-hal-smartled/esp32"]
|
esp32 = ["esp-hal/esp32", "esp-backtrace/esp32", "esp-println/esp32", "esp-hal-smartled/esp32"]
|
||||||
@ -63,9 +64,6 @@ embassy-executor-interrupt = ["esp-hal/embassy-executor-interrupt"]
|
|||||||
embassy-time-timg0 = ["esp-hal/embassy-time-timg0"]
|
embassy-time-timg0 = ["esp-hal/embassy-time-timg0"]
|
||||||
embassy-generic-timers = ["embassy-time/generic-queue-8"]
|
embassy-generic-timers = ["embassy-time/generic-queue-8"]
|
||||||
|
|
||||||
direct-vectoring = ["esp-hal/direct-vectoring"]
|
|
||||||
interrupt-preemption = ["esp-hal/interrupt-preemption"]
|
|
||||||
|
|
||||||
opsram-2m = ["esp-hal/opsram-2m"]
|
opsram-2m = ["esp-hal/opsram-2m"]
|
||||||
psram-2m = ["esp-hal/psram-2m"]
|
psram-2m = ["esp-hal/psram-2m"]
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2
|
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2
|
||||||
//% FEATURES: direct-vectoring
|
|
||||||
|
|
||||||
use core::{arch::asm, cell::RefCell};
|
use core::{arch::asm, cell::RefCell};
|
||||||
|
|
||||||
@ -33,14 +32,13 @@ fn main() -> ! {
|
|||||||
let sw_int = system.software_interrupt_control;
|
let sw_int = system.software_interrupt_control;
|
||||||
|
|
||||||
critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int));
|
critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int));
|
||||||
unsafe {
|
interrupt::enable_direct(
|
||||||
interrupt::enable(
|
|
||||||
Interrupt::FROM_CPU_INTR0,
|
Interrupt::FROM_CPU_INTR0,
|
||||||
Priority::Priority3,
|
Priority::Priority3,
|
||||||
CpuInterrupt::Interrupt1,
|
CpuInterrupt::Interrupt20,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
unsafe {
|
||||||
asm!(
|
asm!(
|
||||||
"
|
"
|
||||||
csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2
|
csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2
|
||||||
@ -69,7 +67,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
fn cpu_int_1_handler() {
|
fn cpu_int_20_handler() {
|
||||||
unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") }
|
unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") }
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
SWINT
|
SWINT
|
||||||
|
@ -33,7 +33,10 @@ async fn main(_spawner: Spawner) {
|
|||||||
embassy::init(&clocks, timg0);
|
embassy::init(&clocks, timg0);
|
||||||
|
|
||||||
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
|
||||||
|
#[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))]
|
||||||
let mut input = io.pins.gpio0.into_pull_down_input();
|
let mut input = io.pins.gpio0.into_pull_down_input();
|
||||||
|
#[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))]
|
||||||
|
let mut input = io.pins.gpio9.into_pull_down_input();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
esp_println::println!("Waiting...");
|
esp_println::println!("Waiting...");
|
||||||
|
@ -4,9 +4,6 @@
|
|||||||
//! priority. Should show higher-numbered software interrupts happening during
|
//! priority. Should show higher-numbered software interrupts happening during
|
||||||
//! the handling of lower-numbered ones.
|
//! the handling of lower-numbered ones.
|
||||||
|
|
||||||
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2
|
|
||||||
//% FEATURES: interrupt-preemption
|
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
@ -34,7 +31,7 @@ fn main() -> ! {
|
|||||||
interrupt::enable(Interrupt::FROM_CPU_INTR0, Priority::Priority1).unwrap();
|
interrupt::enable(Interrupt::FROM_CPU_INTR0, Priority::Priority1).unwrap();
|
||||||
interrupt::enable(Interrupt::FROM_CPU_INTR1, Priority::Priority2).unwrap();
|
interrupt::enable(Interrupt::FROM_CPU_INTR1, Priority::Priority2).unwrap();
|
||||||
interrupt::enable(Interrupt::FROM_CPU_INTR2, Priority::Priority2).unwrap();
|
interrupt::enable(Interrupt::FROM_CPU_INTR2, Priority::Priority2).unwrap();
|
||||||
interrupt::enable(Interrupt::FROM_CPU_INTR3, Priority::Priority15).unwrap();
|
interrupt::enable(Interrupt::FROM_CPU_INTR3, Priority::Priority3).unwrap();
|
||||||
|
|
||||||
// Raise mid priority interrupt.
|
// Raise mid priority interrupt.
|
||||||
//
|
//
|
||||||
|
Loading…
x
Reference in New Issue
Block a user