Xtensa vectored interrupts (#103)

* Xtensa interrupt vectoring: peripheral source

- Initial Xtensa vectoring, updated esp32 gpio example to use new interrupt macro.
- Only peripheral sources supported.
- Only level one priority supported.
- CPU & Edge interrupts still need to be handled.

* Xtensa interrupt vectoring: CPU & EDGE

- Add support for handling CPU interrupts and edge interrupts
- PR required to xtensa-lx-rt for CPU handlers

* Xtensa interrupt vectoring: Priority

- Finally implement priortization
- Only three priorities available at the moment. Xtensa programmer guide
  discourages using highpri interrupts in Rust/C. Guide also mentions
  using software priortization to increase the number of Priorities
  available

* support CPU interrupts, using patch xtensa-lx-rt

* Update example

* Add support & examples for the s2 & s3 too

* Fix formatting and missing imports

* Run interrupt handling in ram, optionally run the vector handler in ram in the examples

* Use xtensa_lx::Mutex CS when enabling interrupts

* Run clippy on each target

* Remove redundant features

* Fix C3 builds

* make enable unsafe. Add note about preallocated interrupts in vectored mode.

* Remove `INTERRUPT_LEVELS` static

The interrupt levels static introduces a few issues
  - A lock is needed when configuring interrupts to keep
    INTERRUPT_LEVELS in a consistent state
  - Interrupts enabled from outside the Rust domain wouldn't be
    serviced, this is the case with the wifi blobs

To remove it, the prioty configuration is now calculated dynamically in
the interrupt handler. Essentially INTERRUPT_LEVELS is now created once
the interrupt triggers. It has some benefits, such as only having to
look at interrupts configured on the current core, not both, but there
is of course an overhead with doing this in the interrupt.

* Allow raw interrupts on levels 4-7, whilst also supporting vectoring on levels 1-3

* rename core number features

* Fix examples and formatting

* use xtensa-lx-rt release, update pacs

* Support passing the trap frame into interrupt handlers

* cfg away the #[interrupt] macro when not using vectoring

* rename enable to map

move vectored feature to chip specific hals

* export vectored functions

- rename `enable_with_priority` to `enable`
- add docs for interrupt macro

* Update all examples to use vectored interrupts
This commit is contained in:
Scott Mabin 2022-07-25 07:12:34 -07:00 committed by GitHub
parent 34b1e09662
commit 1789780d06
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 851 additions and 534 deletions

View File

@ -54,25 +54,44 @@ jobs:
# The `hello_rgb` example requires the `smartled` feature to be enabled
args: -Zbuild-std=core --examples --manifest-path=${{ matrix.chip }}-hal/Cargo.toml --target=xtensa-${{ matrix.chip }}-none-elf --features=smartled
clippy:
name: Clippy
clippy-riscv:
name: Run clippy on RISC-V builds
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
chip: [esp32, esp32c3, esp32s2, esp32s3]
toolchain: [stable, nightly]
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: nightly
default: true
target: riscv32imc-unknown-none-elf
toolchain: ${{ matrix.toolchain }}
components: clippy
default: true
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
with:
command: clippy
# I find `clippy::too-many-arguments` to be rather rather arbitrary.
# As for `clippy::module-inception`... don't tell me what to do ;)
args: --manifest-path=${{ matrix.chip }}-hal/Cargo.toml -- --no-deps -D warnings --A clippy::too-many-arguments --A clippy::module-inception
args: --manifest-path=esp32c3-hal/Cargo.toml --target=riscv32imc-unknown-none-elf -- --no-deps -D warnings --A clippy::too-many-arguments --A clippy::module-inception
clippy-xtensa:
name: Run clippy on Xtensa builds
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
chip: [esp32, esp32s2, esp32s3]
steps:
- uses: actions/checkout@v2
- uses: esp-rs/xtensa-toolchain@v1.2
with:
default: true
ldproxy: false
buildtargets: ${{ matrix.chip }}
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
with:
command: clippy
args: -Zbuild-std=core --manifest-path=${{ matrix.chip }}-hal/Cargo.toml --target=xtensa-${{ matrix.chip }}-none-elf -- --no-deps -D warnings --A clippy::too-many-arguments --A clippy::module-inception

17
.vscode/settings.json vendored
View File

@ -1,17 +1,12 @@
{
"editor.formatOnSave": true,
"rust-analyzer.cargo.buildScripts.enable": true,
"rust-analyzer.cargo.noDefaultFeatures": true,
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.imports.granularity.enforce": true,
"rust-analyzer.imports.granularity.group": "crate",
"rust-analyzer.procMacro.attributes.enable": false,
"rust-analyzer.procMacro.enable": true,
// -----------------------------------------------------------------------
// Since we have to handle multiple toolchains AND multiple targets, we
// we need to give Rust Analyzer some directions.
@ -20,16 +15,14 @@
// developing for. This will propagate to the `esp-hal-common` crate too,
// as it is a dependency. Changing target/project requires reloading
// Rust Analyzer.
// "rust-analyzer.cargo.target": "xtensa-esp32-none-elf",
"rust-analyzer.cargo.target": "riscv32imc-unknown-none-elf",
"rust-analyzer.cargo.target": "xtensa-esp32-none-elf",
// "rust-analyzer.cargo.target": "riscv32imc-unknown-none-elf",
// "rust-analyzer.cargo.target": "xtensa-esp32s2-none-elf",
// "rust-analyzer.cargo.target": "xtensa-esp32s3-none-elf",
"rust-analyzer.linkedProjects": [
// "esp32-hal/Cargo.toml",
"esp32c3-hal/Cargo.toml",
"esp32-hal/Cargo.toml",
// "esp32c3-hal/Cargo.toml",
// "esp32s2-hal/Cargo.toml",
// "esp32s3-hal/Cargo.toml",
],
}
}

View File

@ -38,27 +38,21 @@ smart-leds-trait = { version = "0.2.1", optional = true }
# Each supported device MUST have its PAC included below along with a
# corresponding feature. We rename the PAC packages because we cannot
# have dependencies and features with the same names.
#
# Please note: for now we use git-dependencies from the `with_source` branch however we pin the dependency
# to specific commits.
esp32_pac = { package = "esp32", git = "https://github.com/esp-rs/esp-pacs.git", rev = "148dbb843cba3c311364aa994b8f3f773d15b04f", optional = true }
esp32c3_pac = { package = "esp32c3", git = "https://github.com/esp-rs/esp-pacs.git", rev = "148dbb843cba3c311364aa994b8f3f773d15b04f", optional = true }
esp32s2_pac = { package = "esp32s2", git = "https://github.com/esp-rs/esp-pacs.git", rev = "148dbb843cba3c311364aa994b8f3f773d15b04f", optional = true }
esp32s3_pac = { package = "esp32s3", git = "https://github.com/esp-rs/esp-pacs.git", rev = "148dbb843cba3c311364aa994b8f3f773d15b04f", optional = true }
esp32_pac = { package = "esp32", git = "https://github.com/esp-rs/esp-pacs.git", branch = "with_source", optional = true }
esp32c3_pac = { package = "esp32c3", git = "https://github.com/esp-rs/esp-pacs.git", branch = "with_source", optional = true }
esp32s2_pac = { package = "esp32s2", git = "https://github.com/esp-rs/esp-pacs.git", branch = "with_source", optional = true }
esp32s3_pac = { package = "esp32s3", git = "https://github.com/esp-rs/esp-pacs.git", branch = "with_source", optional = true }
[features]
esp32 = [ "esp32_pac/rt", "xtensa", "dual_core", "xtensa-lx-rt/esp32", "xtensa-lx/esp32"]
esp32c3 = ["esp32c3_pac/rt", "risc_v", "single_core"]
esp32s2 = ["esp32s2_pac/rt", "xtensa", "single_core", "xtensa-lx-rt/esp32s2", "xtensa-lx/esp32s2"]
esp32s3 = ["esp32s3_pac/rt", "xtensa", "dual_core", "xtensa-lx-rt/esp32s3", "xtensa-lx/esp32s3"]
esp32 = ["esp32_pac/rt" , "procmacros/xtensa", "multi_core" , "xtensa-lx-rt/esp32", "xtensa-lx/esp32"]
esp32c3 = ["esp32c3_pac/rt", "procmacros/riscv" , "single_core", "riscv", "riscv-atomic-emulation-trap"]
esp32s2 = ["esp32s2_pac/rt", "procmacros/xtensa", "single_core", "xtensa-lx-rt/esp32s2", "xtensa-lx/esp32s2"]
esp32s3 = ["esp32s3_pac/rt", "procmacros/xtensa", "multi_core" , "xtensa-lx-rt/esp32s3", "xtensa-lx/esp32s3"]
# Architecture (should not be enabled directly, but instead by a PAC's feature)
risc_v = ["riscv", "riscv-atomic-emulation-trap"]
xtensa = ["procmacros/rtc_slow"]
# Core Count (should not be enabled directly, but instead by a PAC's feature)
single_core = []
dual_core = []
multi_core = []
# To support `ufmt`
ufmt = ["ufmt-write"]
@ -68,3 +62,5 @@ smartled = ["smart-leds-trait"]
# Implement the `embedded-hal==1.0.0-alpha.x` traits
eh1 = ["embedded-hal-1"]
# To use vectored interrupts (calling the handlers defined in the PAC)
vectored = ["procmacros/interrupt"]

View File

@ -1,21 +1,17 @@
use xtensa_lx::interrupt::{self, InterruptNumber};
use xtensa_lx_rt::exception::Context;
use crate::{pac::Interrupt, Cpu};
extern "C" {
fn level1_interrupt(save_frame: &mut Context);
fn level2_interrupt(save_frame: &mut Context);
fn level3_interrupt(save_frame: &mut Context);
fn level4_interrupt(save_frame: &mut Context);
fn level5_interrupt(save_frame: &mut Context);
fn level6_interrupt(save_frame: &mut Context);
fn level7_interrupt(save_frame: &mut Context);
}
use crate::{
pac::{self, Interrupt},
Cpu,
};
/// Enumeration of available CPU interrupts
/// It's possible to create one handler per priority level. (e.g
/// `level1_interrupt`)
#[allow(unused)]
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
pub enum CpuInterrupt {
Interrupt0LevelPriority1 = 0,
Interrupt1LevelPriority1,
@ -51,22 +47,32 @@ pub enum CpuInterrupt {
Interrupt31EdgePriority5,
}
/// Enable and assign a peripheral interrupt to an CPU interrupt.
pub fn enable(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
unsafe {
let interrupt_number = interrupt as isize;
let cpu_interrupt_number = which as isize;
let intr_map_base = match core {
Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
#[cfg(feature = "dual_core")]
Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(),
#[cfg(feature = "single_core")]
Cpu::AppCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
};
intr_map_base
.offset(interrupt_number)
.write_volatile(cpu_interrupt_number as u32);
}
/// 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.
///
/// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt
/// still needs to be enabled afterwards
pub unsafe fn map(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) {
let interrupt_number = interrupt as isize;
let cpu_interrupt_number = which as isize;
let intr_map_base = match core {
Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
#[cfg(feature = "multi_core")]
Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(),
#[cfg(feature = "single_core")]
Cpu::AppCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
};
intr_map_base
.offset(interrupt_number)
.write_volatile(cpu_interrupt_number as u32);
}
/// Disable the given peripheral interrupt.
@ -75,7 +81,7 @@ pub fn disable(core: Cpu, interrupt: Interrupt) {
let interrupt_number = interrupt as isize;
let intr_map_base = match core {
Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
#[cfg(feature = "dual_core")]
#[cfg(feature = "multi_core")]
Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(),
#[cfg(feature = "single_core")]
Cpu::AppCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
@ -111,7 +117,7 @@ pub fn get_status(core: Cpu) -> u128 {
.bits() as u128)
<< 64
}
#[cfg(feature = "dual_core")]
#[cfg(feature = "multi_core")]
Cpu::AppCpu => {
((*core1_interrupt_peripheral())
.app_intr_status_0
@ -174,44 +180,380 @@ unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::Re
crate::pac::INTERRUPT_CORE1::PTR
}
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_1_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level1_interrupt(save_frame) };
#[cfg(feature = "vectored")]
pub use vectored::*;
#[cfg(feature = "vectored")]
pub mod vectored {
use procmacros::ram;
use super::*;
use crate::get_core;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Error {
InvalidInterrupt,
}
/// Interrupt priority levels.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum Priority {
None = 0,
Priority1,
Priority2,
Priority3,
}
impl CpuInterrupt {
#[inline]
fn level(&self) -> Priority {
match self {
CpuInterrupt::Interrupt0LevelPriority1
| CpuInterrupt::Interrupt1LevelPriority1
| CpuInterrupt::Interrupt2LevelPriority1
| CpuInterrupt::Interrupt3LevelPriority1
| CpuInterrupt::Interrupt4LevelPriority1
| CpuInterrupt::Interrupt5LevelPriority1
| CpuInterrupt::Interrupt6Timer0Priority1
| CpuInterrupt::Interrupt7SoftwarePriority1
| CpuInterrupt::Interrupt8LevelPriority1
| CpuInterrupt::Interrupt9LevelPriority1
| CpuInterrupt::Interrupt10EdgePriority1
| CpuInterrupt::Interrupt12LevelPriority1
| CpuInterrupt::Interrupt13LevelPriority1
| CpuInterrupt::Interrupt17LevelPriority1
| CpuInterrupt::Interrupt18LevelPriority1 => Priority::Priority1,
CpuInterrupt::Interrupt19LevelPriority2
| CpuInterrupt::Interrupt20LevelPriority2
| CpuInterrupt::Interrupt21LevelPriority2 => Priority::Priority2,
CpuInterrupt::Interrupt11ProfilingPriority3
| CpuInterrupt::Interrupt15Timer1Priority3
| CpuInterrupt::Interrupt22EdgePriority3
| CpuInterrupt::Interrupt27LevelPriority3
| CpuInterrupt::Interrupt29SoftwarePriority3
| CpuInterrupt::Interrupt23LevelPriority3 => Priority::Priority3,
// we direct these to None because we do not support interrupts at this level
// through Rust
CpuInterrupt::Interrupt24LevelPriority4
| CpuInterrupt::Interrupt25LevelPriority4
| CpuInterrupt::Interrupt28EdgePriority4
| CpuInterrupt::Interrupt30EdgePriority4
| CpuInterrupt::Interrupt31EdgePriority5
| CpuInterrupt::Interrupt16Timer2Priority5
| CpuInterrupt::Interrupt26LevelPriority5
| CpuInterrupt::Interrupt14NmiPriority7 => Priority::None,
}
}
}
/// Get the interrupts configured for the core
#[inline]
fn get_configured_interrupts(core: Cpu) -> [u128; 7] {
unsafe {
let intr_map_base = match core {
Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
#[cfg(feature = "multi_core")]
Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(),
#[cfg(feature = "single_core")]
Cpu::AppCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(),
};
let mut levels = [0u128; 7];
for i in 0..get_interrupt_count() {
let i = i as isize;
let cpu_interrupt = intr_map_base.offset(i).read_volatile();
// safety: cast is safe because of repr(u32)
let cpu_interrupt: CpuInterrupt = core::mem::transmute(cpu_interrupt);
let level = cpu_interrupt.level() as u8 as usize;
levels[level] |= 1 << i;
}
levels
}
}
#[inline]
fn get_interrupt_count() -> usize {
cfg_if::cfg_if! {
if #[cfg(feature = "esp32")] {
68
} else if #[cfg(feature = "esp32s2")] {
94
} else if #[cfg(feature = "esp32s3")] {
98
}
}
}
pub fn enable(interrupt: Interrupt, level: Priority) -> Result<(), Error> {
let cpu_interrupt =
interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?;
unsafe {
map(get_core(), interrupt, cpu_interrupt);
xtensa_lx::interrupt::enable_mask(
xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32,
);
}
Ok(())
}
fn interrupt_level_to_cpu_interrupt(
level: Priority,
is_edge: bool,
) -> Result<CpuInterrupt, Error> {
Ok(if is_edge {
match level {
Priority::None => return Err(Error::InvalidInterrupt),
Priority::Priority1 => CpuInterrupt::Interrupt10EdgePriority1,
Priority::Priority2 => return Err(Error::InvalidInterrupt),
Priority::Priority3 => CpuInterrupt::Interrupt22EdgePriority3,
}
} else {
match level {
Priority::None => return Err(Error::InvalidInterrupt),
Priority::Priority1 => CpuInterrupt::Interrupt1LevelPriority1,
Priority::Priority2 => CpuInterrupt::Interrupt19LevelPriority2,
Priority::Priority3 => CpuInterrupt::Interrupt23LevelPriority3,
}
})
}
// TODO use CpuInterrupt::LevelX.mask() // TODO make it const
const CPU_INTERRUPT_LEVELS: [u32; 8] = [
0b_0000_0000_0000_0000_0000_0000_0000_0000, // Dummy level 0
0b_0000_0000_0000_0110_0011_0111_1111_1111, // Level_1
0b_0000_0000_0011_1000_0000_0000_0000_0000, // Level 2
0b_0010_1000_1100_0000_1000_1000_0000_0000, // Level 3
0b_0101_0011_0000_0000_0000_0000_0000_0000, // Level 4
0b_1000_0100_0000_0001_0000_0000_0000_0000, // Level 5
0b_0000_0000_0000_0000_0000_0000_0000_0000, // Level 6
0b_0000_0000_0000_0000_0100_0000_0000_0000, // Level 7
];
const CPU_INTERRUPT_INTERNAL: u32 = 0b_0010_0000_0000_0001_1000_1000_1100_0000;
const CPU_INTERRUPT_EDGE: u32 = 0b_0111_0000_0100_0000_0000_1100_1000_0000;
#[inline]
fn cpu_interrupt_nr_to_cpu_interrupt_handler(number: u32) -> Option<unsafe extern "C" fn(u32)> {
use xtensa_lx_rt::*;
// we're fortunate that all esp variants use the same CPU interrupt layout
Some(match number {
6 => Timer0,
7 => Software0,
11 => Profiling,
14 => NMI,
15 => Timer1,
16 => Timer2,
29 => Software1,
_ => return None,
})
}
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_1_interrupt(level: u32, save_frame: &mut Context) {
handle_interrupts(level, save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_2_interrupt(level: u32, save_frame: &mut Context) {
handle_interrupts(level, save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_3_interrupt(level: u32, save_frame: &mut Context) {
handle_interrupts(level, save_frame)
}
#[ram]
unsafe fn handle_interrupts(level: u32, save_frame: &mut Context) {
let cpu_interrupt_mask =
interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[level as usize];
if cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL != 0 {
let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_INTERNAL;
let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
interrupt::clear(1 << cpu_interrupt_nr);
}
if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) {
handler(level);
}
} else {
let interrupt_levels = get_configured_interrupts(crate::get_core());
if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 {
let cpu_interrupt_mask = cpu_interrupt_mask & CPU_INTERRUPT_EDGE;
let cpu_interrupt_nr = cpu_interrupt_mask.trailing_zeros();
interrupt::clear(1 << cpu_interrupt_nr);
// for edge interrupts cannot rely on the interrupt status
// register, therefore call all registered
// handlers for current level
let mut interrupt_mask =
interrupt_levels[level as usize] & chip_specific::INTERRUPT_EDGE;
loop {
let interrupt_nr = interrupt_mask.trailing_zeros();
if let Ok(interrupt) = pac::Interrupt::try_from(interrupt_nr as u16) {
handle_interrupt(level, interrupt, save_frame)
} else {
break;
}
interrupt_mask &= !(1u128 << interrupt_nr);
}
} else {
// finally check periperal sources and fire of handlers from pac
// peripheral mapped interrupts are cleared by the peripheral
let interrupt_mask =
get_status(crate::get_core()) & interrupt_levels[level as usize];
let interrupt_nr = interrupt_mask.trailing_zeros();
// Interrupt::try_from can fail if interrupt already de-asserted:
// silently ignore
if let Ok(interrupt) = pac::Interrupt::try_from(interrupt_nr as u16) {
handle_interrupt(level, interrupt, save_frame);
}
}
}
}
#[ram]
unsafe fn handle_interrupt(level: u32, interrupt: Interrupt, save_frame: &mut Context) {
extern "C" {
// defined in each hal
fn DefaultHandler(level: u32, interrupt: Interrupt);
}
let handler = pac::__INTERRUPTS[interrupt.number() as usize]._handler;
if handler as *const _ == DefaultHandler as *const unsafe extern "C" fn() {
DefaultHandler(level, interrupt);
} else {
let handler: fn(&mut Context) = core::mem::transmute(handler);
handler(save_frame);
}
}
#[cfg(feature = "esp32")]
mod chip_specific {
use super::*;
pub const INTERRUPT_EDGE: u128 =
0b_0000_0000_0000_0000_0000_0000_0000_0000__0000_0000_0000_0000_0000_0000_0000_0011_1111_1100_0000_0000_0000_0000_0000_0000__0000_0000_0000_0000_0000_0000_0000_0000;
#[inline]
pub fn interrupt_is_edge(interrupt: Interrupt) -> bool {
use pac::Interrupt::*;
[
TG0_T0_EDGE,
TG0_T1_EDGE,
TG0_WDT_EDGE,
TG0_LACT_EDGE,
TG1_T0_EDGE,
TG1_T1_EDGE,
TG1_WDT_EDGE,
TG1_LACT_EDGE,
]
.contains(&interrupt)
}
}
#[cfg(feature = "esp32s2")]
mod chip_specific {
use super::*;
pub const INTERRUPT_EDGE: u128 =
0b_0000_0000_0000_0000_0000_0000_0000_0000__0000_0000_0000_0000_0000_0000_0001_1111_1110_0000_0000_0000_0000_0000_0000_0000__0000_0000_0000_0000_0000_0000_0000_0000;
#[inline]
pub fn interrupt_is_edge(interrupt: Interrupt) -> bool {
use pac::Interrupt::*;
[
TG0_T0_EDGE,
TG0_T1_EDGE,
TG0_WDT_EDGE,
TG0_LACT_EDGE,
TG1_T0_EDGE,
TG1_T1_EDGE,
TG1_WDT_EDGE,
TG1_LACT_EDGE,
]
.contains(&interrupt)
}
}
#[cfg(feature = "esp32s3")]
mod chip_specific {
use super::*;
pub const INTERRUPT_EDGE: u128 = 0;
#[inline]
pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool {
false
}
}
}
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_2_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level2_interrupt(save_frame) };
}
mod raw {
use super::*;
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_3_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level3_interrupt(save_frame) };
}
extern "C" {
#[cfg(not(feature = "vectored"))]
fn level1_interrupt(save_frame: &mut Context);
#[cfg(not(feature = "vectored"))]
fn level2_interrupt(save_frame: &mut Context);
#[cfg(not(feature = "vectored"))]
fn level3_interrupt(save_frame: &mut Context);
fn level4_interrupt(save_frame: &mut Context);
fn level5_interrupt(save_frame: &mut Context);
fn level6_interrupt(save_frame: &mut Context);
fn level7_interrupt(save_frame: &mut Context);
}
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_4_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level4_interrupt(save_frame) };
}
#[no_mangle]
#[link_section = ".rwtext"]
#[cfg(not(feature = "vectored"))]
unsafe fn __level_1_interrupt(_level: u32, save_frame: &mut Context) {
level1_interrupt(save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_5_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level5_interrupt(save_frame) };
}
#[no_mangle]
#[link_section = ".rwtext"]
#[cfg(not(feature = "vectored"))]
unsafe fn __level_2_interrupt(_level: u32, save_frame: &mut Context) {
level2_interrupt(save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_6_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level6_interrupt(save_frame) };
}
#[no_mangle]
#[link_section = ".rwtext"]
#[cfg(not(feature = "vectored"))]
unsafe fn __level_3_interrupt(_level: u32, save_frame: &mut Context) {
level3_interrupt(save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
fn __level_7_interrupt(_level: u32, save_frame: &mut Context) {
unsafe { level7_interrupt(save_frame) };
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_4_interrupt(_level: u32, save_frame: &mut Context) {
level4_interrupt(save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_5_interrupt(_level: u32, save_frame: &mut Context) {
level5_interrupt(save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_6_interrupt(_level: u32, save_frame: &mut Context) {
level6_interrupt(save_frame)
}
#[no_mangle]
#[link_section = ".rwtext"]
unsafe fn __level_7_interrupt(_level: u32, save_frame: &mut Context) {
level7_interrupt(save_frame)
}
}

View File

@ -37,8 +37,8 @@ pub mod efuse;
pub mod gpio;
pub mod i2c;
#[cfg_attr(feature = "risc_v", path = "interrupt/riscv.rs")]
#[cfg_attr(feature = "xtensa", path = "interrupt/xtensa.rs")]
#[cfg_attr(target_arch = "riscv32", path = "interrupt/riscv.rs")]
#[cfg_attr(target_arch = "xtensa", path = "interrupt/xtensa.rs")]
pub mod interrupt;
pub mod prelude;
pub mod pulse_control;
@ -55,7 +55,7 @@ pub mod utils;
pub use delay::Delay;
pub use gpio::*;
pub use interrupt::*;
pub use procmacros::ram;
pub use procmacros as macros;
pub use pulse_control::PulseControl;
pub use rng::Rng;
#[cfg(not(feature = "esp32c3"))]
@ -87,3 +87,17 @@ pub enum Cpu {
/// The second core
AppCpu,
}
pub fn get_core() -> Cpu {
#[cfg(all(target_arch = "xtensa", feature = "multi_core"))]
match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 {
false => Cpu::ProCpu,
true => Cpu::AppCpu,
}
// #[cfg(all(target_arch = "riscv32", feature = "multi_core"))]
// TODO get hart_id
// single core always has ProCpu only
#[cfg(feature = "single_core")]
Cpu::ProCpu
}

View File

@ -60,3 +60,5 @@ pub mod eh1 {
pub use crate::system::SystemExt;
}
pub use crate::macros::*;

View File

@ -22,3 +22,6 @@ proc-macro-error = "1.0.4"
[features]
rtc_slow = []
xtensa = []
riscv = []
interrupt = []

View File

@ -2,6 +2,19 @@ use darling::FromMeta;
use proc_macro::{self, Span, TokenStream};
use proc_macro_error::{abort, proc_macro_error};
use quote::quote;
#[cfg(feature = "interrupt")]
use syn::{
parse,
spanned::Spanned,
AttrStyle,
Attribute,
Ident,
ItemFn,
Meta::Path,
ReturnType,
Type,
Visibility,
};
use syn::{parse_macro_input, AttributeArgs};
#[derive(Debug, Default, FromMeta)]
@ -88,3 +101,208 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream {
};
output.into()
}
/// Marks a function as an interrupt handler
///
/// Used to handle on of the [interrupts](enum.Interrupt.html).
///
/// When specified between braces (`#[interrupt(example)]`) that interrupt will
/// be used and the function can have an arbitrary name. Otherwise the name of
/// the function must be the name of the interrupt.
///
/// Example usage:
///
/// ```rust
/// #[interrupt]
/// fn GPIO() {
/// // code
/// }
/// ```
///
/// The interrupt context can also be supplied by adding a argument to the
/// interrupt function for example, on Xtensa based chips:
///
/// ```rust
/// fn GPIO(context: &mut xtensa_lx_rt::exeception::Context) {
/// // code
/// }
/// ```
#[cfg(feature = "interrupt")]
#[proc_macro_attribute]
pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
let mut f: ItemFn = syn::parse(input).expect("`#[interrupt]` must be applied to a function");
let attr_args = parse_macro_input!(args as AttributeArgs);
if attr_args.len() > 1 {
abort!(
Span::call_site(),
"This attribute accepts zero or 1 arguments"
)
}
let ident = f.sig.ident.clone();
let mut ident_s = &ident.clone();
if attr_args.len() == 1 {
match &attr_args[0] {
syn::NestedMeta::Meta(Path(x)) => {
ident_s = x.get_ident().unwrap();
}
_ => {
abort!(
Span::call_site(),
format!(
"This attribute accepts a string attribute {:?}",
attr_args[0]
)
)
}
}
}
// XXX should we blacklist other attributes?
if let Err(error) = check_attr_whitelist(&f.attrs, WhiteListCaller::Interrupt) {
return error;
}
let valid_signature = f.sig.constness.is_none()
&& f.vis == Visibility::Inherited
&& f.sig.abi.is_none()
&& f.sig.generics.params.is_empty()
&& f.sig.generics.where_clause.is_none()
&& f.sig.variadic.is_none()
&& match f.sig.output {
ReturnType::Default => true,
ReturnType::Type(_, ref ty) => match **ty {
Type::Tuple(ref tuple) => tuple.elems.is_empty(),
Type::Never(..) => true,
_ => false,
},
}
&& f.sig.inputs.len() <= 1;
if !valid_signature {
return parse::Error::new(
f.span(),
"`#[interrupt]` handlers must have signature `[unsafe] fn([&mut Context]) [-> !]`",
)
.to_compile_error()
.into();
}
f.sig.ident = Ident::new(
&format!("__esp_hal_internal_{}", f.sig.ident),
proc_macro2::Span::call_site(),
);
f.block.stmts.extend(std::iter::once(
syn::parse2(quote! {{
// Check that this interrupt actually exists
self::pac::Interrupt::#ident_s;
}})
.unwrap(),
));
let tramp_ident = Ident::new(
&format!("{}_trampoline", f.sig.ident),
proc_macro2::Span::call_site(),
);
let ident = &f.sig.ident;
let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone());
let export_name = ident_s.to_string();
#[cfg(feature = "xtensa")]
let context = quote! {
xtensa_lx_rt::exception::Context
};
#[cfg(feature = "riscv")]
let context = quote! {
crate::interrupt::TrapFrame
};
let context_call =
(f.sig.inputs.len() == 1).then_some(Ident::new("context", proc_macro2::Span::call_site()));
quote!(
#(#cfgs)*
#(#attrs)*
#[doc(hidden)]
#[export_name = #export_name]
pub unsafe extern "C" fn #tramp_ident(context: &mut #context) {
#ident(
#context_call
)
}
#[inline(always)]
#f
)
.into()
}
#[cfg(feature = "interrupt")]
enum WhiteListCaller {
Interrupt,
}
#[cfg(feature = "interrupt")]
fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result<(), TokenStream> {
let whitelist = &[
"doc",
"link_section",
"cfg",
"allow",
"warn",
"deny",
"forbid",
"cold",
"ram",
"inline",
];
'o: for attr in attrs {
for val in whitelist {
if eq(&attr, &val) {
continue 'o;
}
}
let err_str = match caller {
WhiteListCaller::Interrupt => {
"this attribute is not allowed on an interrupt handler controlled by esp-hal"
}
};
return Err(parse::Error::new(attr.span(), &err_str)
.to_compile_error()
.into());
}
Ok(())
}
/// Returns `true` if `attr.path` matches `name`
#[cfg(feature = "interrupt")]
fn eq(attr: &Attribute, name: &str) -> bool {
attr.style == AttrStyle::Outer && attr.path.is_ident(name)
}
#[cfg(feature = "interrupt")]
fn extract_cfgs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<Attribute>) {
let mut cfgs = vec![];
let mut not_cfgs = vec![];
for attr in attrs {
if eq(&attr, "cfg") {
cfgs.push(attr);
} else {
not_cfgs.push(attr);
}
}
(cfgs, not_cfgs)
}

View File

@ -1,16 +0,0 @@
{
"rust-analyzer.cargo.features": [],
"rust-analyzer.cargo.allFeatures": false,
"editor.formatOnSave": false,
"rust-analyzer.checkOnSave.allTargets": false,
"rust-analyzer.checkOnSave.allFeatures": false,
"rust-analyzer.checkOnSave.overrideCommand": [
"cargo",
"check",
"--message-format=json",
"-Z",
"build-std=core",
"--examples"
],
"rust-analyzer.cargo.buildScripts.enable": false
}

View File

@ -43,12 +43,13 @@ smart-leds = "0.3"
esp-println = { version = "0.2.0", features = ["esp32"] }
[features]
default = ["rt"]
default = ["rt", "vectored"]
bluetooth = []
eh1 = ["esp-hal-common/eh1"]
rt = ["xtensa-lx-rt/esp32"]
smartled = ["esp-hal-common/smartled"]
ufmt = ["esp-hal-common/ufmt"]
vectored = ["esp-hal-common/vectored"]
[[example]]
name = "hello_rgb"

View File

@ -6,27 +6,24 @@
#![no_std]
#![no_main]
use core::{cell::RefCell, fmt::Write};
use core::cell::RefCell;
use esp32_hal::{
clock::ClockControl,
gpio::{Gpio0, IO},
gpio_types::{Event, Input, Pin, PullDown},
interrupt,
pac::{self, Peripherals, UART0},
macros::ram,
pac::{self, Peripherals},
prelude::*,
timer::TimerGroup,
Cpu,
Delay,
RtcCntl,
Serial,
};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;
static mut SERIAL: SpinLockMutex<RefCell<Option<Serial<UART0>>>> =
SpinLockMutex::new(RefCell::new(None));
static mut BUTTON: SpinLockMutex<RefCell<Option<Gpio0<Input<PullDown>>>>> =
SpinLockMutex::new(RefCell::new(None));
@ -39,8 +36,6 @@ fn main() -> ! {
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
// Disable the TIMG watchdog timer.
let serial0 = Serial::new(peripherals.UART0);
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
// Disable MWDT and RWDT (Watchdog) flash boot protection
@ -54,15 +49,14 @@ fn main() -> ! {
button.listen(Event::FallingEdge);
unsafe {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
(&BUTTON).lock(|data| (*data).replace(Some(button)));
}
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::GPIO,
interrupt::CpuInterrupt::Interrupt1LevelPriority1,
);
interrupt::vectored::Priority::Priority2,
)
.unwrap();
led.set_high().unwrap();
@ -70,32 +64,21 @@ fn main() -> ! {
// loop.
let mut delay = Delay::new(&clocks);
unsafe {
xtensa_lx::interrupt::enable_mask(1 << 1);
}
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
}
#[no_mangle]
pub fn level1_interrupt() {
#[ram]
#[interrupt]
fn GPIO() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt").ok();
});
}
esp_println::println!(
"GPIO Interrupt with priority {}",
xtensa_lx::interrupt::get_level()
);
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt1LevelPriority1,
);
unsafe {
(&BUTTON).lock(|data| {
let mut button = data.borrow_mut();
let button = button.as_mut().unwrap();

View File

@ -12,9 +12,9 @@ use core::fmt::Write;
use esp32_hal::{
clock::ClockControl,
macros::ram,
pac::{Peripherals, UART0},
prelude::*,
ram,
timer::TimerGroup,
Serial,
};

View File

@ -14,7 +14,6 @@ use esp32_hal::{
prelude::*,
serial::config::AtCmdConfig,
timer::TimerGroup,
Cpu,
RtcCntl,
Serial,
};
@ -53,11 +52,7 @@ fn main() -> ! {
serial0.listen_at_cmd();
serial0.listen_rx_fifo_full();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::UART0,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(pac::Interrupt::UART0, interrupt::Priority::Priority2).unwrap();
timer0.start(1u64.secs());
@ -65,11 +60,6 @@ fn main() -> ! {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
}
unsafe {
xtensa_lx::interrupt::disable();
xtensa_lx::interrupt::enable_mask(1 << 20);
}
loop {
unsafe {
(&SERIAL).lock(|data| {
@ -83,8 +73,8 @@ fn main() -> ! {
}
}
#[no_mangle]
pub fn level2_interrupt() {
#[interrupt]
fn UART0() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
@ -106,10 +96,6 @@ pub fn level2_interrupt() {
serial.reset_at_cmd_interrupt();
serial.reset_rx_fifo_full_interrupt();
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
});
}
}

View File

@ -13,11 +13,10 @@ use esp32_hal::{
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
prelude::*,
timer::{Timer0, Timer1, TimerGroup},
Cpu,
RtcCntl,
Serial,
};
use esp_hal_common::Timer;
use esp_hal_common::{Priority, Timer};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;
@ -58,31 +57,14 @@ fn main() -> ! {
wdt1.disable();
rtc_cntl.set_wdt_global_enable(false);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG0_T0_LEVEL,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG0_T1_LEVEL,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(pac::Interrupt::TG0_T0_LEVEL, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::TG0_T1_LEVEL, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::TG1_T0_LEVEL, Priority::Priority3).unwrap();
interrupt::enable(pac::Interrupt::TG1_T1_LEVEL, Priority::Priority3).unwrap();
timer00.start(500u64.millis());
timer00.listen();
timer01.start(2500u64.millis());
timer01.listen();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG1_T0_LEVEL,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG1_T1_LEVEL,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
timer10.start(1u64.secs());
timer10.listen();
timer11.start(3u64.secs());
@ -96,22 +78,11 @@ fn main() -> ! {
(&TIMER11).lock(|data| (*data).replace(Some(timer11)));
}
unsafe {
xtensa_lx::interrupt::disable();
xtensa_lx::interrupt::enable_mask(1 << 20);
xtensa_lx::interrupt::enable_mask(1 << 23);
}
loop {}
}
#[no_mangle]
pub fn level2_interrupt() {
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
#[interrupt]
fn TG0_T0_LEVEL() {
unsafe {
(&TIMER00).lock(|data| {
let mut timer = data.borrow_mut();
@ -128,7 +99,12 @@ pub fn level2_interrupt() {
});
}
});
}
}
#[interrupt]
fn TG0_T1_LEVEL() {
unsafe {
(&TIMER01).lock(|data| {
let mut timer = data.borrow_mut();
let timer = timer.as_mut().unwrap();
@ -147,13 +123,8 @@ pub fn level2_interrupt() {
}
}
#[no_mangle]
pub fn level3_interrupt() {
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
#[interrupt]
fn TG1_T0_LEVEL() {
unsafe {
(&TIMER10).lock(|data| {
let mut timer = data.borrow_mut();
@ -170,7 +141,12 @@ pub fn level3_interrupt() {
});
}
});
}
}
#[interrupt]
fn TG1_T1_LEVEL() {
unsafe {
(&TIMER11).lock(|data| {
let mut timer = data.borrow_mut();
let timer = timer.as_mut().unwrap();

View File

@ -8,10 +8,10 @@ pub use esp_hal_common::{
gpio as gpio_types,
i2c,
interrupt,
macros,
pac,
prelude,
pulse_control,
ram,
serial,
spi,
timer,

View File

@ -12,9 +12,9 @@ use core::fmt::Write;
use esp32c3_hal::{
clock::ClockControl,
macros::ram,
pac::{Peripherals, UART0},
prelude::*,
ram,
timer::TimerGroup,
Serial,
};

View File

@ -9,10 +9,10 @@ pub use esp_hal_common::{
gpio as gpio_types,
i2c,
interrupt,
macros,
pac,
prelude,
pulse_control,
ram,
serial,
spi,
system,

View File

@ -42,11 +42,12 @@ smart-leds = "0.3"
esp-println = { version = "0.2.0", features = ["esp32s2"] }
[features]
default = ["rt"]
default = ["rt", "vectored"]
eh1 = ["esp-hal-common/eh1"]
rt = ["xtensa-lx-rt/esp32s2"]
smartled = ["esp-hal-common/smartled"]
ufmt = ["esp-hal-common/ufmt"]
vectored = ["esp-hal-common/vectored"]
[[example]]
name = "hello_rgb"

View File

@ -6,27 +6,24 @@
#![no_std]
#![no_main]
use core::{cell::RefCell, fmt::Write};
use core::cell::RefCell;
use esp32s2_hal::{
clock::ClockControl,
gpio::{Gpio0, IO},
gpio_types::{Event, Input, Pin, PullDown},
interrupt,
pac::{self, Peripherals, UART0},
macros::ram,
pac::{self, Peripherals},
prelude::*,
timer::TimerGroup,
Cpu,
Delay,
RtcCntl,
Serial,
};
use panic_halt as _;
use xtensa_lx::mutex::{CriticalSectionMutex, Mutex};
use xtensa_lx_rt::entry;
static mut SERIAL: CriticalSectionMutex<RefCell<Option<Serial<UART0>>>> =
CriticalSectionMutex::new(RefCell::new(None));
static mut BUTTON: CriticalSectionMutex<RefCell<Option<Gpio0<Input<PullDown>>>>> =
CriticalSectionMutex::new(RefCell::new(None));
@ -38,29 +35,28 @@ fn main() -> ! {
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let serial0 = Serial::new(peripherals.UART0);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc_cntl.set_wdt_global_enable(false);
// Set GPIO4 as an output, and set its state high initially.
// Set GPIO15 as an output, and set its state high initially.
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio4.into_push_pull_output();
let mut led = io.pins.gpio15.into_push_pull_output();
let mut button = io.pins.gpio0.into_pull_down_input();
button.listen(Event::FallingEdge);
unsafe {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
(&BUTTON).lock(|data| (*data).replace(Some(button)));
}
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::GPIO,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
interrupt::vectored::Priority::Priority2,
)
.unwrap();
led.set_high().unwrap();
@ -68,32 +64,21 @@ fn main() -> ! {
// loop.
let mut delay = Delay::new(&clocks);
unsafe {
xtensa_lx::interrupt::enable_mask(1 << 19);
}
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
}
#[no_mangle]
pub fn level2_interrupt() {
#[ram]
#[interrupt]
fn GPIO() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt").ok();
});
}
esp_println::println!(
"GPIO Interrupt with priority {}",
xtensa_lx::interrupt::get_level()
);
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
unsafe {
(&BUTTON).lock(|data| {
let mut button = data.borrow_mut();
let button = button.as_mut().unwrap();

View File

@ -12,9 +12,9 @@ use core::fmt::Write;
use esp32s2_hal::{
clock::ClockControl,
macros::ram,
pac::{Peripherals, UART0},
prelude::*,
ram,
timer::TimerGroup,
Serial,
};

View File

@ -14,7 +14,6 @@ use esp32s2_hal::{
prelude::*,
serial::config::AtCmdConfig,
timer::TimerGroup,
Cpu,
RtcCntl,
Serial,
};
@ -36,8 +35,10 @@ fn main() -> ! {
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut timer0 = timer_group0.timer0;
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
let mut wdt1 = timer_group1.wdt;
let mut serial0 = Serial::new(peripherals.UART0);
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
@ -51,11 +52,7 @@ fn main() -> ! {
serial0.listen_at_cmd();
serial0.listen_rx_fifo_full();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::UART0,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(pac::Interrupt::UART0, interrupt::Priority::Priority2).unwrap();
timer0.start(1u64.secs());
@ -63,11 +60,6 @@ fn main() -> ! {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
}
unsafe {
xtensa_lx::interrupt::disable();
xtensa_lx::interrupt::enable_mask(1 << 20);
}
loop {
unsafe {
(&SERIAL).lock(|data| {
@ -81,8 +73,8 @@ fn main() -> ! {
}
}
#[no_mangle]
pub fn level2_interrupt() {
#[interrupt]
fn UART0() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
@ -104,10 +96,6 @@ pub fn level2_interrupt() {
serial.reset_at_cmd_interrupt();
serial.reset_rx_fifo_full_interrupt();
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
});
}
}

View File

@ -4,26 +4,23 @@
#![no_std]
#![no_main]
use core::{cell::RefCell, fmt::Write};
use core::cell::RefCell;
use esp32s2_hal::{
clock::ClockControl,
interrupt,
pac::{self, Peripherals, UART0},
pac::{self, Peripherals},
prelude::*,
systimer::{Alarm, SystemTimer, Target},
timer::TimerGroup,
Cpu,
Delay,
interrupt::Priority,
RtcCntl,
Serial,
};
use panic_halt as _;
use xtensa_lx::mutex::{CriticalSectionMutex, Mutex};
use xtensa_lx::mutex::{Mutex, CriticalSectionMutex};
use xtensa_lx_rt::entry;
static mut SERIAL: CriticalSectionMutex<RefCell<Option<Serial<UART0>>>> =
CriticalSectionMutex::new(RefCell::new(None));
static mut ALARM0: CriticalSectionMutex<RefCell<Option<Alarm<Target, 0>>>> =
CriticalSectionMutex::new(RefCell::new(None));
static mut ALARM1: CriticalSectionMutex<RefCell<Option<Alarm<Target, 1>>>> =
@ -40,7 +37,6 @@ fn main() -> ! {
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let mut serial0 = Serial::new(peripherals.UART0);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
@ -48,10 +44,6 @@ fn main() -> ! {
let syst = SystemTimer::new(peripherals.SYSTIMER);
let now = SystemTimer::now();
writeln!(serial0, "Now: {}", now).ok();
let alarm0 = syst.alarm0;
alarm0.set_target(40_000_0000);
alarm0.enable_interrupt();
@ -65,57 +57,36 @@ fn main() -> ! {
alarm2.enable_interrupt();
unsafe {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
(&ALARM0).lock(|data| (*data).replace(Some(alarm0)));
(&ALARM1).lock(|data| (*data).replace(Some(alarm1)));
(&ALARM2).lock(|data| (*data).replace(Some(alarm2)));
}
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::SYSTIMER_TARGET0,
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
);
Priority::Priority1,
).unwrap();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::SYSTIMER_TARGET1,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
Priority::Priority2,
).unwrap();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::SYSTIMER_TARGET2,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
Priority::Priority2,
).unwrap();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
unsafe {
xtensa_lx::interrupt::enable_mask(1 << 19 | 1 << 0 | 1 << 23);
}
loop {
delay.delay_ms(500u32);
}
}
#[no_mangle]
pub fn level1_interrupt() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt lvl1 (alarm0)").ok();
});
}
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
);
#[interrupt]
fn SYSTIMER_TARGET0() {
esp_println::println!("Interrupt lvl1 (alarm0)");
unsafe {
(&ALARM0).lock(|data| {
@ -126,20 +97,9 @@ pub fn level1_interrupt() {
}
}
#[no_mangle]
pub fn level2_interrupt() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt lvl2 (alarm1)").ok();
});
}
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
#[interrupt]
fn SYSTIMER_TARGET1() {
esp_println::println!("Interrupt lvl2 (alarm1)");
unsafe {
(&ALARM1).lock(|data| {
@ -150,20 +110,9 @@ pub fn level2_interrupt() {
}
}
#[no_mangle]
pub fn level3_interrupt() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt lvl3 (alarm2)").ok();
});
}
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
#[interrupt]
fn SYSTIMER_TARGET2() {
esp_println::println!("Interrupt lvl2 (alarm2)");
unsafe {
(&ALARM2).lock(|data| {

View File

@ -13,11 +13,10 @@ use esp32s2_hal::{
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
prelude::*,
timer::{Timer0, Timer1, TimerGroup},
Cpu,
RtcCntl,
Serial,
};
use esp_hal_common::Timer;
use esp_hal_common::{Priority, Timer};
use panic_halt as _;
use xtensa_lx::mutex::{CriticalSectionMutex, Mutex};
use xtensa_lx_rt::entry;
@ -58,31 +57,14 @@ fn main() -> ! {
wdt1.disable();
rtc_cntl.set_wdt_global_enable(false);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG0_T0_LEVEL,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG0_T1_LEVEL,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(pac::Interrupt::TG0_T0_LEVEL, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::TG0_T1_LEVEL, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::TG1_T0_LEVEL, Priority::Priority3).unwrap();
interrupt::enable(pac::Interrupt::TG1_T1_LEVEL, Priority::Priority3).unwrap();
timer00.start(500u64.millis());
timer00.listen();
timer01.start(2500u64.millis());
timer01.listen();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG1_T0_LEVEL,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG1_T1_LEVEL,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
timer10.start(1u64.secs());
timer10.listen();
timer11.start(3u64.secs());
@ -96,22 +78,11 @@ fn main() -> ! {
(&TIMER11).lock(|data| (*data).replace(Some(timer11)));
}
unsafe {
xtensa_lx::interrupt::disable();
xtensa_lx::interrupt::enable_mask(1 << 20);
xtensa_lx::interrupt::enable_mask(1 << 23);
}
loop {}
}
#[no_mangle]
pub fn level2_interrupt() {
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
#[interrupt]
fn TG0_T0_LEVEL() {
unsafe {
(&TIMER00).lock(|data| {
let mut timer = data.borrow_mut();
@ -128,7 +99,12 @@ pub fn level2_interrupt() {
});
}
});
}
}
#[interrupt]
fn TG0_T1_LEVEL() {
unsafe {
(&TIMER01).lock(|data| {
let mut timer = data.borrow_mut();
let timer = timer.as_mut().unwrap();
@ -147,13 +123,8 @@ pub fn level2_interrupt() {
}
}
#[no_mangle]
pub fn level3_interrupt() {
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
#[interrupt]
fn TG1_T0_LEVEL() {
unsafe {
(&TIMER10).lock(|data| {
let mut timer = data.borrow_mut();
@ -170,7 +141,12 @@ pub fn level3_interrupt() {
});
}
});
}
}
#[interrupt]
fn TG1_T1_LEVEL() {
unsafe {
(&TIMER11).lock(|data| {
let mut timer = data.borrow_mut();
let timer = timer.as_mut().unwrap();

View File

@ -7,10 +7,10 @@ pub use esp_hal_common::{
gpio as gpio_types,
i2c::{self, I2C},
interrupt,
macros,
pac,
prelude,
pulse_control,
ram,
serial,
spi,
systimer,

View File

@ -43,12 +43,13 @@ smart-leds = "0.3"
esp-println = { version = "0.2.0", features = ["esp32s3"] }
[features]
default = ["rt"]
default = ["rt", "vectored"]
direct-boot = ["r0"]
eh1 = ["esp-hal-common/eh1"]
rt = ["xtensa-lx-rt/esp32s3"]
smartled = ["esp-hal-common/smartled"]
ufmt = ["esp-hal-common/ufmt"]
vectored = ["esp-hal-common/vectored"]
[[example]]
name = "hello_rgb"

View File

@ -6,27 +6,24 @@
#![no_std]
#![no_main]
use core::{cell::RefCell, fmt::Write};
use core::cell::RefCell;
use esp32s3_hal::{
clock::ClockControl,
gpio::{Gpio0, IO},
gpio_types::{Event, Input, Pin, PullDown},
interrupt,
pac::{self, Peripherals, UART0},
macros::ram,
pac::{self, Peripherals},
prelude::*,
timer::TimerGroup,
Cpu,
Delay,
RtcCntl,
Serial,
};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;
static mut SERIAL: SpinLockMutex<RefCell<Option<Serial<UART0>>>> =
SpinLockMutex::new(RefCell::new(None));
static mut BUTTON: SpinLockMutex<RefCell<Option<Gpio0<Input<PullDown>>>>> =
SpinLockMutex::new(RefCell::new(None));
@ -38,29 +35,28 @@ fn main() -> ! {
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let serial0 = Serial::new(peripherals.UART0);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc_cntl.set_wdt_global_enable(false);
// Set GPIO4 as an output, and set its state high initially.
// Set GPIO15 as an output, and set its state high initially.
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio4.into_push_pull_output();
let mut led = io.pins.gpio15.into_push_pull_output();
let mut button = io.pins.gpio0.into_pull_down_input();
button.listen(Event::FallingEdge);
unsafe {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
(&BUTTON).lock(|data| (*data).replace(Some(button)));
}
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::GPIO,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
interrupt::vectored::Priority::Priority2,
)
.unwrap();
led.set_high().unwrap();
@ -68,32 +64,21 @@ fn main() -> ! {
// loop.
let mut delay = Delay::new(&clocks);
unsafe {
xtensa_lx::interrupt::enable_mask(1 << 19);
}
loop {
led.toggle().unwrap();
delay.delay_ms(500u32);
}
}
#[no_mangle]
pub fn level2_interrupt() {
#[ram]
#[interrupt]
fn GPIO() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt").ok();
});
}
esp_println::println!(
"GPIO Interrupt with priority {}",
xtensa_lx::interrupt::get_level()
);
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
unsafe {
(&BUTTON).lock(|data| {
let mut button = data.borrow_mut();
let button = button.as_mut().unwrap();

View File

@ -12,9 +12,9 @@ use core::fmt::Write;
use esp32s3_hal::{
clock::ClockControl,
macros::ram,
pac::{Peripherals, UART0},
prelude::*,
ram,
timer::TimerGroup,
Serial,
};

View File

@ -14,7 +14,6 @@ use esp32s3_hal::{
prelude::*,
serial::config::AtCmdConfig,
timer::TimerGroup,
Cpu,
RtcCntl,
Serial,
};
@ -53,11 +52,7 @@ fn main() -> ! {
serial0.listen_at_cmd();
serial0.listen_rx_fifo_full();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::UART0,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(pac::Interrupt::UART0, interrupt::Priority::Priority2).unwrap();
timer0.start(1u64.secs());
@ -65,11 +60,6 @@ fn main() -> ! {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
}
unsafe {
xtensa_lx::interrupt::disable();
xtensa_lx::interrupt::enable_mask(1 << 20);
}
loop {
unsafe {
(&SERIAL).lock(|data| {
@ -83,8 +73,8 @@ fn main() -> ! {
}
}
#[no_mangle]
pub fn level2_interrupt() {
#[interrupt]
fn UART0() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
@ -106,10 +96,6 @@ pub fn level2_interrupt() {
serial.reset_at_cmd_interrupt();
serial.reset_rx_fifo_full_interrupt();
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
});
}
}

View File

@ -4,26 +4,23 @@
#![no_std]
#![no_main]
use core::{cell::RefCell, fmt::Write};
use core::cell::RefCell;
use esp32s3_hal::{
clock::ClockControl,
interrupt,
pac::{self, Peripherals, UART0},
pac::{self, Peripherals},
prelude::*,
systimer::{Alarm, SystemTimer, Target},
timer::TimerGroup,
Cpu,
Delay,
interrupt::Priority,
RtcCntl,
Serial,
};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;
static mut SERIAL: SpinLockMutex<RefCell<Option<Serial<UART0>>>> =
SpinLockMutex::new(RefCell::new(None));
static mut ALARM0: SpinLockMutex<RefCell<Option<Alarm<Target, 0>>>> =
SpinLockMutex::new(RefCell::new(None));
static mut ALARM1: SpinLockMutex<RefCell<Option<Alarm<Target, 1>>>> =
@ -40,7 +37,6 @@ fn main() -> ! {
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
let serial0 = Serial::new(peripherals.UART0);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
@ -61,57 +57,36 @@ fn main() -> ! {
alarm2.enable_interrupt();
unsafe {
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
(&ALARM0).lock(|data| (*data).replace(Some(alarm0)));
(&ALARM1).lock(|data| (*data).replace(Some(alarm1)));
(&ALARM2).lock(|data| (*data).replace(Some(alarm2)));
}
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::SYSTIMER_TARGET0,
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
);
Priority::Priority1,
).unwrap();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::SYSTIMER_TARGET1,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
Priority::Priority2,
).unwrap();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::SYSTIMER_TARGET2,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
Priority::Priority2,
).unwrap();
// Initialize the Delay peripheral, and use it to toggle the LED state in a
// loop.
let mut delay = Delay::new(&clocks);
unsafe {
xtensa_lx::interrupt::enable_mask(1 << 19 | 1 << 0 | 1 << 23);
}
loop {
delay.delay_ms(500u32);
}
}
#[no_mangle]
pub fn level1_interrupt() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt lvl1 (alarm0)").ok();
});
}
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
);
#[interrupt]
fn SYSTIMER_TARGET0() {
esp_println::println!("Interrupt lvl1 (alarm0)");
unsafe {
(&ALARM0).lock(|data| {
@ -122,20 +97,9 @@ pub fn level1_interrupt() {
}
}
#[no_mangle]
pub fn level2_interrupt() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt lvl2 (alarm1)").ok();
});
}
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
);
#[interrupt]
fn SYSTIMER_TARGET1() {
esp_println::println!("Interrupt lvl2 (alarm1)");
unsafe {
(&ALARM1).lock(|data| {
@ -146,20 +110,9 @@ pub fn level2_interrupt() {
}
}
#[no_mangle]
pub fn level3_interrupt() {
unsafe {
(&SERIAL).lock(|data| {
let mut serial = data.borrow_mut();
let serial = serial.as_mut().unwrap();
writeln!(serial, "Interrupt lvl3 (alarm2)").ok();
});
}
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
#[interrupt]
fn SYSTIMER_TARGET2() {
esp_println::println!("Interrupt lvl2 (alarm2)");
unsafe {
(&ALARM2).lock(|data| {

View File

@ -13,11 +13,10 @@ use esp32s3_hal::{
pac::{self, Peripherals, TIMG0, TIMG1, UART0},
prelude::*,
timer::{Timer0, Timer1, TimerGroup},
Cpu,
RtcCntl,
Serial,
};
use esp_hal_common::Timer;
use esp_hal_common::{Priority, Timer};
use panic_halt as _;
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
use xtensa_lx_rt::entry;
@ -58,31 +57,14 @@ fn main() -> ! {
wdt1.disable();
rtc_cntl.set_wdt_global_enable(false);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG0_T0_LEVEL,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG0_T1_LEVEL,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
interrupt::enable(pac::Interrupt::TG0_T0_LEVEL, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::TG0_T1_LEVEL, Priority::Priority2).unwrap();
interrupt::enable(pac::Interrupt::TG1_T0_LEVEL, Priority::Priority3).unwrap();
interrupt::enable(pac::Interrupt::TG1_T1_LEVEL, Priority::Priority3).unwrap();
timer00.start(500u64.millis());
timer00.listen();
timer01.start(2500u64.millis());
timer01.listen();
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG1_T0_LEVEL,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
interrupt::enable(
Cpu::ProCpu,
pac::Interrupt::TG1_T1_LEVEL,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
timer10.start(1u64.secs());
timer10.listen();
timer11.start(3u64.secs());
@ -96,22 +78,11 @@ fn main() -> ! {
(&TIMER11).lock(|data| (*data).replace(Some(timer11)));
}
unsafe {
xtensa_lx::interrupt::disable();
xtensa_lx::interrupt::enable_mask(1 << 20);
xtensa_lx::interrupt::enable_mask(1 << 23);
}
loop {}
}
#[no_mangle]
pub fn level2_interrupt() {
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt20LevelPriority2,
);
#[interrupt]
fn TG0_T0_LEVEL() {
unsafe {
(&TIMER00).lock(|data| {
let mut timer = data.borrow_mut();
@ -128,7 +99,12 @@ pub fn level2_interrupt() {
});
}
});
}
}
#[interrupt]
fn TG0_T1_LEVEL() {
unsafe {
(&TIMER01).lock(|data| {
let mut timer = data.borrow_mut();
let timer = timer.as_mut().unwrap();
@ -147,13 +123,8 @@ pub fn level2_interrupt() {
}
}
#[no_mangle]
pub fn level3_interrupt() {
interrupt::clear(
Cpu::ProCpu,
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
);
#[interrupt]
fn TG1_T0_LEVEL() {
unsafe {
(&TIMER10).lock(|data| {
let mut timer = data.borrow_mut();
@ -170,7 +141,12 @@ pub fn level3_interrupt() {
});
}
});
}
}
#[interrupt]
fn TG1_T1_LEVEL() {
unsafe {
(&TIMER11).lock(|data| {
let mut timer = data.borrow_mut();
let timer = timer.as_mut().unwrap();

View File

@ -10,10 +10,10 @@ pub use esp_hal_common::{
gpio as gpio_types,
i2c,
interrupt,
macros,
pac,
prelude,
pulse_control,
ram,
serial,
spi,
systimer,