mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 12:50:53 +00:00
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:
parent
34b1e09662
commit
1789780d06
35
.github/workflows/ci.yml
vendored
35
.github/workflows/ci.yml
vendored
@ -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
17
.vscode/settings.json
vendored
@ -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",
|
||||
],
|
||||
}
|
||||
}
|
@ -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"]
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -60,3 +60,5 @@ pub mod eh1 {
|
||||
|
||||
pub use crate::system::SystemExt;
|
||||
}
|
||||
|
||||
pub use crate::macros::*;
|
||||
|
@ -22,3 +22,6 @@ proc-macro-error = "1.0.4"
|
||||
|
||||
[features]
|
||||
rtc_slow = []
|
||||
xtensa = []
|
||||
riscv = []
|
||||
interrupt = []
|
@ -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)
|
||||
}
|
||||
|
16
esp32-hal/.vscode/settings.json
vendored
16
esp32-hal/.vscode/settings.json
vendored
@ -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
|
||||
}
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -12,9 +12,9 @@ use core::fmt::Write;
|
||||
|
||||
use esp32_hal::{
|
||||
clock::ClockControl,
|
||||
macros::ram,
|
||||
pac::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
ram,
|
||||
timer::TimerGroup,
|
||||
Serial,
|
||||
};
|
||||
|
@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -8,10 +8,10 @@ pub use esp_hal_common::{
|
||||
gpio as gpio_types,
|
||||
i2c,
|
||||
interrupt,
|
||||
macros,
|
||||
pac,
|
||||
prelude,
|
||||
pulse_control,
|
||||
ram,
|
||||
serial,
|
||||
spi,
|
||||
timer,
|
||||
|
@ -12,9 +12,9 @@ use core::fmt::Write;
|
||||
|
||||
use esp32c3_hal::{
|
||||
clock::ClockControl,
|
||||
macros::ram,
|
||||
pac::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
ram,
|
||||
timer::TimerGroup,
|
||||
Serial,
|
||||
};
|
||||
|
@ -9,10 +9,10 @@ pub use esp_hal_common::{
|
||||
gpio as gpio_types,
|
||||
i2c,
|
||||
interrupt,
|
||||
macros,
|
||||
pac,
|
||||
prelude,
|
||||
pulse_control,
|
||||
ram,
|
||||
serial,
|
||||
spi,
|
||||
system,
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -12,9 +12,9 @@ use core::fmt::Write;
|
||||
|
||||
use esp32s2_hal::{
|
||||
clock::ClockControl,
|
||||
macros::ram,
|
||||
pac::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
ram,
|
||||
timer::TimerGroup,
|
||||
Serial,
|
||||
};
|
||||
|
@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -12,9 +12,9 @@ use core::fmt::Write;
|
||||
|
||||
use esp32s3_hal::{
|
||||
clock::ClockControl,
|
||||
macros::ram,
|
||||
pac::{Peripherals, UART0},
|
||||
prelude::*,
|
||||
ram,
|
||||
timer::TimerGroup,
|
||||
Serial,
|
||||
};
|
||||
|
@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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| {
|
||||
|
@ -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();
|
||||
|
@ -10,10 +10,10 @@ pub use esp_hal_common::{
|
||||
gpio as gpio_types,
|
||||
i2c,
|
||||
interrupt,
|
||||
macros,
|
||||
pac,
|
||||
prelude,
|
||||
pulse_control,
|
||||
ram,
|
||||
serial,
|
||||
spi,
|
||||
systimer,
|
||||
|
Loading…
x
Reference in New Issue
Block a user