From 6d9048a873b701825b884ec71017fd42db1fa3cd Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov <62840029+playfulFence@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:54:10 +0100 Subject: [PATCH 1/5] Update `PR Template` (#1281) * Update `PR Template` * Minor improvements --- .github/PULL_REQUEST_TEMPLATE.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a03a7e2cbc5..9cb728b2f69 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,18 +1,18 @@ -## Thank you! +## Thank you for your contribution! -Thank you for your contribution. -Please make sure that your submission includes the following: +We appreciate the time and effort you've put into this pull request. +To help us review it efficiently, please ensure you've gone through the following checklist: -### Must +### Submission Checklist 📝 +- [ ] I have updated existing examples or added new ones (if applicable). +- [ ] My changes were added to the [`CHANGELOG.md`](https://github.com/esp-rs/esp-hal/blob/main/esp-hal/CHANGELOG.md) in the **_proper_** section. +#### Extra: +- [ ] I have read the [CONTRIBUTING.md guide](https://github.com/esp-rs/esp-hal/blob/main/CONTRIBUTING.md) and followed its instructions. -- [ ] The code compiles without `errors` or `warnings`. -- [ ] All examples work. -- [ ] `cargo fmt` was run. -- [ ] Your changes were added to the `CHANGELOG.md` in the proper section. -- [ ] You updated existing examples or added examples (if applicable). -- [ ] Added examples are checked in CI +### Pull Request Details 📖 -### Nice to have +#### Description +Please provide a clear and concise description of your changes, including the motivation behind these changes. The context is crucial for the reviewers. -- [ ] You add a description of your work to this PR. -- [ ] You added proper docs for your newly added features and code. +#### Testing +Describe how you tested your changes. From e5b393fe4d3021cad025bd0301445cf6c61081a7 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Wed, 20 Mar 2024 14:36:05 +0000 Subject: [PATCH 2/5] Use task arena instead of `embassy-executor`'s `nightly` feature (#1314) --- examples/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 92b1d2187bf..f7c0dcdd957 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -11,7 +11,7 @@ cfg-if = "1.0.0" critical-section = "1.1.2" crypto-bigint = { version = "0.5.5", default-features = false } elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] } -embassy-executor = { version = "0.5.0", features = ["nightly"] } +embassy-executor = { version = "0.5.0", features = ["task-arena-size-8192"] } embassy-sync = "0.5.0" embassy-time = "0.3.0" embassy-time-driver = { version = "0.1.0", optional = true } From 1f155cf301cd35b0ab77fff362c84dc953b39eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Wed, 20 Mar 2024 16:46:38 +0100 Subject: [PATCH 3/5] ESP32: Apply Errata 3.6 fix in more places (#1315) * ESP32: Apply Errata 3.6 fix in more places * CHANGELOG.md entry --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/gpio.rs | 11 ++- esp-hal/src/soc/esp32/gpio.rs | 154 +++++++++++++++++++++++----------- 3 files changed, 116 insertions(+), 50 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index e5137010b71..bd3a8aa9eb9 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reserve `esp32` ROM stacks to prevent the trashing of dram2 section (#1289) - Fixing `esp-wifi` + `TRNG` issue on `ESP32-S2` (#1272) - Fixed core1 startup using the wrong stack on the esp32 and esp32s3 (#1286). +- ESP32: Apply fix for Errata 3.6 in all the places necessary. (#1315) ### Changed diff --git a/esp-hal/src/gpio.rs b/esp-hal/src/gpio.rs index 41c04026562..c0b3b425b85 100644 --- a/esp-hal/src/gpio.rs +++ b/esp-hal/src/gpio.rs @@ -622,7 +622,7 @@ where .modify(|_, w| unsafe { w.out_sel().bits(OutputSignal::GPIO as OutputSignalType) }); #[cfg(esp32)] - crate::soc::gpio::errata36(GPIONUM, pull_up, pull_down); + crate::soc::gpio::errata36(GPIONUM, Some(pull_up), Some(pull_down)); // NOTE: Workaround to make GPIO18 and GPIO19 work on the ESP32-C3, which by // default are assigned to the `USB_SERIAL_JTAG` peripheral. @@ -1139,6 +1139,9 @@ where fn init_output(&self, alternate: AlternateFunction, open_drain: bool) { let gpio = unsafe { &*GPIO::PTR }; + #[cfg(esp32)] + crate::soc::gpio::errata36(GPIONUM, Some(false), Some(false)); + ::Bank::write_out_en_set(1 << (GPIONUM % 32)); gpio.pin(GPIONUM as usize) .modify(|_, w| w.pad_driver().bit(open_drain)); @@ -1277,10 +1280,16 @@ where } fn internal_pull_up(&mut self, on: bool) -> &mut Self { + #[cfg(esp32)] + crate::soc::gpio::errata36(GPIONUM, Some(on), None); + get_io_mux_reg(GPIONUM).modify(|_, w| w.fun_wpu().bit(on)); self } fn internal_pull_down(&mut self, on: bool) -> &mut Self { + #[cfg(esp32)] + crate::soc::gpio::errata36(GPIONUM, None, Some(on)); + get_io_mux_reg(GPIONUM).modify(|_, w| w.fun_wpd().bit(on)); self } diff --git a/esp-hal/src/soc/esp32/gpio.rs b/esp-hal/src/soc/esp32/gpio.rs index d3bb31044ce..eda75aa89d3 100644 --- a/esp-hal/src/soc/esp32/gpio.rs +++ b/esp-hal/src/soc/esp32/gpio.rs @@ -619,85 +619,141 @@ pub enum OutputSignal { MTDO, } -pub(crate) fn errata36(pin_num: u8, pull_up: bool, pull_down: bool) { +pub(crate) fn errata36(pin_num: u8, pull_up: Option, pull_down: Option) { use crate::peripherals::RTC_IO; let rtcio = unsafe { &*RTC_IO::PTR }; match pin_num { 0 => { - rtcio - .touch_pad1() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad1().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 2 => { - rtcio - .touch_pad2() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad2().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 4 => { - rtcio - .touch_pad0() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad0().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 12 => { - rtcio - .touch_pad5() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad5().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 13 => { - rtcio - .touch_pad4() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad4().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 14 => { - rtcio - .touch_pad6() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad6().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 15 => { - rtcio - .touch_pad3() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad3().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 25 => { - rtcio.pad_dac1().modify(|r, w| unsafe { - w.bits(r.bits()) - .pdac1_rue() - .bit(pull_up) - .pdac1_rde() - .bit(pull_down) + rtcio.pad_dac1().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.pdac1_rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.pdac1_rde().bit(pull_down); + } + w }); } 26 => { - rtcio.pad_dac2().modify(|r, w| unsafe { - w.bits(r.bits()) - .pdac2_rue() - .bit(pull_up) - .pdac2_rde() - .bit(pull_down) + rtcio.pad_dac2().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.pdac2_rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.pdac2_rde().bit(pull_down); + } + w }); } 27 => { - rtcio - .touch_pad7() - .modify(|r, w| unsafe { w.bits(r.bits()).rue().bit(pull_up).rde().bit(pull_down) }); + rtcio.touch_pad7().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.rde().bit(pull_down); + } + w + }); } 32 => { - rtcio.xtal_32k_pad().modify(|r, w| unsafe { - w.bits(r.bits()) - .x32p_rue() - .bit(pull_up) - .x32p_rde() - .bit(pull_down) + rtcio.xtal_32k_pad().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.x32p_rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.x32p_rde().bit(pull_down); + } + w }); } 33 => { - rtcio.xtal_32k_pad().modify(|r, w| unsafe { - w.bits(r.bits()) - .x32n_rue() - .bit(pull_up) - .x32n_rde() - .bit(pull_down) + rtcio.xtal_32k_pad().modify(|_, w| { + if let Some(pull_up) = pull_up { + w.x32n_rue().bit(pull_up); + } + if let Some(pull_down) = pull_down { + w.x32n_rde().bit(pull_down); + } + w }); } _ => (), From a61ffef90905e12eea3246cd86f7ec6d6002c9af Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Mar 2024 16:19:22 +0000 Subject: [PATCH 4/5] 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 --- .github/workflows/ci.yml | 4 +- esp-hal/CHANGELOG.md | 2 + esp-hal/Cargo.toml | 4 - esp-hal/build.rs | 12 +- esp-hal/src/embassy/executor/interrupt.rs | 6 +- esp-hal/src/interrupt/mod.rs | 41 +- esp-hal/src/interrupt/riscv.rs | 567 +++++++++------------- esp-hal/src/interrupt/xtensa.rs | 53 +- esp-riscv-rt/Cargo.toml | 8 - esp-riscv-rt/src/lib.rs | 120 ++--- examples/.cargo/config.toml | 3 + examples/Cargo.toml | 8 +- examples/src/bin/direct_vectoring.rs | 16 +- examples/src/bin/embassy_wait.rs | 3 + examples/src/bin/interrupt_preemption.rs | 5 +- 15 files changed, 351 insertions(+), 501 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a927afa28f..c3676eb1379 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,7 @@ jobs: "esp32c3", "esp32c6", "esp32h2", - "esp32p4", + # "esp32p4", # Xtensa devices: "esp32", "esp32s2", @@ -179,7 +179,7 @@ jobs: 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=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) run: | cargo xtask build-package --features=esp32c6 --target=riscv32imac-unknown-none-elf esp-lp-hal diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index bd3a8aa9eb9..7522afb5c07 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - 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 @@ -27,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed - 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 diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 6581fcc23f1..daa50df8d92 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -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"] #! ### 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 ## (ESP32-C6 and ESPS32-H2 only!). 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. place-spi-driver-in-ram = [] ## Initialize the `.data` section of memory. diff --git a/esp-hal/build.rs b/esp-hal/build.rs index a1d13e3518b..efc6e90ab4e 100644 --- a/esp-hal/build.rs +++ b/esp-hal/build.rs @@ -7,7 +7,7 @@ use std::{ str::FromStr, }; -use esp_metadata::{Arch, Chip, Config}; +use esp_metadata::{Chip, Config}; // Macros taken from: // https://github.com/TheDan64/inkwell/blob/36c3b10/src/lib.rs#L81-L110 @@ -113,21 +113,13 @@ fn main() -> Result<(), Box> { 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: config.define_symbols(); #[allow(unused_mut)] let mut config_symbols = config.all(); #[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 // files: diff --git a/esp-hal/src/embassy/executor/interrupt.rs b/esp-hal/src/embassy/executor/interrupt.rs index 18f2164f4be..ad15c00b1d6 100644 --- a/esp-hal/src/embassy/executor/interrupt.rs +++ b/esp-hal/src/embassy/executor/interrupt.rs @@ -42,11 +42,7 @@ macro_rules! from_cpu { 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::[], priority)); - } + unwrap!(interrupt::enable(peripherals::Interrupt::[], priority)); } fn number() -> usize { diff --git a/esp-hal/src/interrupt/mod.rs b/esp-hal/src/interrupt/mod.rs index f7b92eee38e..5652e0b8b5e 100644 --- a/esp-hal/src/interrupt/mod.rs +++ b/esp-hal/src/interrupt/mod.rs @@ -1,27 +1,18 @@ //! # Interrupt support //! -//! ## Overview -//! 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 -//! management of interrupts. When an interrupt occurs, it temporarily stops the -//! ongoing CPU operations, saves its current state, and starts executing the -//! corresponding interrupt service routine (ISR). The interrupt service routine -//! 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 -//! interrupt driver determines the `priority` of each interrupt. This -//! prioritization ensures that critical or high-priority tasks are handled -//! 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. +//! Interrupt support functionality depends heavily on the features enabled. //! +//! When the `vectored` feature is enabled, the +//! [`enable`] method will map interrupt to a CPU +//! interrupt, and handle the `vector`ing to the peripheral interrupt, for +//! example `UART0`. +//! +//! It is also possible, but not recommended, to bind an interrupt directly to a +//! CPU interrupt. This can offer lower latency, at the cost of more complexity +//! in the interrupt handler. +//! +//! The `vectored` reserves a number of CPU interrupts, which cannot be used see +//! [`RESERVED_INTERRUPTS`]. //! //! ## Example //! ```no_run @@ -30,12 +21,20 @@ //! ... //! critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int)); //! +//! // enable the interrupt //! interrupt::enable( //! peripherals::Interrupt::FROM_CPU_INTR0, //! interrupt::Priority::Priority1, //! ) //! .unwrap(); //! +//! // trigger the interrupt +//! SWINT +//! .borrow_ref_mut(cs) +//! .as_mut() +//! .unwrap() +//! .raise(SoftwareInterrupt::SoftwareInterrupt0); +//! //! loop {} //! } //! diff --git a/esp-hal/src/interrupt/riscv.rs b/esp-hal/src/interrupt/riscv.rs index da13660588b..f941628fa79 100644 --- a/esp-hal/src/interrupt/riscv.rs +++ b/esp-hal/src/interrupt/riscv.rs @@ -29,6 +29,15 @@ use crate::{ 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 #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum InterruptKind { @@ -127,6 +136,194 @@ impl Priority { #[cfg(feature = "vectored")] pub use vectored::*; +#[cfg(feature = "vectored")] +pub const RESERVED_INTERRUPTS: &[usize] = INTERRUPT_TO_PRIORITY; + +/// # Safety +/// +/// This function is called from an assembly trap handler. +#[doc(hidden)] +#[link_section = ".trap.rust"] +#[export_name = "_start_trap_rust_hal"] +pub unsafe extern "C" fn start_trap_rust_hal(trap_frame: *mut TrapFrame) { + assert!( + mcause::read().is_exception(), + "Arrived into _start_trap_rust_hal but mcause is not an exception!" + ); + extern "C" { + fn ExceptionHandler(tf: *mut TrapFrame); + } + ExceptionHandler(trap_frame); +} + +#[doc(hidden)] +#[no_mangle] +pub fn _setup_interrupts() { + extern "C" { + static _vector_table: *const u32; + } + + unsafe { + // disable all known interrupts + // at least after the 2nd stage bootloader there are some interrupts enabled + // (e.g. UART) + for peripheral_interrupt in 0..255 { + crate::soc::peripherals::Interrupt::try_from(peripheral_interrupt) + .map(|intr| { + #[cfg(multi_core)] + disable(Cpu::AppCpu, intr); + disable(Cpu::ProCpu, intr); + }) + .ok(); + } + + let vec_table = &_vector_table as *const _ as usize; + mtvec::write(vec_table, mtvec::TrapMode::Vectored); + + #[cfg(feature = "vectored")] + crate::interrupt::init_vectoring(); + }; + + #[cfg(plic)] + unsafe { + core::arch::asm!("csrw mie, {0}", in(reg) u32::MAX); + } +} + +/// 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. +pub fn disable(_core: Cpu, interrupt: Interrupt) { + unsafe { + let interrupt_number = interrupt as isize; + let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; + + // set to 0 to disable the peripheral interrupt on chips with an interrupt + // controller other than PLIC use the disabled interrupt 31 otherwise + intr_map_base + .offset(interrupt_number) + .write_volatile(DISABLED_CPU_INTERRUPT); + } +} + +/// Get status of peripheral interrupts +#[inline] +pub fn get_status(_core: Cpu) -> u128 { + #[cfg(large_intr_status)] + unsafe { + ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_0() + .read() + .bits() as u128) + | ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_1() + .read() + .bits() as u128) + << 32 + | ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .int_status_reg_2() + .read() + .bits() as u128) + << 64 + } + + #[cfg(very_large_intr_status)] + unsafe { + ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_0() + .read() + .bits() as u128) + | ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_1() + .read() + .bits() as u128) + << 32 + | ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_2() + .read() + .bits() as u128) + << 64 + | ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_3() + .read() + .bits() as u128) + << 96 + } + + #[cfg(not(any(large_intr_status, very_large_intr_status)))] + unsafe { + ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_0() + .read() + .bits() as u128) + | ((*crate::peripherals::INTERRUPT_CORE0::PTR) + .intr_status_reg_1() + .read() + .bits() as u128) + << 32 + } +} + +/// Assign a peripheral interrupt to an CPU interrupt. +/// +/// Great care must be taken when using the `vectored` feature, +/// 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) { + let interrupt_number = interrupt as isize; + let cpu_interrupt_number = which as isize; + #[cfg(not(multi_core))] + let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; + #[cfg(multi_core)] + let intr_map_base = match _core { + Cpu::ProCpu => crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32, + Cpu::AppCpu => crate::soc::registers::INTERRUPT_MAP_BASE_APP_CPU as *mut u32, + }; + + intr_map_base + .offset(interrupt_number) + .write_volatile(cpu_interrupt_number as u32 + EXTERNAL_INTERRUPT_OFFSET); +} + +/// Get cpu interrupt assigned to peripheral interrupt +#[inline] +unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option { + let interrupt_number = interrupt as isize; + let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; + + let cpu_intr = intr_map_base.offset(interrupt_number).read_volatile(); + if cpu_intr > 0 { + Some(core::mem::transmute(cpu_intr - EXTERNAL_INTERRUPT_OFFSET)) + } else { + None + } +} + #[cfg(feature = "vectored")] mod vectored { use procmacros::ram; @@ -174,18 +371,10 @@ mod vectored { } } - /// 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); @@ -206,31 +395,6 @@ mod vectored { 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()); @@ -275,391 +439,123 @@ mod vectored { #[no_mangle] #[ram] - pub unsafe fn interrupt1(context: &mut TrapFrame) { + unsafe fn cpu_int_1_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt1, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt2(context: &mut TrapFrame) { + unsafe fn cpu_int_2_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt2, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt3(context: &mut TrapFrame) { + unsafe fn cpu_int_3_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt3, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt4(context: &mut TrapFrame) { + unsafe fn cpu_int_4_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt4, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt5(context: &mut TrapFrame) { + unsafe fn cpu_int_5_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt5, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt6(context: &mut TrapFrame) { + unsafe fn cpu_int_6_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt6, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt7(context: &mut TrapFrame) { + unsafe fn cpu_int_7_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt7, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt8(context: &mut TrapFrame) { + unsafe fn cpu_int_8_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt8, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt9(context: &mut TrapFrame) { + unsafe fn cpu_int_9_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt9, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt10(context: &mut TrapFrame) { + unsafe fn cpu_int_10_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt10, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt11(context: &mut TrapFrame) { + unsafe fn cpu_int_11_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt11, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt12(context: &mut TrapFrame) { + unsafe fn cpu_int_12_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt12, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt13(context: &mut TrapFrame) { + unsafe fn cpu_int_13_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt13, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt14(context: &mut TrapFrame) { + unsafe fn cpu_int_14_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt14, context) } #[no_mangle] #[ram] - pub unsafe fn interrupt15(context: &mut TrapFrame) { + unsafe fn cpu_int_15_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt15, context) } #[cfg(plic)] #[no_mangle] #[ram] - pub unsafe fn interrupt16(context: &mut TrapFrame) { + unsafe fn cpu_int_16_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt16, context) } #[cfg(plic)] #[no_mangle] #[ram] - pub unsafe fn interrupt17(context: &mut TrapFrame) { + unsafe fn cpu_int_17_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt17, context) } #[cfg(plic)] #[no_mangle] #[ram] - pub unsafe fn interrupt18(context: &mut TrapFrame) { + unsafe fn cpu_int_18_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt18, context) } #[cfg(plic)] #[no_mangle] #[ram] - pub unsafe fn interrupt19(context: &mut TrapFrame) { + unsafe fn cpu_int_19_handler(context: &mut TrapFrame) { handle_interrupts(CpuInterrupt::Interrupt19, context) } } -/// # Safety -/// -/// This function is called from an assembly trap handler. -#[doc(hidden)] -#[link_section = ".trap.rust"] -#[export_name = "_start_trap_rust_hal"] -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 - // general. However this makes things like preemtive multitasking easier in - // future - 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" { - fn ExceptionHandler(tf: *mut TrapFrame); - } - 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)] -#[no_mangle] -pub fn _setup_interrupts() { - extern "C" { - static _vector_table: *const u32; - } - - unsafe { - // disable all known interrupts - // at least after the 2nd stage bootloader there are some interrupts enabled - // (e.g. UART) - for peripheral_interrupt in 0..255 { - crate::soc::peripherals::Interrupt::try_from(peripheral_interrupt) - .map(|intr| { - #[cfg(multi_core)] - disable(Cpu::AppCpu, intr); - disable(Cpu::ProCpu, intr); - }) - .ok(); - } - - let vec_table = &_vector_table as *const _ as usize; - mtvec::write(vec_table, mtvec::TrapMode::Vectored); - - #[cfg(feature = "vectored")] - crate::interrupt::init_vectoring(); - }; - - #[cfg(plic)] - unsafe { - core::arch::asm!("csrw mie, {0}", in(reg) u32::MAX); - } -} - -/// Disable the given peripheral interrupt. -pub fn disable(_core: Cpu, interrupt: Interrupt) { - unsafe { - let interrupt_number = interrupt as isize; - let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; - - // set to 0 to disable the peripheral interrupt on chips with an interrupt - // controller other than PLIC use the disabled interrupt 31 otherwise - intr_map_base - .offset(interrupt_number) - .write_volatile(DISABLED_CPU_INTERRUPT); - } -} - -/// Get status of peripheral interrupts -#[inline] -pub fn get_status(_core: Cpu) -> u128 { - #[cfg(large_intr_status)] - unsafe { - ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_0() - .read() - .bits() as u128) - | ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_1() - .read() - .bits() as u128) - << 32 - | ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .int_status_reg_2() - .read() - .bits() as u128) - << 64 - } - - #[cfg(very_large_intr_status)] - unsafe { - ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_0() - .read() - .bits() as u128) - | ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_1() - .read() - .bits() as u128) - << 32 - | ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_2() - .read() - .bits() as u128) - << 64 - | ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_3() - .read() - .bits() as u128) - << 96 - } - - #[cfg(not(any(large_intr_status, very_large_intr_status)))] - unsafe { - ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_0() - .read() - .bits() as u128) - | ((*crate::peripherals::INTERRUPT_CORE0::PTR) - .intr_status_reg_1() - .read() - .bits() as u128) - << 32 - } -} - -/// 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. -pub unsafe fn map(_core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { - let interrupt_number = interrupt as isize; - let cpu_interrupt_number = which as isize; - #[cfg(not(multi_core))] - let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; - #[cfg(multi_core)] - let intr_map_base = match _core { - Cpu::ProCpu => crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32, - Cpu::AppCpu => crate::soc::registers::INTERRUPT_MAP_BASE_APP_CPU as *mut u32, - }; - - intr_map_base - .offset(interrupt_number) - .write_volatile(cpu_interrupt_number as u32 + EXTERNAL_INTERRUPT_OFFSET); -} - -/// Get cpu interrupt assigned to peripheral interrupt -#[inline] -unsafe fn get_assigned_cpu_interrupt(interrupt: Interrupt) -> Option { - let interrupt_number = interrupt as isize; - let intr_map_base = crate::soc::registers::INTERRUPT_MAP_BASE as *mut u32; - - let cpu_intr = intr_map_base.offset(interrupt_number).read_volatile(); - if cpu_intr > 0 { - Some(core::mem::transmute(cpu_intr - EXTERNAL_INTERRUPT_OFFSET)) - } else { - None - } -} - #[cfg(not(any(plic, clic)))] mod classic { use super::{CpuInterrupt, InterruptKind, Priority}; @@ -669,11 +565,11 @@ mod classic { pub(super) const EXTERNAL_INTERRUPT_OFFSET: u32 = 0; - pub(super) const PRIORITY_TO_INTERRUPT: [usize; 15] = - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + pub(super) const PRIORITY_TO_INTERRUPT: &[usize] = + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - pub(super) const INTERRUPT_TO_PRIORITY: [usize; 15] = - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + pub(super) const INTERRUPT_TO_PRIORITY: &[usize] = + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; /// Enable a CPU interrupt pub unsafe fn enable_cpu_interrupt(which: CpuInterrupt) { @@ -749,7 +645,6 @@ mod classic { .read_volatile(); core::mem::transmute(prio as u8) } - #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] #[no_mangle] #[link_section = ".trap"] pub(super) unsafe extern "C" fn _handle_priority() -> u32 { @@ -759,7 +654,7 @@ mod classic { let interrupt_priority = intr .cpu_int_pri_0() .as_ptr() - .offset(interrupt_id as isize) + .add(interrupt_id) .read_volatile(); let prev_interrupt_priority = intr.cpu_int_thresh().read().bits(); @@ -773,7 +668,6 @@ mod classic { } prev_interrupt_priority } - #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] #[no_mangle] #[link_section = ".trap"] 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) // for some reason also CPU interrupt 8 doesn't work by default since it's // disabled after reset - so don't use that, too - pub(super) const PRIORITY_TO_INTERRUPT: [usize; 15] = - [1, 2, 5, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; + pub(super) const PRIORITY_TO_INTERRUPT: &[usize] = + &[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, ]; @@ -807,7 +701,6 @@ 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(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) { @@ -883,13 +776,12 @@ mod plic { .read_volatile(); core::mem::transmute(prio as u8) } - #[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; 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 thresh_reg = PLIC_MXINT_THRESH_REG as *mut u32; @@ -904,7 +796,6 @@ mod plic { } prev_interrupt_priority } - #[cfg(any(feature = "interrupt-preemption", feature = "direct-vectoring"))] #[no_mangle] #[link_section = ".trap"] 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 PRIORITY_TO_INTERRUPT: [usize; 15] = - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + pub(super) const PRIORITY_TO_INTERRUPT: &[usize] = + &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; - pub(super) const INTERRUPT_TO_PRIORITY: [usize; 15] = - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + pub(super) const INTERRUPT_TO_PRIORITY: &[usize] = + &[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, // base points to the current core interrupt register, diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index 285dfe40042..6b1b4d7a6a0 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -9,6 +9,14 @@ use crate::{ 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 /// /// It's possible to create one handler per priority level. (e.g @@ -52,16 +60,41 @@ pub enum CpuInterrupt { 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 /// /// Great care **must** be taken when using this function with interrupt -/// vectoring (enabled by default). Avoid the following CPU interrupts: -/// - Interrupt1LevelPriority1 -/// - Interrupt19LevelPriority2 -/// - Interrupt23LevelPriority3 -/// - Interrupt10EdgePriority1 -/// - Interrupt22EdgePriority3 -/// As they are preallocated for interrupt vectoring. +/// vectoring (enabled by default). Avoid the interrupts listed in +/// [`RESERVED_INTERRUPTS`] as they are preallocated for interrupt vectoring. /// /// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt /// still needs to be enabled afterwards @@ -196,12 +229,6 @@ mod vectored { use super::*; use crate::get_core; - #[derive(Copy, Clone, Debug, PartialEq, Eq)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum Error { - InvalidInterrupt, - } - /// Interrupt priority levels. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/esp-riscv-rt/Cargo.toml b/esp-riscv-rt/Cargo.toml index 76e2f35404b..6a6d9208332 100644 --- a/esp-riscv-rt/Cargo.toml +++ b/esp-riscv-rt/Cargo.toml @@ -35,22 +35,14 @@ zero-bss = [] ## Zero the `.rtc_fast.bss` section. 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: ci = [ - "direct-vectoring", "fix-sp", "has-mie-mip", "init-data", "init-rtc-fast-data", "init-rtc-fast-text", "init-rw-text", - "interrupt-preemption", "zero-bss", "zero-rtc-fast-bss", ] diff --git a/esp-riscv-rt/src/lib.rs b/esp-riscv-rt/src/lib.rs index ee941243bff..226492c3e49 100644 --- a/esp-riscv-rt/src/lib.rs +++ b/esp-riscv-rt/src/lib.rs @@ -442,7 +442,7 @@ _abs_start: _start_trap_rust, then restores all saved registers before `mret` */ .section .trap, "ax" -.weak _start_trap +.weak _start_trap /* Exceptions call into _start_trap in vectored mode */ .weak _start_trap1 .weak _start_trap2 .weak _start_trap3 @@ -475,8 +475,40 @@ _abs_start: .weak _start_trap30 .weak _start_trap31 "#, -#[cfg(feature="direct-vectoring")] 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: addi sp, sp, -40*4 sw ra, 0(sp) @@ -632,77 +664,7 @@ _start_trap31: 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: -_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 +la ra, _start_trap_rust_hal /* this runs on exception, use regular fault handler */ _start_trap_direct: "#, r#" @@ -749,7 +711,7 @@ r#" 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#" addi sp, sp, -4 #build stack sw ra, 0(sp) @@ -758,15 +720,11 @@ r#" 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 + // 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 + // restore threshold r#" lw a0, 0(sp) #load stored priority jal ra, _restore_priority @@ -866,10 +824,8 @@ _vector_table: j _start_trap29 j _start_trap30 j _start_trap31 - .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" diff --git a/examples/.cargo/config.toml b/examples/.cargo/config.toml index f717140031f..c5549ea3ebc 100644 --- a/examples/.cargo/config.toml +++ b/examples/.cargo/config.toml @@ -27,5 +27,8 @@ rustflags = [ # "-C", "linker=rust-lld", ] +[env] +ESP_LOGLEVEL = "info" + [unstable] build-std = ["alloc", "core"] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f7c0dcdd957..4d1af639549 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -23,9 +23,9 @@ embedded-hal-bus = "0.1.0" embedded-io-async = "0.6.1" esp-alloc = "0.3.0" 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-println = "0.9.1" +esp-println = { version = "0.9.1", features = ["log"] } heapless = "0.8.0" hex-literal = "0.4.1" hmac = { version = "0.12.1", default-features = false } @@ -39,6 +39,7 @@ ssd1306 = "0.8.4" static_cell = { version = "2.0.0", features = ["nightly"] } usb-device = "0.3.2" usbd-serial = "0.2.1" +log = "0.4" [features] 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-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"] psram-2m = ["esp-hal/psram-2m"] diff --git a/examples/src/bin/direct_vectoring.rs b/examples/src/bin/direct_vectoring.rs index ab09e5836f1..463ce9853ad 100644 --- a/examples/src/bin/direct_vectoring.rs +++ b/examples/src/bin/direct_vectoring.rs @@ -2,7 +2,6 @@ #![no_std] //% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 -//% FEATURES: direct-vectoring use core::{arch::asm, cell::RefCell}; @@ -33,14 +32,13 @@ fn main() -> ! { let sw_int = system.software_interrupt_control; critical_section::with(|cs| SWINT.borrow_ref_mut(cs).replace(sw_int)); + interrupt::enable_direct( + Interrupt::FROM_CPU_INTR0, + Priority::Priority3, + CpuInterrupt::Interrupt20, + ) + .unwrap(); unsafe { - interrupt::enable( - Interrupt::FROM_CPU_INTR0, - Priority::Priority3, - CpuInterrupt::Interrupt1, - ) - .unwrap(); - asm!( " csrrwi x0, 0x7e0, 1 #what to count, for cycles write 1 for instructions write 2 @@ -69,7 +67,7 @@ fn main() -> ! { } #[no_mangle] -fn cpu_int_1_handler() { +fn cpu_int_20_handler() { unsafe { asm!("csrrwi x0, 0x7e1, 0 #disable timer") } critical_section::with(|cs| { SWINT diff --git a/examples/src/bin/embassy_wait.rs b/examples/src/bin/embassy_wait.rs index 56a8c4c1151..9824007e9a0 100644 --- a/examples/src/bin/embassy_wait.rs +++ b/examples/src/bin/embassy_wait.rs @@ -33,7 +33,10 @@ async fn main(_spawner: Spawner) { embassy::init(&clocks, timg0); 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(); + #[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))] + let mut input = io.pins.gpio9.into_pull_down_input(); loop { esp_println::println!("Waiting..."); diff --git a/examples/src/bin/interrupt_preemption.rs b/examples/src/bin/interrupt_preemption.rs index e80515c76c4..f9542ed0a49 100644 --- a/examples/src/bin/interrupt_preemption.rs +++ b/examples/src/bin/interrupt_preemption.rs @@ -4,9 +4,6 @@ //! priority. Should show higher-numbered software interrupts happening during //! the handling of lower-numbered ones. -//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 -//% FEATURES: interrupt-preemption - #![no_std] #![no_main] @@ -34,7 +31,7 @@ fn main() -> ! { interrupt::enable(Interrupt::FROM_CPU_INTR0, Priority::Priority1).unwrap(); interrupt::enable(Interrupt::FROM_CPU_INTR1, 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. // From e98cf71b670c1bcd0050c72636c1dbbe4e9430a6 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Mar 2024 17:12:33 +0000 Subject: [PATCH 5/5] Fix up docs and features; default to enabling eh1 instead of eh02 (#1313) * Fix up docs and features; default to enabling eh1 instead of eh02 * Changelog * Fix twai example * Fixup from defaulting to eh1 --- esp-hal/CHANGELOG.md | 1 + esp-hal/Cargo.toml | 36 ++++++++++++++++----------- esp-hal/src/analog/adc/esp32.rs | 3 +++ esp-hal/src/analog/adc/riscv.rs | 6 +++++ esp-hal/src/analog/adc/xtensa.rs | 3 +++ esp-hal/src/i2c.rs | 4 +-- esp-hal/src/rng.rs | 4 ++- esp-hal/src/rtc_cntl/mod.rs | 2 +- esp-hal/src/spi/master.rs | 42 +++++++++++++++----------------- esp-hal/src/timer.rs | 7 ++++-- examples/Cargo.toml | 1 + examples/src/bin/twai.rs | 7 +++--- xtask/src/lib.rs | 8 +++++- 13 files changed, 78 insertions(+), 46 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 7522afb5c07..497abfc69b0 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Prefer mutable references over moving for DMA transactions (#1238) - Support runtime interrupt binding, adapt GPIO driver (#1231) - Renamed `eh1` feature to `embedded-hal`, feature-gated `embedded-hal@0.2.x` trait implementations (#1273) +- Enable `embedded-hal` feature by default, instead of the `embedded-hal-02` feature (#1313) ### Removed diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index daa50df8d92..e6a594fab82 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -74,7 +74,7 @@ esp-metadata = { version = "0.1.0", path = "../esp-metadata" } serde = { version = "1.0.197", features = ["derive"] } [features] -default = ["embedded-hal-02", "rt", "vectored"] +default = ["embedded-hal", "rt", "vectored"] riscv = ["dep:riscv", "critical-section/restore-state-u8", "esp-riscv-rt?/zero-bss"] xtensa = ["dep:xtensa-lx", "critical-section/restore-state-u32"] @@ -111,31 +111,31 @@ rt = [ ] ## Enable interrupt vectoring. vectored = ["procmacros/interrupt"] +## Configuration for placing device drivers in the IRAM for faster access. +place-spi-driver-in-ram = [] -#! ### Chip Support Feature Flags -## Target the ESP32. +# Chip Support Feature Flags +# Target the ESP32. esp32 = ["dep:esp32", "xtensa", "xtensa-lx/spin", "xtensa-lx-rt?/esp32"] -## Target the ESP32-C2. +# Target the ESP32-C2. esp32c2 = ["dep:esp32c2", "riscv", "portable-atomic/unsafe-assume-single-core"] -## Target the ESP32-C3. +# Target the ESP32-C3. esp32c3 = ["dep:esp32c3", "riscv", "portable-atomic/unsafe-assume-single-core", "rv-zero-rtc-bss"] -## Target the ESP32-C6. +# Target the ESP32-C6. esp32c6 = ["dep:esp32c6", "riscv", "procmacros/has-lp-core", "rv-zero-rtc-bss"] -## Target the ESP32-H2. +# Target the ESP32-H2. esp32h2 = ["dep:esp32h2", "riscv", "rv-zero-rtc-bss"] -## Target the ESP32-P4. +# Target the ESP32-P4. esp32p4 = ["dep:esp32p4", "riscv", "procmacros/has-lp-core", "rv-zero-rtc-bss"] -## Target the ESP32-S2. +# Target the ESP32-S2. esp32s2 = ["dep:esp32s2", "xtensa", "portable-atomic/critical-section", "procmacros/has-ulp-core", "xtensa-lx-rt?/esp32s2", "usb-otg"] -## Target the ESP32-S3. +# Target the ESP32-S3. esp32s3 = ["dep:esp32s3", "xtensa", "procmacros/has-ulp-core", "xtensa-lx/spin", "xtensa-lx-rt?/esp32s3", "usb-otg"] #! ### RISC-V Exclusive Feature Flags ## Move the stack to start of RAM to get zero-cost stack overflow protection ## (ESP32-C6 and ESPS32-H2 only!). flip-link = ["esp-riscv-rt/fix-sp"] -## Configuration for placing device drivers in the IRAM for faster access. -place-spi-driver-in-ram = [] ## Initialize the `.data` section of memory. rv-init-data = ["esp-riscv-rt?/init-data", "esp-riscv-rt?/init-rw-text"] ## Zero the `.bss` section of low-power memory. @@ -164,11 +164,11 @@ defmt = [ "embedded-io/defmt-03", "embedded-io-async?/defmt-03", ] -## Implement the traits defined in the `0.2.x` release of `embedded-hal`. -embedded-hal-02 = ["dep:embedded-hal-02"] ## Implement the traits defined in the `1.0.0` releases of `embedded-hal` and ## `embedded-hal-nb` for the relevant peripherals. embedded-hal = ["dep:embedded-hal", "dep:embedded-hal-nb", "dep:embedded-can"] +## Implement the traits defined in the `0.2.x` release of `embedded-hal`. +embedded-hal-02 = ["dep:embedded-hal-02"] ## Implement the traits defined in `embedded-io` for certain peripherals. embedded-io = ["dep:embedded-io"] ## Implement the `ufmt_write::uWrite` trait for certain peripherals. @@ -217,6 +217,14 @@ opsram-8m = [] ## Use externally connected Octal RAM (16MB). opsram-16m = [] +# This feature is intended for testing; you probably don't want to enable it: +ci = [ + "default", + "embedded-hal-02", + "ufmt", + "async", +] + [lints.clippy] mixed_attributes_style = "allow" diff --git a/esp-hal/src/analog/adc/esp32.rs b/esp-hal/src/analog/adc/esp32.rs index 9f6f5f6d920..d7e90177a4b 100644 --- a/esp-hal/src/analog/adc/esp32.rs +++ b/esp-hal/src/analog/adc/esp32.rs @@ -249,7 +249,9 @@ impl RegisterAccess for ADC2 { /// Analog-to-Digital Converter peripheral driver. pub struct ADC<'d, ADC> { _adc: PeripheralRef<'d, ADC>, + #[allow(dead_code)] // FIXME attenuations: [Option; 10], + #[allow(dead_code)] // FIXME active_channel: Option, } @@ -418,6 +420,7 @@ macro_rules! impl_adc_interface { } mod adc_implementation { + #[cfg(feature = "embedded-hal-02")] use crate::peripherals::{ADC1, ADC2}; impl_adc_interface! { diff --git a/esp-hal/src/analog/adc/riscv.rs b/esp-hal/src/analog/adc/riscv.rs index 406b24a4471..599062ac010 100644 --- a/esp-hal/src/analog/adc/riscv.rs +++ b/esp-hal/src/analog/adc/riscv.rs @@ -486,7 +486,9 @@ impl CalibrationAccess for crate::peripherals::ADC2 { /// Analog-to-Digital Converter peripheral driver. pub struct ADC<'d, ADCI> { _adc: PeripheralRef<'d, ADCI>, + #[allow(dead_code)] // FIXME attenuations: [Option; NUM_ATTENS], + #[allow(dead_code)] // FIXME active_channel: Option, } @@ -648,6 +650,7 @@ macro_rules! impl_adc_interface { #[cfg(esp32c2)] mod adc_implementation { + #[cfg(feature = "embedded-hal-02")] use crate::peripherals::ADC1; impl_adc_interface! { @@ -663,6 +666,7 @@ mod adc_implementation { #[cfg(esp32c3)] mod adc_implementation { + #[cfg(feature = "embedded-hal-02")] use crate::peripherals::{ADC1, ADC2}; impl_adc_interface! { @@ -684,6 +688,7 @@ mod adc_implementation { #[cfg(esp32c6)] mod adc_implementation { + #[cfg(feature = "embedded-hal-02")] use crate::peripherals::ADC1; impl_adc_interface! { @@ -701,6 +706,7 @@ mod adc_implementation { #[cfg(esp32h2)] mod adc_implementation { + #[cfg(feature = "embedded-hal-02")] use crate::peripherals::ADC1; impl_adc_interface! { diff --git a/esp-hal/src/analog/adc/xtensa.rs b/esp-hal/src/analog/adc/xtensa.rs index 096fd1ac52f..c3ccb9b9655 100644 --- a/esp-hal/src/analog/adc/xtensa.rs +++ b/esp-hal/src/analog/adc/xtensa.rs @@ -524,7 +524,9 @@ impl CalibrationAccess for crate::peripherals::ADC2 { /// Analog-to-Digital Converter peripheral driver. pub struct ADC<'d, ADC> { _adc: PeripheralRef<'d, ADC>, + #[allow(dead_code)] // FIXME attenuations: [Option; 10], + #[allow(dead_code)] // FIXME active_channel: Option, } @@ -719,6 +721,7 @@ macro_rules! impl_adc_interface { } mod adc_implementation { + #[cfg(feature = "embedded-hal-02")] use crate::peripherals::{ADC1, ADC2}; impl_adc_interface! { diff --git a/esp-hal/src/i2c.rs b/esp-hal/src/i2c.rs index 6af5ab12ad2..43a8e5b259d 100644 --- a/esp-hal/src/i2c.rs +++ b/esp-hal/src/i2c.rs @@ -255,10 +255,10 @@ where self.peripheral.master_write_read(address, bytes, buffer) } - fn transaction<'a>( + fn transaction( &mut self, _address: u8, - _operations: &mut [embedded_hal::i2c::Operation<'a>], + _operations: &mut [embedded_hal::i2c::Operation<'_>], ) -> Result<(), Self::Error> { todo!() } diff --git a/esp-hal/src/rng.rs b/esp-hal/src/rng.rs index d3ee9cfc426..8ea996f4a7b 100644 --- a/esp-hal/src/rng.rs +++ b/esp-hal/src/rng.rs @@ -63,7 +63,9 @@ //! rng.read(&mut buffer).unwrap(); //! ``` -use core::{convert::Infallible, marker::PhantomData}; +#[cfg(feature = "embedded-hal-02")] +use core::convert::Infallible; +use core::marker::PhantomData; use crate::{peripheral::Peripheral, peripherals::RNG}; diff --git a/esp-hal/src/rtc_cntl/mod.rs b/esp-hal/src/rtc_cntl/mod.rs index b72a9387ab2..c813c0ed296 100644 --- a/esp-hal/src/rtc_cntl/mod.rs +++ b/esp-hal/src/rtc_cntl/mod.rs @@ -805,7 +805,7 @@ impl Rwdt { self.set_write_protection(true); } - fn set_timeout(&mut self, timeout: MicrosDurationU64) { + pub fn set_timeout(&mut self, timeout: MicrosDurationU64) { #[cfg(not(any(esp32c6, esp32h2)))] let rtc_cntl = unsafe { &*LPWR::PTR }; #[cfg(any(esp32c6, esp32h2))] diff --git a/esp-hal/src/spi/master.rs b/esp-hal/src/spi/master.rs index 9941a72a2fb..6bf8beab8d1 100644 --- a/esp-hal/src/spi/master.rs +++ b/esp-hal/src/spi/master.rs @@ -1532,29 +1532,27 @@ pub mod dma { } fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - Ok( - if !crate::soc::is_valid_ram_address(&words[0] as *const _ as u32) { - for chunk in words.chunks(SIZE) { - self.buffer[..chunk.len()].copy_from_slice(chunk); - self.inner.write(&self.buffer[..chunk.len()])?; - } - } else { - self.inner.write(words)?; - }, - ) + if !crate::soc::is_valid_ram_address(&words[0] as *const _ as u32) { + for chunk in words.chunks(SIZE) { + self.buffer[..chunk.len()].copy_from_slice(chunk); + self.inner.write(&self.buffer[..chunk.len()])?; + } + } else { + self.inner.write(words)?; + } + Ok(()) } fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { - Ok( - if !crate::soc::is_valid_ram_address(&write[0] as *const _ as u32) { - for (read, write) in read.chunks_mut(SIZE).zip(write.chunks(SIZE)) { - self.buffer[..write.len()].copy_from_slice(write); - self.inner.transfer(read, &self.buffer[..write.len()])?; - } - } else { - self.inner.transfer(read, write)?; - }, - ) + if !crate::soc::is_valid_ram_address(&write[0] as *const _ as u32) { + for (read, write) in read.chunks_mut(SIZE).zip(write.chunks(SIZE)) { + self.buffer[..write.len()].copy_from_slice(write); + self.inner.transfer(read, &self.buffer[..write.len()])?; + } + } else { + self.inner.transfer(read, write)?; + } + Ok(()) } fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { @@ -1608,9 +1606,9 @@ mod ehal1 { fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { // Optimizations - if read.len() == 0 { + if read.is_empty() { SpiBus::write(self, write)?; - } else if write.len() == 0 { + } else if write.is_empty() { SpiBus::read(self, read)?; } diff --git a/esp-hal/src/timer.rs b/esp-hal/src/timer.rs index ad97998c5c9..a2a492779b3 100644 --- a/esp-hal/src/timer.rs +++ b/esp-hal/src/timer.rs @@ -40,6 +40,7 @@ use core::{ }; use fugit::{HertzU32, MicrosDurationU64}; +#[cfg(feature = "embedded-hal-02")] use void::Void; #[cfg(timg1)] @@ -221,6 +222,7 @@ where /// General-purpose Timer driver pub struct Timer { timg: T, + #[allow(dead_code)] // FIXME apb_clk_freq: HertzU32, } @@ -638,6 +640,7 @@ where } } +#[allow(dead_code)] // FIXME fn timeout_to_ticks(timeout: T, clock: F, divider: u32) -> u64 where T: Into, @@ -781,7 +784,7 @@ where .write(|w| unsafe { w.wdt_wkey().bits(0u32) }); } - fn feed(&mut self) { + pub fn feed(&mut self) { let reg_block = unsafe { &*TG::register_block() }; reg_block @@ -795,7 +798,7 @@ where .write(|w| unsafe { w.wdt_wkey().bits(0u32) }); } - fn set_timeout(&mut self, timeout: MicrosDurationU64) { + pub fn set_timeout(&mut self, timeout: MicrosDurationU64) { let timeout_raw = (timeout.to_nanos() * 10 / 125) as u32; let reg_block = unsafe { &*TG::register_block() }; diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 4d1af639549..5de4f1da7ef 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -21,6 +21,7 @@ embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = embedded-hal-async = "1.0.0" embedded-hal-bus = "0.1.0" embedded-io-async = "0.6.1" +embedded-can = "0.4.1" esp-alloc = "0.3.0" esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] } esp-hal = { version = "0.16.0", path = "../esp-hal", features = ["log"] } diff --git a/examples/src/bin/twai.rs b/examples/src/bin/twai.rs index 1808998e812..539ec981ab4 100644 --- a/examples/src/bin/twai.rs +++ b/examples/src/bin/twai.rs @@ -12,6 +12,7 @@ //! `IS_FIRST_SENDER` below must be set to false on one of the ESP's //% CHIPS: esp32c3 esp32s3 +//% FEATURES: embedded-hal #![no_std] #![no_main] @@ -20,12 +21,12 @@ const IS_FIRST_SENDER: bool = true; // Run this example with the embedded-hal feature enabled to use embedded-can instead of // embedded-hal-0.2.7. embedded-can was split off from embedded-hal before it's -// upgrade to 1.0.0. cargo run --example twai --features embedded-hal --release +// upgrade to 1.0.0. cargo run --example twai --release #[cfg(feature = "embedded-hal")] use embedded_can::{nb::Can, Frame, StandardId}; // Run this example without the embedded-hal flag to use the embedded-hal 0.2.7 CAN traits. -// cargo run --example twai --release -#[cfg(not(feature = "embedded-hal"))] +// cargo run --example twai --features embedded-hal-02 --release +#[cfg(feature = "embedded-hal-02")] use embedded_hal_02::can::{Can, Frame, StandardId}; use esp_backtrace as _; use esp_hal::{ diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index 2e7ad8f3501..e47a0cb2540 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs @@ -150,12 +150,18 @@ pub fn build_documentation( log::info!("Building '{package_name}' documentation targeting '{chip}'"); + let mut features = vec![chip.to_string()]; + + if matches!(package, Package::EspHal) { + features.push("ci".to_owned()) + } + // Build up an array of command-line arguments to pass to `cargo`: let mut builder = CargoArgsBuilder::default() .subcommand("doc") .arg("-Zbuild-std=core") // Required for Xtensa, for some reason .target(target) - .features(&[chip.to_string()]); + .features(&features); if open { builder = builder.arg("--open");