From ea29a9b236103e3ff61dbe3dc55d20fbd1945186 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 22 Jun 2022 22:18:00 +0100 Subject: [PATCH 01/23] 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. --- esp-hal-common/Cargo.toml | 2 + esp-hal-common/src/interrupt/xtensa.rs | 184 +++++++++++++----- esp-hal-common/src/lib.rs | 12 +- esp-hal-common/src/prelude.rs | 2 + esp-hal-procmacros/src/lib.rs | 259 ++++++++++++++++++++++++- esp32-hal/examples/gpio_interrupt.rs | 14 +- esp32-hal/src/lib.rs | 3 +- 7 files changed, 419 insertions(+), 57 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index ad5559fb781..9877c4cb4b6 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -68,3 +68,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 = [] diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 76258b0de8f..30dd2e32541 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -1,16 +1,10 @@ +use xtensa_lx::interrupt::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 @@ -174,44 +168,146 @@ 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")] +mod vectored { + use super::*; -#[no_mangle] -#[link_section = ".rwtext"] -fn __level_2_interrupt(_level: u32, save_frame: &mut Context) { - unsafe { level2_interrupt(save_frame) }; -} + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_1_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } -#[no_mangle] -#[link_section = ".rwtext"] -fn __level_3_interrupt(_level: u32, save_frame: &mut Context) { - unsafe { level3_interrupt(save_frame) }; -} + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_2_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } -#[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"] + unsafe fn __level_3_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } -#[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"] + unsafe fn __level_4_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } -#[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"] + unsafe fn __level_5_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } + + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_6_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } + + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_7_interrupt(level: u32, _save_frame: &mut Context) { + handle_interrupts(level) + } + + // /// Stores what interrupts are enabled at each interrupt level + // static mut INTERRUPT_LEVELS: [u128; 8] = [0u128; 8]; + + unsafe fn handle_interrupts(level: u32) { + // TODO check if its a CPU interrupt + // TODO check if its an edge interrupt + // CPU & EDGE interrupts were declared inside the pac on the old esp32 + // crates, but I think we should define them with extern "C" + // inside this crate, e.g + // + // extern "C" { + // fn Timer0(); + // } + + // finally check periperal sources and fire of handlers from pac + let interrupt_mask = get_status(crate::get_core()); // & INTERRUPT_LEVELS[level as usize] // TODO priority + 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); + } + // peripheral mapped interrupts are cleared by the peripheral + } + + unsafe fn handle_interrupt(level: u32, interrupt: Interrupt) { + extern "C" { + // defined in xtensa_lx_rt + 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 { + handler(); + } + } } -#[no_mangle] -#[link_section = ".rwtext"] -fn __level_7_interrupt(_level: u32, save_frame: &mut Context) { - unsafe { level7_interrupt(save_frame) }; +#[cfg(not(feature = "vectored"))] +mod raw { + use super::*; + + 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); + } + + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_1_interrupt(_level: u32, save_frame: &mut Context) { + level1_interrupt(save_frame) + } + + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_2_interrupt(_level: u32, save_frame: &mut Context) { + level2_interrupt(save_frame) + } + + #[no_mangle] + #[link_section = ".rwtext"] + unsafe fn __level_3_interrupt(_level: u32, save_frame: &mut Context) { + level3_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) + } } diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 2f024723c62..8d05437a28d 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -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,13 @@ pub enum Cpu { /// The second core AppCpu, } + +pub fn get_core() -> Cpu { + #[cfg(target_arch = "xtensa")] + match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 { + false => Cpu::ProCpu, + true => Cpu::AppCpu, + } + #[cfg(target_arch = "riscv")] // TODO get hart_id + Cpu::ProCpu +} diff --git a/esp-hal-common/src/prelude.rs b/esp-hal-common/src/prelude.rs index 7878557c14e..7d29d73eff8 100644 --- a/esp-hal-common/src/prelude.rs +++ b/esp-hal-common/src/prelude.rs @@ -60,3 +60,5 @@ pub mod eh1 { pub use crate::system::SystemExt; } + +pub use crate::macros::*; diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index cdc8213d2a2..c88c80c671b 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -1,8 +1,27 @@ +use std::{collections::HashSet, iter}; + use darling::FromMeta; use proc_macro::{self, Span, TokenStream}; use proc_macro_error::{abort, proc_macro_error}; use quote::quote; -use syn::{parse_macro_input, AttributeArgs}; +use syn::{ + parse, + parse_macro_input, + spanned::Spanned, + AttrStyle, + Attribute, + AttributeArgs, + FnArg, + Ident, + Item, + ItemFn, + ItemStatic, + Meta::Path, + ReturnType, + Stmt, + Type, + Visibility, +}; #[derive(Debug, Default, FromMeta)] #[darling(default)] @@ -88,3 +107,241 @@ 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. +#[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.inputs.is_empty() + && 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, + }, + }; + + if !valid_signature { + return parse::Error::new( + f.span(), + "`#[interrupt]` handlers must have signature `[unsafe] fn() [-> !]`", + ) + .to_compile_error() + .into(); + } + + let (statics, stmts) = match extract_static_muts(f.block.stmts.iter().cloned()) { + Err(e) => return e.to_compile_error().into(), + Ok(x) => x, + }; + + f.sig.ident = Ident::new( + &format!("__xtensa_lx_6_{}", f.sig.ident), + proc_macro2::Span::call_site(), + ); + f.sig.inputs.extend(statics.iter().map(|statik| { + let ident = &statik.ident; + let ty = &statik.ty; + let attrs = &statik.attrs; + syn::parse::(quote!(#[allow(non_snake_case)] #(#attrs)* #ident: &mut #ty).into()) + .unwrap() + })); + f.block.stmts = iter::once( + syn::parse2(quote! {{ + // Check that this interrupt actually exists + crate::pac::Interrupt::#ident_s; + }}) + .unwrap(), + ) + .chain(stmts) + .collect(); + + let tramp_ident = Ident::new( + &format!("{}_trampoline", f.sig.ident), + proc_macro2::Span::call_site(), + ); + let ident = &f.sig.ident; + + let resource_args = statics + .iter() + .map(|statik| { + let (ref cfgs, ref attrs) = extract_cfgs(statik.attrs.clone()); + let ident = &statik.ident; + let ty = &statik.ty; + let expr = &statik.expr; + quote! { + #(#cfgs)* + { + #(#attrs)* + static mut #ident: #ty = #expr; + &mut #ident + } + } + }) + .collect::>(); + + let (ref cfgs, ref attrs) = extract_cfgs(f.attrs.clone()); + + let export_name = ident_s.to_string(); + + quote!( + #(#cfgs)* + #(#attrs)* + #[doc(hidden)] + #[export_name = #export_name] + pub unsafe extern "C" fn #tramp_ident() { + #ident( + #(#resource_args),* + ) + } + + #[inline(always)] + #f + ) + .into() +} + +enum WhiteListCaller { + Interrupt, +} + +fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result<(), TokenStream> { + let whitelist = &[ + "doc", + "link_section", + "cfg", + "allow", + "warn", + "deny", + "forbid", + "cold", + "ram", + ]; + + '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 esp32_hal" + } + }; + + return Err(parse::Error::new(attr.span(), &err_str) + .to_compile_error() + .into()); + } + + Ok(()) +} + +/// Returns `true` if `attr.path` matches `name` +fn eq(attr: &Attribute, name: &str) -> bool { + attr.style == AttrStyle::Outer && attr.path.is_ident(name) +} + +fn extract_cfgs(attrs: Vec) -> (Vec, Vec) { + 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) +} + +/// Extracts `static mut` vars from the beginning of the given statements +fn extract_static_muts( + stmts: impl IntoIterator, +) -> Result<(Vec, Vec), parse::Error> { + let mut istmts = stmts.into_iter(); + + let mut seen = HashSet::new(); + let mut statics = vec![]; + let mut stmts = vec![]; + while let Some(stmt) = istmts.next() { + match stmt { + Stmt::Item(Item::Static(var)) => { + if var.mutability.is_some() { + if seen.contains(&var.ident) { + return Err(parse::Error::new( + var.ident.span(), + format!("the name `{}` is defined multiple times", var.ident), + )); + } + + seen.insert(var.ident.clone()); + statics.push(var); + } else { + stmts.push(Stmt::Item(Item::Static(var))); + } + } + _ => { + stmts.push(stmt); + break; + } + } + } + + stmts.extend(istmts); + + Ok((statics, stmts)) +} diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index c0dfd194d33..1e06efe364e 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -43,6 +43,9 @@ fn main() -> ! { let serial0 = Serial::new(peripherals.UART0); let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); + writeln!(serial0, "Hello world!").ok(); + esp_println::println!("Hello esp_println!"); + // Disable MWDT and RWDT (Watchdog) flash boot protection wdt.disable(); rtc_cntl.set_wdt_global_enable(false); @@ -80,22 +83,15 @@ fn main() -> ! { } } -#[no_mangle] -pub fn level1_interrupt() { +#[interrupt] +fn GPIO() { unsafe { (&SERIAL).lock(|data| { let mut serial = data.borrow_mut(); let serial = serial.as_mut().unwrap(); writeln!(serial, "Interrupt").ok(); }); - } - interrupt::clear( - Cpu::ProCpu, - interrupt::CpuInterrupt::Interrupt1LevelPriority1, - ); - - unsafe { (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); let button = button.as_mut().unwrap(); diff --git a/esp32-hal/src/lib.rs b/esp32-hal/src/lib.rs index f6eda61d69e..31bc23ae5e2 100644 --- a/esp32-hal/src/lib.rs +++ b/esp32-hal/src/lib.rs @@ -11,9 +11,8 @@ pub use esp_hal_common::{ pac, prelude, pulse_control, - ram, - serial, spi, + serial, timer, utils, Cpu, From a450214c90c0011c0648773cdd33b184247c3aa8 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 23 Jun 2022 12:16:14 +0100 Subject: [PATCH 02/23] Xtensa interrupt vectoring: CPU & EDGE - Add support for handling CPU interrupts and edge interrupts - PR required to xtensa-lx-rt for CPU handlers --- esp-hal-common/src/interrupt/xtensa.rs | 129 +++++++++++++++++++++---- 1 file changed, 110 insertions(+), 19 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 30dd2e32541..a179ec22375 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -1,4 +1,4 @@ -use xtensa_lx::interrupt::InterruptNumber; +use xtensa_lx::interrupt::{self, InterruptNumber}; use xtensa_lx_rt::exception::Context; use crate::{ @@ -172,6 +172,70 @@ unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::Re mod vectored { use super::*; + // 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; + + fn cpu_interrupt_nr_to_handler(_number: u32) -> Option { + // TODO this needs be in a xtensa_lx with a default impl! Like arm + // extern "C" { + // fn Timer0(); + // fn Timer1(); + // fn Timer2(); + + // fn Profiling(); + + // fn SoftwareLevel1(); + // fn SoftwareLevel3(); + + // fn NMI(); + // } + + // match number { + // 6 => Timer0, + // 7 => SoftwareLevel1, + // 11 => Profiling, + // 14 => NMI, + // 15 => Timer1, + // 16 => Timer2, + // 29 => SoftwareLevel3, + // _ => return None; + // } + + unsafe extern "C" fn nop() {} + + Some(nop) + } + + // TODO this will be chip specific - this only handles esp32 + 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; + // TODO this will be chip specific - this only handles esp32 + // 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) + // } + #[no_mangle] #[link_section = ".rwtext"] unsafe fn __level_1_interrupt(level: u32, _save_frame: &mut Context) { @@ -218,31 +282,58 @@ mod vectored { // static mut INTERRUPT_LEVELS: [u128; 8] = [0u128; 8]; unsafe fn handle_interrupts(level: u32) { - // TODO check if its a CPU interrupt - // TODO check if its an edge interrupt - // CPU & EDGE interrupts were declared inside the pac on the old esp32 - // crates, but I think we should define them with extern "C" - // inside this crate, e.g - // - // extern "C" { - // fn Timer0(); - // } + let cpu_interrupt_mask = + interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[level as usize]; - // finally check periperal sources and fire of handlers from pac - let interrupt_mask = get_status(crate::get_core()); // & INTERRUPT_LEVELS[level as usize] // TODO priority - let interrupt_nr = interrupt_mask.trailing_zeros(); + 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(); - // 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); + if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 { + interrupt::clear(1 << cpu_interrupt_nr); + } + if let Some(handler) = cpu_interrupt_nr_to_handler(cpu_interrupt_nr) { + handler(); + } + } else { + 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] & INTERRUPT_EDGE; + // // TODO priority + let mut interrupt_mask = 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) + } 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] // TODO priority + 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); + } + } } - // peripheral mapped interrupts are cleared by the peripheral } unsafe fn handle_interrupt(level: u32, interrupt: Interrupt) { extern "C" { - // defined in xtensa_lx_rt + // defined in each hal fn DefaultHandler(level: u32, interrupt: Interrupt); } From 004659d0a0595754a339b45059927fed9c3afe79 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 23 Jun 2022 22:17:18 +0100 Subject: [PATCH 03/23] 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 --- .vscode/settings.json | 17 +-- esp-hal-common/src/interrupt/xtensa.rs | 148 ++++++++++++++++++++----- esp32-hal/examples/gpio_interrupt.rs | 22 +--- 3 files changed, 129 insertions(+), 58 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7bb978cce08..f7586734f6f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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", ], -} +} \ No newline at end of file diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index a179ec22375..e077f6d8717 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -10,6 +10,7 @@ use crate::{ /// It's possible to create one handler per priority level. (e.g /// `level1_interrupt`) #[allow(unused)] +#[derive(Debug, Copy, Clone)] pub enum CpuInterrupt { Interrupt0LevelPriority1 = 0, Interrupt1LevelPriority1, @@ -169,9 +170,97 @@ unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::Re } #[cfg(feature = "vectored")] -mod vectored { +pub mod vectored { use super::*; + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum Error { + InvalidInterrupt, + } + + /// Interrupt priority levels. + #[derive(Copy, Clone, Debug, PartialEq, Eq)] + pub enum Priority { + None = 0, + Priority1, + Priority2, + Priority3, + // TODO the following priorities are 'unusable' due to the value in PS_INTLEVEL_EXCM + // defined in xtensa_lx_rt Xtensa programmer guide indicates we _can_ implement + // high level interrupts in Rust, but they recommend we dont (however their reasoning + // seemed to indicate interference with rtos') + // + // Another suggestion from Xtensa programmers guide: + // Alternatively, a level-one interrupt can also be used instead (with software + // prioritization if needed) but I have no idea what software prioritization would + // look like in this context. + + // Priority4, + // Priority5, + // Priority6, + } + + /// Stores what interrupts are enabled at each interrupt level + static mut INTERRUPT_LEVELS: [u128; 8] = [0u128; 8]; + + /// A priority of None, disables the interrupt + pub fn enable_with_priority( + core: crate::Cpu, + interrupt: Interrupt, + level: Priority, + ) -> Result<(), Error> { + let cpu_interrupt = + interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; + + // (&INTERRUPT_LEVELS_MUTEX).lock(|_| unsafe { + // TODO: CS here + unsafe { + for i in 0..=7 { + INTERRUPT_LEVELS[i] &= !(1 << interrupt.number()); + } + INTERRUPT_LEVELS[level as usize] |= 1 << interrupt.number(); + + enable(core, interrupt, cpu_interrupt); + + xtensa_lx::interrupt::enable_mask( + xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, + ); + } + Ok(()) + // }) + } + + // TODO mention that theses interrupts are reservered in vector mode + // TODO make the normal `enable` unsafe? Would break vectoring unless careful + fn interrupt_level_to_cpu_interrupt( + level: Priority, + is_edge: bool, + ) -> Result { + 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, + // Priority::Priority4 => CpuInterrupt::Interrupt28EdgePriority4, + // Priority::Priority5 => CpuInterrupt::Interrupt31EdgePriority5, + // Priority::Priority6 => return Err(Error::InvalidInterrupt), + // Priority::Priority7 => CpuInterrupt::Interrupt14NmiPriority7, + } + } else { + match level { + Priority::None => return Err(Error::InvalidInterrupt), + Priority::Priority1 => CpuInterrupt::Interrupt1LevelPriority1, + Priority::Priority2 => CpuInterrupt::Interrupt19LevelPriority2, + Priority::Priority3 => CpuInterrupt::Interrupt23LevelPriority3, + // Priority::Priority4 => CpuInterrupt::Interrupt24LevelPriority4, + // Priority::Priority5 => CpuInterrupt::Interrupt26LevelPriority5, + // Priority::Priority6 => return Err(Error::InvalidInterrupt), + // Priority::Priority7 => CpuInterrupt::Interrupt14NmiPriority7, + } + }) + } + // 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 @@ -186,8 +275,8 @@ mod vectored { 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; - fn cpu_interrupt_nr_to_handler(_number: u32) -> Option { - // TODO this needs be in a xtensa_lx with a default impl! Like arm + fn cpu_interrupt_nr_to_cpu_interrupt_handler(_number: u32) -> Option { + // TODO this needs be in a xtensa_lx with a default impl! Like cortex-m crates // extern "C" { // fn Timer0(); // fn Timer1(); @@ -217,25 +306,6 @@ mod vectored { Some(nop) } - // TODO this will be chip specific - this only handles esp32 - 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; - // TODO this will be chip specific - this only handles esp32 - // 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) - // } - #[no_mangle] #[link_section = ".rwtext"] unsafe fn __level_1_interrupt(level: u32, _save_frame: &mut Context) { @@ -278,9 +348,6 @@ mod vectored { handle_interrupts(level) } - // /// Stores what interrupts are enabled at each interrupt level - // static mut INTERRUPT_LEVELS: [u128; 8] = [0u128; 8]; - unsafe fn handle_interrupts(level: u32) { let cpu_interrupt_mask = interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[level as usize]; @@ -292,7 +359,7 @@ mod vectored { if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 { interrupt::clear(1 << cpu_interrupt_nr); } - if let Some(handler) = cpu_interrupt_nr_to_handler(cpu_interrupt_nr) { + if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) { handler(); } } else { @@ -304,9 +371,8 @@ mod vectored { // 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] & INTERRUPT_EDGE; - // // TODO priority - let mut interrupt_mask = INTERRUPT_EDGE; + 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) { @@ -319,7 +385,8 @@ mod vectored { } 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] // TODO priority + 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: @@ -344,6 +411,27 @@ mod vectored { handler(); } } + + #[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; + 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(not(feature = "vectored"))] diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 1e06efe364e..27bc8df08a2 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -6,27 +6,26 @@ #![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}, + pac::{self, Peripherals}, prelude::*, timer::TimerGroup, Cpu, Delay, RtcCntl, Serial, + Timer, }; use panic_halt as _; use xtensa_lx::mutex::{Mutex, SpinLockMutex}; use xtensa_lx_rt::entry; -static mut SERIAL: SpinLockMutex>>> = - SpinLockMutex::new(RefCell::new(None)); static mut BUTTON: SpinLockMutex>>>> = SpinLockMutex::new(RefCell::new(None)); @@ -43,7 +42,6 @@ fn main() -> ! { let serial0 = Serial::new(peripherals.UART0); let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); - writeln!(serial0, "Hello world!").ok(); esp_println::println!("Hello esp_println!"); // Disable MWDT and RWDT (Watchdog) flash boot protection @@ -57,15 +55,10 @@ 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::enable_with_priority(Cpu::ProCpu, pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority3).unwrap(); led.set_high().unwrap(); @@ -78,6 +71,7 @@ fn main() -> ! { } loop { + esp_println::println!("Interrupt - INTLEVEL: {}", xtensa_lx::interrupt::get_level()); led.toggle().unwrap(); delay.delay_ms(500u32); } @@ -86,11 +80,7 @@ fn main() -> ! { #[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"); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); From 465b2d36d79d29f4d21d1109a5b3a3722cd6738c Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 14:37:49 +0100 Subject: [PATCH 04/23] support CPU interrupts, using patch xtensa-lx-rt --- esp-hal-common/Cargo.toml | 3 ++ esp-hal-common/src/interrupt/xtensa.rs | 43 ++++++++------------------ esp32-hal/Cargo.toml | 3 ++ 3 files changed, 19 insertions(+), 30 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 9877c4cb4b6..2e4234ee5ed 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -46,6 +46,9 @@ esp32c3_pac = { package = "esp32c3", git = "https://github.com/esp-rs/esp-pacs.g 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 } +[patch.crates-io] +xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } + [features] esp32 = [ "esp32_pac/rt", "xtensa", "dual_core", "xtensa-lx-rt/esp32", "xtensa-lx/esp32"] esp32c3 = ["esp32c3_pac/rt", "risc_v", "single_core"] diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index e077f6d8717..df89a3aa68c 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -275,35 +275,18 @@ pub mod vectored { 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; - fn cpu_interrupt_nr_to_cpu_interrupt_handler(_number: u32) -> Option { - // TODO this needs be in a xtensa_lx with a default impl! Like cortex-m crates - // extern "C" { - // fn Timer0(); - // fn Timer1(); - // fn Timer2(); - - // fn Profiling(); - - // fn SoftwareLevel1(); - // fn SoftwareLevel3(); - - // fn NMI(); - // } - - // match number { - // 6 => Timer0, - // 7 => SoftwareLevel1, - // 11 => Profiling, - // 14 => NMI, - // 15 => Timer1, - // 16 => Timer2, - // 29 => SoftwareLevel3, - // _ => return None; - // } - - unsafe extern "C" fn nop() {} - - Some(nop) + fn cpu_interrupt_nr_to_cpu_interrupt_handler(number: u32) -> Option { + use xtensa_lx_rt::*; + Some(match number { + 6 => Timer0, + 7 => Software0, + 11 => Profiling, + 14 => NMI, + 15 => Timer1, + 16 => Timer2, + 29 => Software1, + _ => return None, + }) } #[no_mangle] @@ -360,7 +343,7 @@ pub mod vectored { interrupt::clear(1 << cpu_interrupt_nr); } if let Some(handler) = cpu_interrupt_nr_to_cpu_interrupt_handler(cpu_interrupt_nr) { - handler(); + handler(level); } } else { if (cpu_interrupt_mask & CPU_INTERRUPT_EDGE) != 0 { diff --git a/esp32-hal/Cargo.toml b/esp32-hal/Cargo.toml index 7075b4cdc02..14262758479 100644 --- a/esp32-hal/Cargo.toml +++ b/esp32-hal/Cargo.toml @@ -31,6 +31,9 @@ xtensa-lx = { version = "0.7", features = ["esp32"] } xtensa-lx-rt = { version = "0.13", features = ["esp32"], optional = true } nb = "1.0.0" +[patch.crates-io] +xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } + [dependencies.esp-hal-common] path = "../esp-hal-common" features = ["esp32"] From f677dd4019850af1ed9d0b23db11634fa0e091a9 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 14:46:36 +0100 Subject: [PATCH 05/23] Update example --- esp32-hal/examples/gpio_interrupt.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 27bc8df08a2..cb868ed821b 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -66,12 +66,7 @@ fn main() -> ! { // loop. let mut delay = Delay::new(&clocks); - unsafe { - xtensa_lx::interrupt::enable_mask(1 << 1); - } - loop { - esp_println::println!("Interrupt - INTLEVEL: {}", xtensa_lx::interrupt::get_level()); led.toggle().unwrap(); delay.delay_ms(500u32); } @@ -80,7 +75,7 @@ fn main() -> ! { #[interrupt] fn GPIO() { unsafe { - esp_println::println!("GPIO Interrupt"); + esp_println::println!("GPIO Interrupt with priority {}", xtensa_lx::interrupt::get_level()); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); From 46b3591d04d055f2c516e7f5e40ad8aa11da2741 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 15:19:26 +0100 Subject: [PATCH 06/23] Add support & examples for the s2 & s3 too --- esp-hal-common/src/interrupt/xtensa.rs | 30 ++++++++++++++++++ esp32s2-hal/Cargo.toml | 3 ++ esp32s2-hal/examples/gpio_interrupt.rs | 44 +++++++------------------- esp32s2-hal/src/lib.rs | 3 +- esp32s3-hal/Cargo.toml | 3 ++ esp32s3-hal/examples/gpio_interrupt.rs | 42 +++++++----------------- esp32s3-hal/src/lib.rs | 3 +- 7 files changed, 61 insertions(+), 67 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index df89a3aa68c..eef4b00a808 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -415,6 +415,36 @@ pub mod vectored { .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; + 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; + pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool { + false + } + } } #[cfg(not(feature = "vectored"))] diff --git a/esp32s2-hal/Cargo.toml b/esp32s2-hal/Cargo.toml index 8b71e9ec0fb..0eea2840cd3 100644 --- a/esp32s2-hal/Cargo.toml +++ b/esp32s2-hal/Cargo.toml @@ -34,6 +34,9 @@ xtensa-lx-rt = { version = "0.13", features = ["esp32s2"], optional = true } path = "../esp-hal-common" features = ["esp32s2"] +[patch.crates-io] +xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } + [dev-dependencies] embedded-graphics = "0.7" panic-halt = "0.2" diff --git a/esp32s2-hal/examples/gpio_interrupt.rs b/esp32s2-hal/examples/gpio_interrupt.rs index cc251dfd4dc..f6f34b0719c 100644 --- a/esp32s2-hal/examples/gpio_interrupt.rs +++ b/esp32s2-hal/examples/gpio_interrupt.rs @@ -6,27 +6,26 @@ #![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}, + pac::{self, Peripherals}, prelude::*, timer::TimerGroup, Cpu, Delay, RtcCntl, Serial, + Timer }; 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>>> = - CriticalSectionMutex::new(RefCell::new(None)); static mut BUTTON: CriticalSectionMutex>>>> = CriticalSectionMutex::new(RefCell::new(None)); @@ -39,28 +38,24 @@ 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); + + esp_println::println!("Hello esp_println!"); // 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::enable_with_priority(Cpu::ProCpu, pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority3).unwrap(); led.set_high().unwrap(); @@ -68,32 +63,17 @@ 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() { +#[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(); diff --git a/esp32s2-hal/src/lib.rs b/esp32s2-hal/src/lib.rs index d5769dcd75b..267d49ede4a 100644 --- a/esp32s2-hal/src/lib.rs +++ b/esp32s2-hal/src/lib.rs @@ -10,9 +10,8 @@ pub use esp_hal_common::{ pac, prelude, pulse_control, - ram, - serial, spi, + serial, systimer, timer, utils, diff --git a/esp32s3-hal/Cargo.toml b/esp32s3-hal/Cargo.toml index 7992159b423..4cda97d621e 100644 --- a/esp32s3-hal/Cargo.toml +++ b/esp32s3-hal/Cargo.toml @@ -35,6 +35,9 @@ r0 = { version = "1.0", optional = true } path = "../esp-hal-common" features = ["esp32s3"] +[patch.crates-io] +xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } + [dev-dependencies] embedded-graphics = "0.7" panic-halt = "0.2" diff --git a/esp32s3-hal/examples/gpio_interrupt.rs b/esp32s3-hal/examples/gpio_interrupt.rs index 223d8eb5b68..c6ae88ac8b5 100644 --- a/esp32s3-hal/examples/gpio_interrupt.rs +++ b/esp32s3-hal/examples/gpio_interrupt.rs @@ -6,27 +6,26 @@ #![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}, + pac::{self, Peripherals}, prelude::*, timer::TimerGroup, Cpu, Delay, RtcCntl, Serial, + Timer, }; use panic_halt as _; use xtensa_lx::mutex::{Mutex, SpinLockMutex}; use xtensa_lx_rt::entry; -static mut SERIAL: SpinLockMutex>>> = - SpinLockMutex::new(RefCell::new(None)); static mut BUTTON: SpinLockMutex>>>> = SpinLockMutex::new(RefCell::new(None)); @@ -39,28 +38,24 @@ 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); + + esp_println::println!("Hello esp_println!"); // 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::enable_with_priority(Cpu::ProCpu, pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority3).unwrap(); led.set_high().unwrap(); @@ -68,32 +63,17 @@ 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() { +#[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(); diff --git a/esp32s3-hal/src/lib.rs b/esp32s3-hal/src/lib.rs index c758b98ee3c..a33c4a8e2d3 100644 --- a/esp32s3-hal/src/lib.rs +++ b/esp32s3-hal/src/lib.rs @@ -13,9 +13,8 @@ pub use esp_hal_common::{ pac, prelude, pulse_control, - ram, - serial, spi, + serial, systimer, timer, usb_serial_jtag, From 6fa4af8d5ad9e1be107ad78b2aaecca4c104751f Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 15:25:56 +0100 Subject: [PATCH 07/23] Fix formatting and missing imports --- esp32-hal/examples/gpio_interrupt.rs | 12 ++++++++++-- esp32-hal/examples/ram.rs | 2 +- esp32-hal/src/lib.rs | 1 + esp32s2-hal/examples/gpio_interrupt.rs | 14 +++++++++++--- esp32s2-hal/examples/ram.rs | 2 +- esp32s2-hal/src/lib.rs | 1 + esp32s3-hal/examples/gpio_interrupt.rs | 12 ++++++++++-- esp32s3-hal/examples/ram.rs | 2 +- esp32s3-hal/src/lib.rs | 1 + 9 files changed, 37 insertions(+), 10 deletions(-) diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index cb868ed821b..0c40f61978b 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -58,7 +58,12 @@ fn main() -> ! { (&BUTTON).lock(|data| (*data).replace(Some(button))); } - interrupt::vectored::enable_with_priority(Cpu::ProCpu, pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority3).unwrap(); + interrupt::vectored::enable_with_priority( + Cpu::ProCpu, + pac::Interrupt::GPIO, + interrupt::vectored::Priority::Priority3, + ) + .unwrap(); led.set_high().unwrap(); @@ -75,7 +80,10 @@ fn main() -> ! { #[interrupt] fn GPIO() { unsafe { - esp_println::println!("GPIO Interrupt with priority {}", xtensa_lx::interrupt::get_level()); + esp_println::println!( + "GPIO Interrupt with priority {}", + xtensa_lx::interrupt::get_level() + ); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); diff --git a/esp32-hal/examples/ram.rs b/esp32-hal/examples/ram.rs index e96bbd8e18a..1a89c8414cd 100644 --- a/esp32-hal/examples/ram.rs +++ b/esp32-hal/examples/ram.rs @@ -12,9 +12,9 @@ use core::fmt::Write; use esp32_hal::{ clock::ClockControl, + macros::ram, pac::{Peripherals, UART0}, prelude::*, - ram, timer::TimerGroup, Serial, }; diff --git a/esp32-hal/src/lib.rs b/esp32-hal/src/lib.rs index 31bc23ae5e2..251cd0937a1 100644 --- a/esp32-hal/src/lib.rs +++ b/esp32-hal/src/lib.rs @@ -8,6 +8,7 @@ pub use esp_hal_common::{ gpio as gpio_types, i2c, interrupt, + macros, pac, prelude, pulse_control, diff --git a/esp32s2-hal/examples/gpio_interrupt.rs b/esp32s2-hal/examples/gpio_interrupt.rs index f6f34b0719c..fbe9e5b7064 100644 --- a/esp32s2-hal/examples/gpio_interrupt.rs +++ b/esp32s2-hal/examples/gpio_interrupt.rs @@ -23,7 +23,7 @@ use esp32s2_hal::{ Timer }; use panic_halt as _; -use xtensa_lx::mutex::{Mutex, CriticalSectionMutex}; +use xtensa_lx::mutex::{CriticalSectionMutex, Mutex}; use xtensa_lx_rt::entry; static mut BUTTON: CriticalSectionMutex>>>> = @@ -55,7 +55,12 @@ fn main() -> ! { (&BUTTON).lock(|data| (*data).replace(Some(button))); } - interrupt::vectored::enable_with_priority(Cpu::ProCpu, pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority3).unwrap(); + interrupt::vectored::enable_with_priority( + Cpu::ProCpu, + pac::Interrupt::GPIO, + interrupt::vectored::Priority::Priority3, + ) + .unwrap(); led.set_high().unwrap(); @@ -72,7 +77,10 @@ fn main() -> ! { #[interrupt] fn GPIO() { unsafe { - esp_println::println!("GPIO Interrupt with priority {}", xtensa_lx::interrupt::get_level()); + esp_println::println!( + "GPIO Interrupt with priority {}", + xtensa_lx::interrupt::get_level() + ); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); diff --git a/esp32s2-hal/examples/ram.rs b/esp32s2-hal/examples/ram.rs index 9f864e72a72..943839dc8a2 100644 --- a/esp32s2-hal/examples/ram.rs +++ b/esp32s2-hal/examples/ram.rs @@ -12,9 +12,9 @@ use core::fmt::Write; use esp32s2_hal::{ clock::ClockControl, + macros::ram, pac::{Peripherals, UART0}, prelude::*, - ram, timer::TimerGroup, Serial, }; diff --git a/esp32s2-hal/src/lib.rs b/esp32s2-hal/src/lib.rs index 267d49ede4a..faa8b7ea2fb 100644 --- a/esp32s2-hal/src/lib.rs +++ b/esp32s2-hal/src/lib.rs @@ -7,6 +7,7 @@ pub use esp_hal_common::{ gpio as gpio_types, i2c::{self, I2C}, interrupt, + macros, pac, prelude, pulse_control, diff --git a/esp32s3-hal/examples/gpio_interrupt.rs b/esp32s3-hal/examples/gpio_interrupt.rs index c6ae88ac8b5..2210b0b9e31 100644 --- a/esp32s3-hal/examples/gpio_interrupt.rs +++ b/esp32s3-hal/examples/gpio_interrupt.rs @@ -55,7 +55,12 @@ fn main() -> ! { (&BUTTON).lock(|data| (*data).replace(Some(button))); } - interrupt::vectored::enable_with_priority(Cpu::ProCpu, pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority3).unwrap(); + interrupt::vectored::enable_with_priority( + Cpu::ProCpu, + pac::Interrupt::GPIO, + interrupt::vectored::Priority::Priority3, + ) + .unwrap(); led.set_high().unwrap(); @@ -72,7 +77,10 @@ fn main() -> ! { #[interrupt] fn GPIO() { unsafe { - esp_println::println!("GPIO Interrupt with priority {}", xtensa_lx::interrupt::get_level()); + esp_println::println!( + "GPIO Interrupt with priority {}", + xtensa_lx::interrupt::get_level() + ); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); diff --git a/esp32s3-hal/examples/ram.rs b/esp32s3-hal/examples/ram.rs index 1d1f77f17c4..97f828dd560 100644 --- a/esp32s3-hal/examples/ram.rs +++ b/esp32s3-hal/examples/ram.rs @@ -12,9 +12,9 @@ use core::fmt::Write; use esp32s3_hal::{ clock::ClockControl, + macros::ram, pac::{Peripherals, UART0}, prelude::*, - ram, timer::TimerGroup, Serial, }; diff --git a/esp32s3-hal/src/lib.rs b/esp32s3-hal/src/lib.rs index a33c4a8e2d3..ab5691fec84 100644 --- a/esp32s3-hal/src/lib.rs +++ b/esp32s3-hal/src/lib.rs @@ -10,6 +10,7 @@ pub use esp_hal_common::{ gpio as gpio_types, i2c, interrupt, + macros, pac, prelude, pulse_control, From 9a516d1cefb5f9168542e48971d39bf9599948b1 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 15:48:58 +0100 Subject: [PATCH 08/23] Run interrupt handling in ram, optionally run the vector handler in ram in the examples --- esp-hal-common/src/interrupt/xtensa.rs | 7 +++++++ esp-hal-procmacros/src/lib.rs | 3 ++- esp32-hal/examples/gpio_interrupt.rs | 2 ++ esp32s2-hal/examples/gpio_interrupt.rs | 2 ++ esp32s3-hal/examples/gpio_interrupt.rs | 2 ++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index eef4b00a808..f17ccfe60aa 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -171,6 +171,8 @@ unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::Re #[cfg(feature = "vectored")] pub mod vectored { + use procmacros::ram; + use super::*; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -331,6 +333,7 @@ pub mod vectored { handle_interrupts(level) } + #[ram] unsafe fn handle_interrupts(level: u32) { let cpu_interrupt_mask = interrupt::get() & interrupt::get_mask() & CPU_INTERRUPT_LEVELS[level as usize]; @@ -381,6 +384,7 @@ pub mod vectored { } } + #[ram] unsafe fn handle_interrupt(level: u32, interrupt: Interrupt) { extern "C" { // defined in each hal @@ -400,6 +404,7 @@ pub mod vectored { 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::*; [ @@ -421,6 +426,7 @@ pub mod vectored { 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::*; [ @@ -441,6 +447,7 @@ pub mod vectored { mod chip_specific { use super::*; pub const INTERRUPT_EDGE: u128 = 0; + #[inline] pub fn interrupt_is_edge(_interrupt: Interrupt) -> bool { false } diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index c88c80c671b..6c7a2da8a41 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -265,6 +265,7 @@ fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result< "forbid", "cold", "ram", + "inline", ]; 'o: for attr in attrs { @@ -276,7 +277,7 @@ fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result< let err_str = match caller { WhiteListCaller::Interrupt => { - "this attribute is not allowed on an interrupt handler controlled by esp32_hal" + "this attribute is not allowed on an interrupt handler controlled by esp-hal" } }; diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 0c40f61978b..888d4b539c6 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -13,6 +13,7 @@ use esp32_hal::{ gpio::{Gpio0, IO}, gpio_types::{Event, Input, Pin, PullDown}, interrupt, + macros::ram, pac::{self, Peripherals}, prelude::*, timer::TimerGroup, @@ -77,6 +78,7 @@ fn main() -> ! { } } +#[ram] #[interrupt] fn GPIO() { unsafe { diff --git a/esp32s2-hal/examples/gpio_interrupt.rs b/esp32s2-hal/examples/gpio_interrupt.rs index fbe9e5b7064..2431c50cbfa 100644 --- a/esp32s2-hal/examples/gpio_interrupt.rs +++ b/esp32s2-hal/examples/gpio_interrupt.rs @@ -13,6 +13,7 @@ use esp32s2_hal::{ gpio::{Gpio0, IO}, gpio_types::{Event, Input, Pin, PullDown}, interrupt, + macros::ram, pac::{self, Peripherals}, prelude::*, timer::TimerGroup, @@ -74,6 +75,7 @@ fn main() -> ! { } } +#[ram] #[interrupt] fn GPIO() { unsafe { diff --git a/esp32s3-hal/examples/gpio_interrupt.rs b/esp32s3-hal/examples/gpio_interrupt.rs index 2210b0b9e31..eaf2440e74b 100644 --- a/esp32s3-hal/examples/gpio_interrupt.rs +++ b/esp32s3-hal/examples/gpio_interrupt.rs @@ -13,6 +13,7 @@ use esp32s3_hal::{ gpio::{Gpio0, IO}, gpio_types::{Event, Input, Pin, PullDown}, interrupt, + macros::ram, pac::{self, Peripherals}, prelude::*, timer::TimerGroup, @@ -74,6 +75,7 @@ fn main() -> ! { } } +#[ram] #[interrupt] fn GPIO() { unsafe { From 430de39665858ea26782ea18cacd237ee84b73d7 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 21:31:44 +0100 Subject: [PATCH 09/23] Use xtensa_lx::Mutex CS when enabling interrupts --- esp-hal-common/src/interrupt/xtensa.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index f17ccfe60aa..354b5851c46 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -213,10 +213,17 @@ pub mod vectored { ) -> Result<(), Error> { let cpu_interrupt = interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; + use xtensa_lx::mutex::Mutex as _; - // (&INTERRUPT_LEVELS_MUTEX).lock(|_| unsafe { - // TODO: CS here - unsafe { + #[cfg(any(feature = "esp32", feature = "esp32s3"))] + type Mutex = xtensa_lx::mutex::CriticalSectionSpinLockMutex; + #[cfg(feature = "esp32s2")] + type Mutex = xtensa_lx::mutex::CriticalSectionMutex; + + // TODO: replace with critical-section CS later + static LEVELS_CS: Mutex<()> = Mutex::new(()); + (&LEVELS_CS).lock(|_| unsafe { + // TODO reduce to 3?, as we only support up to 3 prios atm for i in 0..=7 { INTERRUPT_LEVELS[i] &= !(1 << interrupt.number()); } @@ -227,9 +234,8 @@ pub mod vectored { xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, ); - } + }); Ok(()) - // }) } // TODO mention that theses interrupts are reservered in vector mode From 494d16c87f37d7554e0f82fc83a823b6f346b0a3 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 24 Jun 2022 12:00:05 +0100 Subject: [PATCH 10/23] Run clippy on each target --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++-------- esp-hal-common/src/lib.rs | 8 ++++++-- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7471c55abb3..bfaf5b9b620 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 + 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 - # 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: -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 diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 8d05437a28d..3bdc73215fe 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -89,11 +89,15 @@ pub enum Cpu { } pub fn get_core() -> Cpu { - #[cfg(target_arch = "xtensa")] + #[cfg(all(target_arch = "xtensa", feature = "multicore"))] match ((xtensa_lx::get_processor_id() >> 13) & 1) != 0 { false => Cpu::ProCpu, true => Cpu::AppCpu, } - #[cfg(target_arch = "riscv")] // TODO get hart_id + // #[cfg(all(target_arch = "riscv32", feature = "multicore"))] + // TODO get hart_id + + // single core always has ProCpu only + #[cfg(feature = "unicore")] Cpu::ProCpu } From 406822079b3897b71ff19ae5503602f84153cd2d Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 24 Jun 2022 13:23:22 +0100 Subject: [PATCH 11/23] Remove redundant features --- esp-hal-common/Cargo.toml | 3 --- esp-hal-common/src/lib.rs | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 2e4234ee5ed..87929ca2e23 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -55,9 +55,6 @@ 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"] -# 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 = [] diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 3bdc73215fe..7dbe5e5ae75 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -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; From 369dee23652867ae09cb95b09714d12e26bd0338 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 21:42:23 +0100 Subject: [PATCH 12/23] Fix C3 builds --- esp32c3-hal/examples/ram.rs | 2 +- esp32c3-hal/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esp32c3-hal/examples/ram.rs b/esp32c3-hal/examples/ram.rs index 2bdf2b51a55..3e7c81ab07d 100644 --- a/esp32c3-hal/examples/ram.rs +++ b/esp32c3-hal/examples/ram.rs @@ -12,9 +12,9 @@ use core::fmt::Write; use esp32c3_hal::{ clock::ClockControl, + macros::ram, pac::{Peripherals, UART0}, prelude::*, - ram, timer::TimerGroup, Serial, }; diff --git a/esp32c3-hal/src/lib.rs b/esp32c3-hal/src/lib.rs index 2b305017ca0..9abecd22fe4 100644 --- a/esp32c3-hal/src/lib.rs +++ b/esp32c3-hal/src/lib.rs @@ -9,10 +9,10 @@ pub use esp_hal_common::{ gpio as gpio_types, i2c, interrupt, + macros, pac, prelude, pulse_control, - ram, serial, spi, system, From b647534cb2260e07636a7e9b2e1ad8cc682837e2 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Thu, 14 Jul 2022 21:59:10 +0100 Subject: [PATCH 13/23] make enable unsafe. Add note about preallocated interrupts in vectored mode. --- esp-hal-common/src/interrupt/xtensa.rs | 40 +++++++++++++-------- esp32-hal/examples/serial_interrupts.rs | 12 ++++--- esp32-hal/examples/timer_interrupt.rs | 43 +++++++++++----------- esp32-hal/src/lib.rs | 2 +- esp32s2-hal/examples/serial_interrupts.rs | 12 ++++--- esp32s2-hal/examples/systimer.rs | 36 +++++++++---------- esp32s2-hal/examples/timer_interrupt.rs | 44 ++++++++++++----------- esp32s2-hal/src/lib.rs | 2 +- esp32s3-hal/examples/serial_interrupts.rs | 12 ++++--- esp32s3-hal/examples/systimer.rs | 36 +++++++++---------- esp32s3-hal/examples/timer_interrupt.rs | 42 +++++++++++----------- esp32s3-hal/src/lib.rs | 2 +- 12 files changed, 152 insertions(+), 131 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 354b5851c46..009659f94f5 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -47,21 +47,31 @@ pub enum CpuInterrupt { } /// 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); - } +/// +/// Great care **must** be taken when using with 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 enable(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 = "multicore")] + Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(), + #[cfg(feature = "unicore")] + 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. diff --git a/esp32-hal/examples/serial_interrupts.rs b/esp32-hal/examples/serial_interrupts.rs index 238ebe95cc2..7460783b310 100644 --- a/esp32-hal/examples/serial_interrupts.rs +++ b/esp32-hal/examples/serial_interrupts.rs @@ -53,11 +53,13 @@ fn main() -> ! { serial0.listen_at_cmd(); serial0.listen_rx_fifo_full(); - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::UART0, - interrupt::CpuInterrupt::Interrupt20LevelPriority2, - ); + unsafe { + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::UART0, + interrupt::CpuInterrupt::Interrupt20LevelPriority2, + ); + } timer0.start(1u64.secs()); diff --git a/esp32-hal/examples/timer_interrupt.rs b/esp32-hal/examples/timer_interrupt.rs index bb37b9e4c99..beb29f1771a 100644 --- a/esp32-hal/examples/timer_interrupt.rs +++ b/esp32-hal/examples/timer_interrupt.rs @@ -58,31 +58,32 @@ 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, - ); + unsafe { + 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( + Cpu::ProCpu, + pac::Interrupt::TG1_T0_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::TG1_T1_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + } 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()); diff --git a/esp32-hal/src/lib.rs b/esp32-hal/src/lib.rs index 251cd0937a1..86641cc49a0 100644 --- a/esp32-hal/src/lib.rs +++ b/esp32-hal/src/lib.rs @@ -12,8 +12,8 @@ pub use esp_hal_common::{ pac, prelude, pulse_control, - spi, serial, + spi, timer, utils, Cpu, diff --git a/esp32s2-hal/examples/serial_interrupts.rs b/esp32s2-hal/examples/serial_interrupts.rs index 45799bbae0b..8a83cf4981e 100644 --- a/esp32s2-hal/examples/serial_interrupts.rs +++ b/esp32s2-hal/examples/serial_interrupts.rs @@ -51,11 +51,13 @@ fn main() -> ! { serial0.listen_at_cmd(); serial0.listen_rx_fifo_full(); - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::UART0, - interrupt::CpuInterrupt::Interrupt20LevelPriority2, - ); + unsafe { + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::UART0, + interrupt::CpuInterrupt::Interrupt20LevelPriority2, + ); + } timer0.start(1u64.secs()); diff --git a/esp32s2-hal/examples/systimer.rs b/esp32s2-hal/examples/systimer.rs index da9ce26c107..78d11e594c6 100644 --- a/esp32s2-hal/examples/systimer.rs +++ b/esp32s2-hal/examples/systimer.rs @@ -69,25 +69,25 @@ fn main() -> ! { (&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, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET1, - interrupt::CpuInterrupt::Interrupt19LevelPriority2, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET2, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::SYSTIMER_TARGET0, + interrupt::CpuInterrupt::Interrupt0LevelPriority1, + ); + + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::SYSTIMER_TARGET1, + interrupt::CpuInterrupt::Interrupt19LevelPriority2, + ); + + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::SYSTIMER_TARGET2, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + } // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32s2-hal/examples/timer_interrupt.rs b/esp32s2-hal/examples/timer_interrupt.rs index 99e5f19c9c2..cab2d072930 100644 --- a/esp32s2-hal/examples/timer_interrupt.rs +++ b/esp32s2-hal/examples/timer_interrupt.rs @@ -58,31 +58,33 @@ 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, - ); + unsafe { + 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( + Cpu::ProCpu, + pac::Interrupt::TG1_T0_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::TG1_T1_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + } 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()); diff --git a/esp32s2-hal/src/lib.rs b/esp32s2-hal/src/lib.rs index faa8b7ea2fb..55314dc976a 100644 --- a/esp32s2-hal/src/lib.rs +++ b/esp32s2-hal/src/lib.rs @@ -11,8 +11,8 @@ pub use esp_hal_common::{ pac, prelude, pulse_control, - spi, serial, + spi, systimer, timer, utils, diff --git a/esp32s3-hal/examples/serial_interrupts.rs b/esp32s3-hal/examples/serial_interrupts.rs index 88dcbc1652b..1bd89102267 100644 --- a/esp32s3-hal/examples/serial_interrupts.rs +++ b/esp32s3-hal/examples/serial_interrupts.rs @@ -53,11 +53,13 @@ fn main() -> ! { serial0.listen_at_cmd(); serial0.listen_rx_fifo_full(); - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::UART0, - interrupt::CpuInterrupt::Interrupt20LevelPriority2, - ); + unsafe { + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::UART0, + interrupt::CpuInterrupt::Interrupt20LevelPriority2, + ); + } timer0.start(1u64.secs()); diff --git a/esp32s3-hal/examples/systimer.rs b/esp32s3-hal/examples/systimer.rs index 12d33f17411..3ddc7dbb89b 100644 --- a/esp32s3-hal/examples/systimer.rs +++ b/esp32s3-hal/examples/systimer.rs @@ -65,25 +65,25 @@ fn main() -> ! { (&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, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET1, - interrupt::CpuInterrupt::Interrupt19LevelPriority2, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET2, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::SYSTIMER_TARGET0, + interrupt::CpuInterrupt::Interrupt0LevelPriority1, + ); + + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::SYSTIMER_TARGET1, + interrupt::CpuInterrupt::Interrupt19LevelPriority2, + ); + + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::SYSTIMER_TARGET2, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + } // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32s3-hal/examples/timer_interrupt.rs b/esp32s3-hal/examples/timer_interrupt.rs index f540df0f5e0..56d875ee1dd 100644 --- a/esp32s3-hal/examples/timer_interrupt.rs +++ b/esp32s3-hal/examples/timer_interrupt.rs @@ -58,31 +58,33 @@ 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( + unsafe { + 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( Cpu::ProCpu, - pac::Interrupt::TG0_T1_LEVEL, - interrupt::CpuInterrupt::Interrupt20LevelPriority2, - ); + pac::Interrupt::TG1_T0_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + interrupt::enable( + Cpu::ProCpu, + pac::Interrupt::TG1_T1_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, + ); + } + 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()); diff --git a/esp32s3-hal/src/lib.rs b/esp32s3-hal/src/lib.rs index ab5691fec84..4c7f3beaae8 100644 --- a/esp32s3-hal/src/lib.rs +++ b/esp32s3-hal/src/lib.rs @@ -14,8 +14,8 @@ pub use esp_hal_common::{ pac, prelude, pulse_control, - spi, serial, + spi, systimer, timer, usb_serial_jtag, From 11f234217dc9a2bdfacaa4a15860eef5b6052c9c Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Jul 2022 13:05:59 +0100 Subject: [PATCH 14/23] 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. --- esp-hal-common/src/interrupt/xtensa.rs | 137 +++++++++++++++++-------- 1 file changed, 93 insertions(+), 44 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 009659f94f5..7e5515ac13a 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -11,6 +11,7 @@ use crate::{ /// `level1_interrupt`) #[allow(unused)] #[derive(Debug, Copy, Clone)] +#[repr(u32)] pub enum CpuInterrupt { Interrupt0LevelPriority1 = 0, Interrupt1LevelPriority1, @@ -192,30 +193,99 @@ pub mod vectored { /// Interrupt priority levels. #[derive(Copy, Clone, Debug, PartialEq, Eq)] + #[repr(u8)] pub enum Priority { None = 0, Priority1, Priority2, Priority3, - // TODO the following priorities are 'unusable' due to the value in PS_INTLEVEL_EXCM - // defined in xtensa_lx_rt Xtensa programmer guide indicates we _can_ implement - // high level interrupts in Rust, but they recommend we dont (however their reasoning - // seemed to indicate interference with rtos') - // - // Another suggestion from Xtensa programmers guide: - // Alternatively, a level-one interrupt can also be used instead (with software - // prioritization if needed) but I have no idea what software prioritization would - // look like in this context. - - // Priority4, - // Priority5, - // Priority6, } - /// Stores what interrupts are enabled at each interrupt level - static mut INTERRUPT_LEVELS: [u128; 8] = [0u128; 8]; + 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 = "multicore")] + Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(), + #[cfg(feature = "unicore")] + 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 + } + } + } - /// A priority of None, disables the interrupt pub fn enable_with_priority( core: crate::Cpu, interrupt: Interrupt, @@ -223,33 +293,17 @@ pub mod vectored { ) -> Result<(), Error> { let cpu_interrupt = interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; - use xtensa_lx::mutex::Mutex as _; - - #[cfg(any(feature = "esp32", feature = "esp32s3"))] - type Mutex = xtensa_lx::mutex::CriticalSectionSpinLockMutex; - #[cfg(feature = "esp32s2")] - type Mutex = xtensa_lx::mutex::CriticalSectionMutex; - - // TODO: replace with critical-section CS later - static LEVELS_CS: Mutex<()> = Mutex::new(()); - (&LEVELS_CS).lock(|_| unsafe { - // TODO reduce to 3?, as we only support up to 3 prios atm - for i in 0..=7 { - INTERRUPT_LEVELS[i] &= !(1 << interrupt.number()); - } - INTERRUPT_LEVELS[level as usize] |= 1 << interrupt.number(); + unsafe { enable(core, interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, ); - }); + } Ok(()) } - // TODO mention that theses interrupts are reservered in vector mode - // TODO make the normal `enable` unsafe? Would break vectoring unless careful fn interrupt_level_to_cpu_interrupt( level: Priority, is_edge: bool, @@ -260,10 +314,6 @@ pub mod vectored { Priority::Priority1 => CpuInterrupt::Interrupt10EdgePriority1, Priority::Priority2 => return Err(Error::InvalidInterrupt), Priority::Priority3 => CpuInterrupt::Interrupt22EdgePriority3, - // Priority::Priority4 => CpuInterrupt::Interrupt28EdgePriority4, - // Priority::Priority5 => CpuInterrupt::Interrupt31EdgePriority5, - // Priority::Priority6 => return Err(Error::InvalidInterrupt), - // Priority::Priority7 => CpuInterrupt::Interrupt14NmiPriority7, } } else { match level { @@ -271,10 +321,6 @@ pub mod vectored { Priority::Priority1 => CpuInterrupt::Interrupt1LevelPriority1, Priority::Priority2 => CpuInterrupt::Interrupt19LevelPriority2, Priority::Priority3 => CpuInterrupt::Interrupt23LevelPriority3, - // Priority::Priority4 => CpuInterrupt::Interrupt24LevelPriority4, - // Priority::Priority5 => CpuInterrupt::Interrupt26LevelPriority5, - // Priority::Priority6 => return Err(Error::InvalidInterrupt), - // Priority::Priority7 => CpuInterrupt::Interrupt14NmiPriority7, } }) } @@ -293,8 +339,10 @@ pub mod vectored { 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 { use xtensa_lx_rt::*; + // we're fortunate that all esp variants use the same CPU interrupt layout Some(match number { 6 => Timer0, 7 => Software0, @@ -365,6 +413,7 @@ pub mod vectored { 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(); @@ -374,7 +423,7 @@ pub mod vectored { // register, therefore call all registered // handlers for current level let mut interrupt_mask = - INTERRUPT_LEVELS[level as usize] & chip_specific::INTERRUPT_EDGE; + 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) { @@ -388,7 +437,7 @@ pub mod vectored { // 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]; + 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: From af023a69b45e909a1694a043a8db926100148b02 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Jul 2022 13:14:17 +0100 Subject: [PATCH 15/23] Allow raw interrupts on levels 4-7, whilst also supporting vectoring on levels 1-3 --- esp-hal-common/src/interrupt/xtensa.rs | 31 +++++--------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 7e5515ac13a..b0df436457e 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -373,30 +373,6 @@ pub mod vectored { handle_interrupts(level) } - #[no_mangle] - #[link_section = ".rwtext"] - unsafe fn __level_4_interrupt(level: u32, _save_frame: &mut Context) { - handle_interrupts(level) - } - - #[no_mangle] - #[link_section = ".rwtext"] - unsafe fn __level_5_interrupt(level: u32, _save_frame: &mut Context) { - handle_interrupts(level) - } - - #[no_mangle] - #[link_section = ".rwtext"] - unsafe fn __level_6_interrupt(level: u32, _save_frame: &mut Context) { - handle_interrupts(level) - } - - #[no_mangle] - #[link_section = ".rwtext"] - unsafe fn __level_7_interrupt(level: u32, _save_frame: &mut Context) { - handle_interrupts(level) - } - #[ram] unsafe fn handle_interrupts(level: u32) { let cpu_interrupt_mask = @@ -519,13 +495,15 @@ pub mod vectored { } } -#[cfg(not(feature = "vectored"))] mod raw { use super::*; 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); @@ -535,18 +513,21 @@ mod raw { #[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"] + #[cfg(not(feature = "vectored"))] unsafe fn __level_2_interrupt(_level: u32, save_frame: &mut Context) { level2_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) } From 5692ffd60c07f6b5177e0f5bf2a46e13bd2b161c Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Jul 2022 13:16:09 +0100 Subject: [PATCH 16/23] rename core number features --- esp-hal-common/Cargo.toml | 2 +- esp-hal-common/src/interrupt/xtensa.rs | 12 ++++++------ esp-hal-common/src/lib.rs | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 87929ca2e23..b32b3394fab 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -58,7 +58,7 @@ esp32s3 = ["esp32s3_pac/rt", "xtensa", "dual_core", "xtensa-lx-rt/esp32s3", "x # 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"] diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index b0df436457e..7c2c9648d15 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -65,9 +65,9 @@ pub unsafe fn enable(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { 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 = "multicore")] + #[cfg(feature = "multi_core")] Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(), - #[cfg(feature = "unicore")] + #[cfg(feature = "single_core")] Cpu::AppCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(), }; intr_map_base @@ -81,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(), @@ -117,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 @@ -252,9 +252,9 @@ pub mod vectored { unsafe { let intr_map_base = match core { Cpu::ProCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(), - #[cfg(feature = "multicore")] + #[cfg(feature = "multi_core")] Cpu::AppCpu => (*core1_interrupt_peripheral()).app_mac_intr_map.as_ptr(), - #[cfg(feature = "unicore")] + #[cfg(feature = "single_core")] Cpu::AppCpu => (*core0_interrupt_peripheral()).pro_mac_intr_map.as_ptr(), }; diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 7dbe5e5ae75..dcde7b5d59d 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -89,15 +89,15 @@ pub enum Cpu { } pub fn get_core() -> Cpu { - #[cfg(all(target_arch = "xtensa", feature = "multicore"))] + #[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 = "multicore"))] + // #[cfg(all(target_arch = "riscv32", feature = "multi_core"))] // TODO get hart_id // single core always has ProCpu only - #[cfg(feature = "unicore")] + #[cfg(feature = "single_core")] Cpu::ProCpu } From b88270357cc0c8e24d6c7b3ebea4c5013c94bc4b Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Jul 2022 15:49:34 +0100 Subject: [PATCH 17/23] Fix examples and formatting --- esp32-hal/.vscode/settings.json | 16 ---------------- esp32-hal/examples/gpio_interrupt.rs | 6 ------ esp32s2-hal/examples/gpio_interrupt.rs | 4 ---- esp32s3-hal/examples/gpio_interrupt.rs | 2 -- esp32s3-hal/examples/timer_interrupt.rs | 6 +++--- 5 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 esp32-hal/.vscode/settings.json diff --git a/esp32-hal/.vscode/settings.json b/esp32-hal/.vscode/settings.json deleted file mode 100644 index 54dd8e2321d..00000000000 --- a/esp32-hal/.vscode/settings.json +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 888d4b539c6..32597ed079a 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -20,8 +20,6 @@ use esp32_hal::{ Cpu, Delay, RtcCntl, - Serial, - Timer, }; use panic_halt as _; use xtensa_lx::mutex::{Mutex, SpinLockMutex}; @@ -39,12 +37,8 @@ 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); - esp_println::println!("Hello esp_println!"); - // Disable MWDT and RWDT (Watchdog) flash boot protection wdt.disable(); rtc_cntl.set_wdt_global_enable(false); diff --git a/esp32s2-hal/examples/gpio_interrupt.rs b/esp32s2-hal/examples/gpio_interrupt.rs index 2431c50cbfa..f5bc0755e1f 100644 --- a/esp32s2-hal/examples/gpio_interrupt.rs +++ b/esp32s2-hal/examples/gpio_interrupt.rs @@ -20,8 +20,6 @@ use esp32s2_hal::{ Cpu, Delay, RtcCntl, - Serial, - Timer }; use panic_halt as _; use xtensa_lx::mutex::{CriticalSectionMutex, Mutex}; @@ -40,8 +38,6 @@ fn main() -> ! { let mut wdt = timer_group0.wdt; let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); - esp_println::println!("Hello esp_println!"); - // Disable MWDT and RWDT (Watchdog) flash boot protection wdt.disable(); rtc_cntl.set_wdt_global_enable(false); diff --git a/esp32s3-hal/examples/gpio_interrupt.rs b/esp32s3-hal/examples/gpio_interrupt.rs index eaf2440e74b..e6a9d409530 100644 --- a/esp32s3-hal/examples/gpio_interrupt.rs +++ b/esp32s3-hal/examples/gpio_interrupt.rs @@ -20,8 +20,6 @@ use esp32s3_hal::{ Cpu, Delay, RtcCntl, - Serial, - Timer, }; use panic_halt as _; use xtensa_lx::mutex::{Mutex, SpinLockMutex}; diff --git a/esp32s3-hal/examples/timer_interrupt.rs b/esp32s3-hal/examples/timer_interrupt.rs index 56d875ee1dd..d12377566da 100644 --- a/esp32s3-hal/examples/timer_interrupt.rs +++ b/esp32s3-hal/examples/timer_interrupt.rs @@ -70,9 +70,9 @@ fn main() -> ! { interrupt::CpuInterrupt::Interrupt20LevelPriority2, ); interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::TG1_T0_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, + Cpu::ProCpu, + pac::Interrupt::TG1_T0_LEVEL, + interrupt::CpuInterrupt::Interrupt23LevelPriority3, ); interrupt::enable( Cpu::ProCpu, From 6c7fda965a4f01acfa4b6c33792746c52614ff0a Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Wed, 20 Jul 2022 16:57:31 +0100 Subject: [PATCH 18/23] use xtensa-lx-rt release, update pacs --- esp-hal-common/Cargo.toml | 14 ++++---------- esp32-hal/Cargo.toml | 3 --- esp32-hal/examples/gpio_interrupt.rs | 2 +- esp32s2-hal/Cargo.toml | 3 --- esp32s3-hal/Cargo.toml | 3 --- 5 files changed, 5 insertions(+), 20 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index b32b3394fab..31440e89eb6 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -38,16 +38,10 @@ 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 } - -[patch.crates-io] -xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } +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"] diff --git a/esp32-hal/Cargo.toml b/esp32-hal/Cargo.toml index 14262758479..7075b4cdc02 100644 --- a/esp32-hal/Cargo.toml +++ b/esp32-hal/Cargo.toml @@ -31,9 +31,6 @@ xtensa-lx = { version = "0.7", features = ["esp32"] } xtensa-lx-rt = { version = "0.13", features = ["esp32"], optional = true } nb = "1.0.0" -[patch.crates-io] -xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } - [dependencies.esp-hal-common] path = "../esp-hal-common" features = ["esp32"] diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 32597ed079a..2c653691194 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -56,7 +56,7 @@ fn main() -> ! { interrupt::vectored::enable_with_priority( Cpu::ProCpu, pac::Interrupt::GPIO, - interrupt::vectored::Priority::Priority3, + interrupt::vectored::Priority::Priority2, ) .unwrap(); diff --git a/esp32s2-hal/Cargo.toml b/esp32s2-hal/Cargo.toml index 0eea2840cd3..8b71e9ec0fb 100644 --- a/esp32s2-hal/Cargo.toml +++ b/esp32s2-hal/Cargo.toml @@ -34,9 +34,6 @@ xtensa-lx-rt = { version = "0.13", features = ["esp32s2"], optional = true } path = "../esp-hal-common" features = ["esp32s2"] -[patch.crates-io] -xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } - [dev-dependencies] embedded-graphics = "0.7" panic-halt = "0.2" diff --git a/esp32s3-hal/Cargo.toml b/esp32s3-hal/Cargo.toml index 4cda97d621e..7992159b423 100644 --- a/esp32s3-hal/Cargo.toml +++ b/esp32s3-hal/Cargo.toml @@ -35,9 +35,6 @@ r0 = { version = "1.0", optional = true } path = "../esp-hal-common" features = ["esp32s3"] -[patch.crates-io] -xtensa-lx-rt = { git = "https://github.com/esp-rs/xtensa-lx-rt", rev = "70c56b1090d36742077283af2a83ca4bc1b4f338" } - [dev-dependencies] embedded-graphics = "0.7" panic-halt = "0.2" From b1f0cc5cc6dfee5b5865c8bbc77205afd44b49b3 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 22 Jul 2022 11:03:11 +0100 Subject: [PATCH 19/23] Support passing the trap frame into interrupt handlers --- esp-hal-common/src/interrupt/xtensa.rs | 23 +++--- esp-hal-procmacros/Cargo.toml | 2 + esp-hal-procmacros/src/lib.rs | 105 ++++++------------------- esp32-hal/examples/gpio_interrupt.rs | 6 +- esp32-hal/test.rs | 96 ++++++++++++++++++++++ 5 files changed, 137 insertions(+), 95 deletions(-) create mode 100644 esp32-hal/test.rs diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 7c2c9648d15..933a194c418 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -357,24 +357,24 @@ pub mod vectored { #[no_mangle] #[link_section = ".rwtext"] - unsafe fn __level_1_interrupt(level: u32, _save_frame: &mut Context) { - handle_interrupts(level) + 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) + 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) + unsafe fn __level_3_interrupt(level: u32, save_frame: &mut Context) { + handle_interrupts(level, save_frame) } #[ram] - unsafe fn handle_interrupts(level: u32) { + 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]; @@ -403,7 +403,7 @@ pub mod vectored { loop { let interrupt_nr = interrupt_mask.trailing_zeros(); if let Ok(interrupt) = pac::Interrupt::try_from(interrupt_nr as u16) { - handle_interrupt(level, interrupt) + handle_interrupt(level, interrupt, save_frame) } else { break; } @@ -419,14 +419,14 @@ pub mod vectored { // 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); + handle_interrupt(level, interrupt, save_frame); } } } } #[ram] - unsafe fn handle_interrupt(level: u32, interrupt: Interrupt) { + unsafe fn handle_interrupt(level: u32, interrupt: Interrupt, save_frame: &mut Context) { extern "C" { // defined in each hal fn DefaultHandler(level: u32, interrupt: Interrupt); @@ -436,7 +436,8 @@ pub mod vectored { if handler as *const _ == DefaultHandler as *const unsafe extern "C" fn() { DefaultHandler(level, interrupt); } else { - handler(); + let handler: fn(&mut Context) = core::mem::transmute(handler); + handler(save_frame); } } diff --git a/esp-hal-procmacros/Cargo.toml b/esp-hal-procmacros/Cargo.toml index f1ba3a65c24..e6cab554aa0 100644 --- a/esp-hal-procmacros/Cargo.toml +++ b/esp-hal-procmacros/Cargo.toml @@ -22,3 +22,5 @@ proc-macro-error = "1.0.4" [features] rtc_slow = [] +xtensa = [] +riscv = [] \ No newline at end of file diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 6c7a2da8a41..7b5766b5443 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -1,4 +1,4 @@ -use std::{collections::HashSet, iter}; +use std::iter; use darling::FromMeta; use proc_macro::{self, Span, TokenStream}; @@ -11,14 +11,10 @@ use syn::{ AttrStyle, Attribute, AttributeArgs, - FnArg, Ident, - Item, ItemFn, - ItemStatic, Meta::Path, ReturnType, - Stmt, Type, Visibility, }; @@ -157,7 +153,6 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { let valid_signature = f.sig.constness.is_none() && f.vis == Visibility::Inherited && f.sig.abi.is_none() - && f.sig.inputs.is_empty() && f.sig.generics.params.is_empty() && f.sig.generics.where_clause.is_none() && f.sig.variadic.is_none() @@ -168,42 +163,29 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { 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() [-> !]`", + "`#[interrupt]` handlers must have signature `[unsafe] fn([&mut Context]) [-> !]`", ) .to_compile_error() .into(); } - let (statics, stmts) = match extract_static_muts(f.block.stmts.iter().cloned()) { - Err(e) => return e.to_compile_error().into(), - Ok(x) => x, - }; - f.sig.ident = Ident::new( - &format!("__xtensa_lx_6_{}", f.sig.ident), + &format!("__esp_hal_internal_{}", f.sig.ident), proc_macro2::Span::call_site(), ); - f.sig.inputs.extend(statics.iter().map(|statik| { - let ident = &statik.ident; - let ty = &statik.ty; - let attrs = &statik.attrs; - syn::parse::(quote!(#[allow(non_snake_case)] #(#attrs)* #ident: &mut #ty).into()) - .unwrap() - })); - f.block.stmts = iter::once( + f.block.stmts.extend(iter::once( syn::parse2(quote! {{ // Check that this interrupt actually exists crate::pac::Interrupt::#ident_s; }}) .unwrap(), - ) - .chain(stmts) - .collect(); + )); let tramp_ident = Ident::new( &format!("{}_trampoline", f.sig.ident), @@ -211,36 +193,31 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { ); let ident = &f.sig.ident; - let resource_args = statics - .iter() - .map(|statik| { - let (ref cfgs, ref attrs) = extract_cfgs(statik.attrs.clone()); - let ident = &statik.ident; - let ty = &statik.ty; - let expr = &statik.expr; - quote! { - #(#cfgs)* - { - #(#attrs)* - static mut #ident: #ty = #expr; - &mut #ident - } - } - }) - .collect::>(); - 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() { + pub unsafe extern "C" fn #tramp_ident(context: &mut #context) { #ident( - #(#resource_args),* + #context_call ) } @@ -308,41 +285,3 @@ fn extract_cfgs(attrs: Vec) -> (Vec, Vec) { (cfgs, not_cfgs) } - -/// Extracts `static mut` vars from the beginning of the given statements -fn extract_static_muts( - stmts: impl IntoIterator, -) -> Result<(Vec, Vec), parse::Error> { - let mut istmts = stmts.into_iter(); - - let mut seen = HashSet::new(); - let mut statics = vec![]; - let mut stmts = vec![]; - while let Some(stmt) = istmts.next() { - match stmt { - Stmt::Item(Item::Static(var)) => { - if var.mutability.is_some() { - if seen.contains(&var.ident) { - return Err(parse::Error::new( - var.ident.span(), - format!("the name `{}` is defined multiple times", var.ident), - )); - } - - seen.insert(var.ident.clone()); - statics.push(var); - } else { - stmts.push(Stmt::Item(Item::Static(var))); - } - } - _ => { - stmts.push(stmt); - break; - } - } - } - - stmts.extend(istmts); - - Ok((statics, stmts)) -} diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 2c653691194..929ab5244c9 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -74,12 +74,16 @@ fn main() -> ! { #[ram] #[interrupt] -fn GPIO() { +fn GPIO(frame: &mut xtensa_lx_rt::exception::Context) { unsafe { esp_println::println!( "GPIO Interrupt with priority {}", xtensa_lx::interrupt::get_level() ); + esp_println::println!( + "{:?}", + frame + ); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); diff --git a/esp32-hal/test.rs b/esp32-hal/test.rs new file mode 100644 index 00000000000..efe312cfd8b --- /dev/null +++ b/esp32-hal/test.rs @@ -0,0 +1,96 @@ +#![feature(prelude_import)] +#![no_std] +#![no_main] +#[prelude_import] +use core::prelude::rust_2021::*; +#[macro_use] +extern crate core; +#[macro_use] +extern crate compiler_builtins; +use core::cell::RefCell; +use esp32_hal::{ + clock::ClockControl, + gpio::{Gpio0, IO}, + gpio_types::{Event, Input, Pin, PullDown}, + interrupt, + macros::ram, + pac::{self, Peripherals}, + prelude::*, + timer::TimerGroup, + Cpu, Delay, RtcCntl, +}; +use panic_halt as _; +use xtensa_lx::mutex::{Mutex, SpinLockMutex}; +use xtensa_lx_rt::entry; +static mut BUTTON: SpinLockMutex>>>> = + SpinLockMutex::new(RefCell::new(None)); +#[doc(hidden)] +#[export_name = "main"] +pub unsafe extern "C" fn __xtensa_lx_rt_main_trampoline() { + __xtensa_lx_rt_main() +} +#[inline(always)] +fn __xtensa_lx_rt_main() -> ! { + let peripherals = Peripherals::take().unwrap(); + let system = peripherals.DPORT.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); + let mut wdt = timer_group0.wdt; + let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); + wdt.disable(); + rtc_cntl.set_wdt_global_enable(false); + let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); + 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 { + (&BUTTON).lock(|data| (*data).replace(Some(button))); + } + interrupt::vectored::enable_with_priority( + Cpu::ProCpu, + pac::Interrupt::GPIO, + interrupt::vectored::Priority::Priority2, + ) + .unwrap(); + led.set_high().unwrap(); + let mut delay = Delay::new(&clocks); + loop { + led.toggle().unwrap(); + delay.delay_ms(500u32); + } +} +#[link_section = ".rwtext"] +#[inline(never)] +#[doc(hidden)] +#[export_name = "GPIO"] +pub unsafe extern "C" fn __esp_hal_internal_GPIO_trampoline( + context: &mut xtensa_lx_rt::exception::Context, +) { + __esp_hal_internal_GPIO() +} +#[inline(always)] +#[link_section = ".rwtext"] +#[inline(never)] +fn __esp_hal_internal_GPIO() { + unsafe { + { + use core::fmt::Write; + ::esp_println::Printer + .write_fmt(::core::fmt::Arguments::new_v1( + &["GPIO Interrupt with priority ", "\n"], + &[::core::fmt::ArgumentV1::new_display( + &xtensa_lx::interrupt::get_level(), + )], + )) + .ok(); + }; + (&BUTTON).lock(|data| { + let mut button = data.borrow_mut(); + let button = button.as_mut().unwrap(); + button.clear_interrupt(); + }); + } + { + crate::pac::Interrupt::GPIO; + } +} From b30b3eb57f22fcc9d0b3b0733681659dd6f1091f Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 22 Jul 2022 11:15:15 +0100 Subject: [PATCH 20/23] cfg away the #[interrupt] macro when not using vectoring --- esp-hal-common/Cargo.toml | 2 +- esp-hal-procmacros/Cargo.toml | 3 +- esp-hal-procmacros/src/lib.rs | 13 +++-- esp32-hal/test.rs | 96 ----------------------------------- 4 files changed, 11 insertions(+), 103 deletions(-) delete mode 100644 esp32-hal/test.rs diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 31440e89eb6..4d95f8fb39e 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -63,4 +63,4 @@ 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 = [] +vectored = ["procmacros/interrupt"] diff --git a/esp-hal-procmacros/Cargo.toml b/esp-hal-procmacros/Cargo.toml index e6cab554aa0..c13d8e65212 100644 --- a/esp-hal-procmacros/Cargo.toml +++ b/esp-hal-procmacros/Cargo.toml @@ -23,4 +23,5 @@ proc-macro-error = "1.0.4" [features] rtc_slow = [] xtensa = [] -riscv = [] \ No newline at end of file +riscv = [] +interrupt = [] \ No newline at end of file diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 7b5766b5443..73438a3e543 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -1,16 +1,13 @@ -use std::iter; - 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, - parse_macro_input, spanned::Spanned, AttrStyle, Attribute, - AttributeArgs, Ident, ItemFn, Meta::Path, @@ -18,6 +15,7 @@ use syn::{ Type, Visibility, }; +use syn::{parse_macro_input, AttributeArgs}; #[derive(Debug, Default, FromMeta)] #[darling(default)] @@ -111,6 +109,7 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream { /// 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. +#[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"); @@ -179,7 +178,7 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { &format!("__esp_hal_internal_{}", f.sig.ident), proc_macro2::Span::call_site(), ); - f.block.stmts.extend(iter::once( + f.block.stmts.extend(std::iter::once( syn::parse2(quote! {{ // Check that this interrupt actually exists crate::pac::Interrupt::#ident_s; @@ -227,10 +226,12 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { .into() } +#[cfg(feature = "interrupt")] enum WhiteListCaller { Interrupt, } +#[cfg(feature = "interrupt")] fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result<(), TokenStream> { let whitelist = &[ "doc", @@ -267,10 +268,12 @@ fn check_attr_whitelist(attrs: &[Attribute], caller: WhiteListCaller) -> Result< } /// 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) -> (Vec, Vec) { let mut cfgs = vec![]; let mut not_cfgs = vec![]; diff --git a/esp32-hal/test.rs b/esp32-hal/test.rs deleted file mode 100644 index efe312cfd8b..00000000000 --- a/esp32-hal/test.rs +++ /dev/null @@ -1,96 +0,0 @@ -#![feature(prelude_import)] -#![no_std] -#![no_main] -#[prelude_import] -use core::prelude::rust_2021::*; -#[macro_use] -extern crate core; -#[macro_use] -extern crate compiler_builtins; -use core::cell::RefCell; -use esp32_hal::{ - clock::ClockControl, - gpio::{Gpio0, IO}, - gpio_types::{Event, Input, Pin, PullDown}, - interrupt, - macros::ram, - pac::{self, Peripherals}, - prelude::*, - timer::TimerGroup, - Cpu, Delay, RtcCntl, -}; -use panic_halt as _; -use xtensa_lx::mutex::{Mutex, SpinLockMutex}; -use xtensa_lx_rt::entry; -static mut BUTTON: SpinLockMutex>>>> = - SpinLockMutex::new(RefCell::new(None)); -#[doc(hidden)] -#[export_name = "main"] -pub unsafe extern "C" fn __xtensa_lx_rt_main_trampoline() { - __xtensa_lx_rt_main() -} -#[inline(always)] -fn __xtensa_lx_rt_main() -> ! { - let peripherals = Peripherals::take().unwrap(); - let system = peripherals.DPORT.split(); - let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks); - let mut wdt = timer_group0.wdt; - let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); - wdt.disable(); - rtc_cntl.set_wdt_global_enable(false); - let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); - 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 { - (&BUTTON).lock(|data| (*data).replace(Some(button))); - } - interrupt::vectored::enable_with_priority( - Cpu::ProCpu, - pac::Interrupt::GPIO, - interrupt::vectored::Priority::Priority2, - ) - .unwrap(); - led.set_high().unwrap(); - let mut delay = Delay::new(&clocks); - loop { - led.toggle().unwrap(); - delay.delay_ms(500u32); - } -} -#[link_section = ".rwtext"] -#[inline(never)] -#[doc(hidden)] -#[export_name = "GPIO"] -pub unsafe extern "C" fn __esp_hal_internal_GPIO_trampoline( - context: &mut xtensa_lx_rt::exception::Context, -) { - __esp_hal_internal_GPIO() -} -#[inline(always)] -#[link_section = ".rwtext"] -#[inline(never)] -fn __esp_hal_internal_GPIO() { - unsafe { - { - use core::fmt::Write; - ::esp_println::Printer - .write_fmt(::core::fmt::Arguments::new_v1( - &["GPIO Interrupt with priority ", "\n"], - &[::core::fmt::ArgumentV1::new_display( - &xtensa_lx::interrupt::get_level(), - )], - )) - .ok(); - }; - (&BUTTON).lock(|data| { - let mut button = data.borrow_mut(); - let button = button.as_mut().unwrap(); - button.clear_interrupt(); - }); - } - { - crate::pac::Interrupt::GPIO; - } -} From 1eb70a0cc3d52ad852dae93d46ac94c8644eb463 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 22 Jul 2022 15:11:21 +0100 Subject: [PATCH 21/23] rename enable to map move vectored feature to chip specific hals --- esp-hal-common/Cargo.toml | 8 ++++---- esp-hal-common/src/interrupt/xtensa.rs | 8 ++++---- esp32-hal/Cargo.toml | 3 ++- esp32s2-hal/Cargo.toml | 3 ++- esp32s3-hal/Cargo.toml | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 4d95f8fb39e..7e1182f392b 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -44,10 +44,10 @@ esp32s2_pac = { package = "esp32s2", git = "https://github.com/esp-rs/esp-pacs.g 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"] +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"] # Core Count (should not be enabled directly, but instead by a PAC's feature) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 933a194c418..517c913450f 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -47,9 +47,9 @@ pub enum CpuInterrupt { Interrupt31EdgePriority5, } -/// Enable and assign a peripheral interrupt to an CPU interrupt. +/// Assign a peripheral interrupt to an CPU interrupt. /// -/// Great care **must** be taken when using with function with interrupt +/// Great care **must** be taken when using this function with interrupt /// vectoring (enabled by default). Avoid the following CPU interrupts: /// - Interrupt1LevelPriority1 /// - Interrupt19LevelPriority2 @@ -60,7 +60,7 @@ pub enum CpuInterrupt { /// /// Note: this only maps the interrupt to the CPU interrupt. The CPU interrupt /// still needs to be enabled afterwards -pub unsafe fn enable(core: Cpu, interrupt: Interrupt, which: CpuInterrupt) { +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 { @@ -295,7 +295,7 @@ pub mod vectored { interrupt_level_to_cpu_interrupt(level, chip_specific::interrupt_is_edge(interrupt))?; unsafe { - enable(core, interrupt, cpu_interrupt); + map(core, interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, diff --git a/esp32-hal/Cargo.toml b/esp32-hal/Cargo.toml index 7075b4cdc02..212713fc1ac 100644 --- a/esp32-hal/Cargo.toml +++ b/esp32-hal/Cargo.toml @@ -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" diff --git a/esp32s2-hal/Cargo.toml b/esp32s2-hal/Cargo.toml index 8b71e9ec0fb..dd80854544b 100644 --- a/esp32s2-hal/Cargo.toml +++ b/esp32s2-hal/Cargo.toml @@ -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" diff --git a/esp32s3-hal/Cargo.toml b/esp32s3-hal/Cargo.toml index 7992159b423..6b700051d0f 100644 --- a/esp32s3-hal/Cargo.toml +++ b/esp32s3-hal/Cargo.toml @@ -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" From 5bf76c5acae1032c0173a4d24f9da6a89cf02df9 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 22 Jul 2022 15:23:50 +0100 Subject: [PATCH 22/23] export vectored functions - rename `enable_with_priority` to `enable` - add docs for interrupt macro --- esp-hal-common/src/interrupt/xtensa.rs | 12 ++++++------ esp-hal-procmacros/src/lib.rs | 20 +++++++++++++++++++- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/esp-hal-common/src/interrupt/xtensa.rs b/esp-hal-common/src/interrupt/xtensa.rs index 517c913450f..5e7bb38afc6 100644 --- a/esp-hal-common/src/interrupt/xtensa.rs +++ b/esp-hal-common/src/interrupt/xtensa.rs @@ -180,11 +180,15 @@ unsafe fn core1_interrupt_peripheral() -> *const crate::pac::interrupt_core1::Re crate::pac::INTERRUPT_CORE1::PTR } +#[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 { @@ -286,16 +290,12 @@ pub mod vectored { } } - pub fn enable_with_priority( - core: crate::Cpu, - interrupt: Interrupt, - level: Priority, - ) -> Result<(), Error> { + 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(core, interrupt, cpu_interrupt); + map(get_core(), interrupt, cpu_interrupt); xtensa_lx::interrupt::enable_mask( xtensa_lx::interrupt::get_mask() | 1 << cpu_interrupt as u32, diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 73438a3e543..eea31003673 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -109,6 +109,24 @@ pub fn ram(args: TokenStream, input: TokenStream) -> TokenStream { /// 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 { @@ -181,7 +199,7 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { f.block.stmts.extend(std::iter::once( syn::parse2(quote! {{ // Check that this interrupt actually exists - crate::pac::Interrupt::#ident_s; + self::pac::Interrupt::#ident_s; }}) .unwrap(), )); From 67ba5f0755e8dc6a4a57453ddc94330c51ab8f77 Mon Sep 17 00:00:00 2001 From: Scott Mabin Date: Fri, 22 Jul 2022 15:59:41 +0100 Subject: [PATCH 23/23] Update all examples to use vectored interrupts --- esp-hal-common/Cargo.toml | 2 +- esp32-hal/examples/gpio_interrupt.rs | 10 +-- esp32-hal/examples/serial_interrupts.rs | 22 +---- esp32-hal/examples/timer_interrupt.rs | 63 ++++--------- esp32s2-hal/examples/gpio_interrupt.rs | 7 +- esp32s2-hal/examples/serial_interrupts.rs | 24 ++--- esp32s2-hal/examples/systimer.rs | 103 ++++++---------------- esp32s2-hal/examples/timer_interrupt.rs | 64 ++++---------- esp32s3-hal/examples/gpio_interrupt.rs | 9 +- esp32s3-hal/examples/serial_interrupts.rs | 22 +---- esp32s3-hal/examples/systimer.rs | 97 ++++++-------------- esp32s3-hal/examples/timer_interrupt.rs | 64 ++++---------- 12 files changed, 128 insertions(+), 359 deletions(-) diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 7e1182f392b..692bf062242 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -45,7 +45,7 @@ esp32s3_pac = { package = "esp32s3", git = "https://github.com/esp-rs/esp-pacs.g [features] esp32 = ["esp32_pac/rt" , "procmacros/xtensa", "multi_core" , "xtensa-lx-rt/esp32", "xtensa-lx/esp32"] -esp32c3 = ["esp32c3_pac/rt", "procmacros/riscv" , "single_core"] +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"] diff --git a/esp32-hal/examples/gpio_interrupt.rs b/esp32-hal/examples/gpio_interrupt.rs index 929ab5244c9..b8ee22de53b 100644 --- a/esp32-hal/examples/gpio_interrupt.rs +++ b/esp32-hal/examples/gpio_interrupt.rs @@ -17,7 +17,6 @@ use esp32_hal::{ pac::{self, Peripherals}, prelude::*, timer::TimerGroup, - Cpu, Delay, RtcCntl, }; @@ -53,8 +52,7 @@ fn main() -> ! { (&BUTTON).lock(|data| (*data).replace(Some(button))); } - interrupt::vectored::enable_with_priority( - Cpu::ProCpu, + interrupt::enable( pac::Interrupt::GPIO, interrupt::vectored::Priority::Priority2, ) @@ -74,16 +72,12 @@ fn main() -> ! { #[ram] #[interrupt] -fn GPIO(frame: &mut xtensa_lx_rt::exception::Context) { +fn GPIO() { unsafe { esp_println::println!( "GPIO Interrupt with priority {}", xtensa_lx::interrupt::get_level() ); - esp_println::println!( - "{:?}", - frame - ); (&BUTTON).lock(|data| { let mut button = data.borrow_mut(); diff --git a/esp32-hal/examples/serial_interrupts.rs b/esp32-hal/examples/serial_interrupts.rs index 7460783b310..cd48c08b2a0 100644 --- a/esp32-hal/examples/serial_interrupts.rs +++ b/esp32-hal/examples/serial_interrupts.rs @@ -14,7 +14,6 @@ use esp32_hal::{ prelude::*, serial::config::AtCmdConfig, timer::TimerGroup, - Cpu, RtcCntl, Serial, }; @@ -53,13 +52,7 @@ fn main() -> ! { serial0.listen_at_cmd(); serial0.listen_rx_fifo_full(); - unsafe { - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::UART0, - interrupt::CpuInterrupt::Interrupt20LevelPriority2, - ); - } + interrupt::enable(pac::Interrupt::UART0, interrupt::Priority::Priority2).unwrap(); timer0.start(1u64.secs()); @@ -67,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| { @@ -85,8 +73,8 @@ fn main() -> ! { } } -#[no_mangle] -pub fn level2_interrupt() { +#[interrupt] +fn UART0() { unsafe { (&SERIAL).lock(|data| { let mut serial = data.borrow_mut(); @@ -108,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, - ); }); } } diff --git a/esp32-hal/examples/timer_interrupt.rs b/esp32-hal/examples/timer_interrupt.rs index beb29f1771a..fcbd4774591 100644 --- a/esp32-hal/examples/timer_interrupt.rs +++ b/esp32-hal/examples/timer_interrupt.rs @@ -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,28 +57,10 @@ fn main() -> ! { wdt1.disable(); rtc_cntl.set_wdt_global_enable(false); - unsafe { - 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( - Cpu::ProCpu, - pac::Interrupt::TG1_T0_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::TG1_T1_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); - } + 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()); @@ -97,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(); @@ -129,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(); @@ -148,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(); @@ -171,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(); diff --git a/esp32s2-hal/examples/gpio_interrupt.rs b/esp32s2-hal/examples/gpio_interrupt.rs index f5bc0755e1f..4d6018f46d1 100644 --- a/esp32s2-hal/examples/gpio_interrupt.rs +++ b/esp32s2-hal/examples/gpio_interrupt.rs @@ -17,7 +17,6 @@ use esp32s2_hal::{ pac::{self, Peripherals}, prelude::*, timer::TimerGroup, - Cpu, Delay, RtcCntl, }; @@ -36,6 +35,7 @@ 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); // Disable MWDT and RWDT (Watchdog) flash boot protection @@ -52,10 +52,9 @@ fn main() -> ! { (&BUTTON).lock(|data| (*data).replace(Some(button))); } - interrupt::vectored::enable_with_priority( - Cpu::ProCpu, + interrupt::enable( pac::Interrupt::GPIO, - interrupt::vectored::Priority::Priority3, + interrupt::vectored::Priority::Priority2, ) .unwrap(); diff --git a/esp32s2-hal/examples/serial_interrupts.rs b/esp32s2-hal/examples/serial_interrupts.rs index 8a83cf4981e..5a4bcd00d5e 100644 --- a/esp32s2-hal/examples/serial_interrupts.rs +++ b/esp32s2-hal/examples/serial_interrupts.rs @@ -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,13 +52,7 @@ fn main() -> ! { serial0.listen_at_cmd(); serial0.listen_rx_fifo_full(); - unsafe { - 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, - ); }); } } diff --git a/esp32s2-hal/examples/systimer.rs b/esp32s2-hal/examples/systimer.rs index 78d11e594c6..bb166479d95 100644 --- a/esp32s2-hal/examples/systimer.rs +++ b/esp32s2-hal/examples/systimer.rs @@ -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>>> = - CriticalSectionMutex::new(RefCell::new(None)); static mut ALARM0: CriticalSectionMutex>>> = CriticalSectionMutex::new(RefCell::new(None)); static mut ALARM1: CriticalSectionMutex>>> = @@ -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, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET1, - interrupt::CpuInterrupt::Interrupt19LevelPriority2, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET2, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); } + interrupt::enable( + pac::Interrupt::SYSTIMER_TARGET0, + Priority::Priority1, + ).unwrap(); + interrupt::enable( + pac::Interrupt::SYSTIMER_TARGET1, + Priority::Priority2, + ).unwrap(); + interrupt::enable( + pac::Interrupt::SYSTIMER_TARGET2, + 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| { diff --git a/esp32s2-hal/examples/timer_interrupt.rs b/esp32s2-hal/examples/timer_interrupt.rs index cab2d072930..7e6c63005aa 100644 --- a/esp32s2-hal/examples/timer_interrupt.rs +++ b/esp32s2-hal/examples/timer_interrupt.rs @@ -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,29 +57,10 @@ fn main() -> ! { wdt1.disable(); rtc_cntl.set_wdt_global_enable(false); - unsafe { - 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( - Cpu::ProCpu, - pac::Interrupt::TG1_T0_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::TG1_T1_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); - } + 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()); @@ -98,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(); @@ -130,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(); @@ -149,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(); @@ -172,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(); diff --git a/esp32s3-hal/examples/gpio_interrupt.rs b/esp32s3-hal/examples/gpio_interrupt.rs index e6a9d409530..a98138b1622 100644 --- a/esp32s3-hal/examples/gpio_interrupt.rs +++ b/esp32s3-hal/examples/gpio_interrupt.rs @@ -17,7 +17,6 @@ use esp32s3_hal::{ pac::{self, Peripherals}, prelude::*, timer::TimerGroup, - Cpu, Delay, RtcCntl, }; @@ -36,9 +35,8 @@ 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); - esp_println::println!("Hello esp_println!"); + let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL); // Disable MWDT and RWDT (Watchdog) flash boot protection wdt.disable(); @@ -54,10 +52,9 @@ fn main() -> ! { (&BUTTON).lock(|data| (*data).replace(Some(button))); } - interrupt::vectored::enable_with_priority( - Cpu::ProCpu, + interrupt::enable( pac::Interrupt::GPIO, - interrupt::vectored::Priority::Priority3, + interrupt::vectored::Priority::Priority2, ) .unwrap(); diff --git a/esp32s3-hal/examples/serial_interrupts.rs b/esp32s3-hal/examples/serial_interrupts.rs index 1bd89102267..0cca9e737c0 100644 --- a/esp32s3-hal/examples/serial_interrupts.rs +++ b/esp32s3-hal/examples/serial_interrupts.rs @@ -14,7 +14,6 @@ use esp32s3_hal::{ prelude::*, serial::config::AtCmdConfig, timer::TimerGroup, - Cpu, RtcCntl, Serial, }; @@ -53,13 +52,7 @@ fn main() -> ! { serial0.listen_at_cmd(); serial0.listen_rx_fifo_full(); - unsafe { - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::UART0, - interrupt::CpuInterrupt::Interrupt20LevelPriority2, - ); - } + interrupt::enable(pac::Interrupt::UART0, interrupt::Priority::Priority2).unwrap(); timer0.start(1u64.secs()); @@ -67,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| { @@ -85,8 +73,8 @@ fn main() -> ! { } } -#[no_mangle] -pub fn level2_interrupt() { +#[interrupt] +fn UART0() { unsafe { (&SERIAL).lock(|data| { let mut serial = data.borrow_mut(); @@ -108,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, - ); }); } } diff --git a/esp32s3-hal/examples/systimer.rs b/esp32s3-hal/examples/systimer.rs index 3ddc7dbb89b..865b88b0936 100644 --- a/esp32s3-hal/examples/systimer.rs +++ b/esp32s3-hal/examples/systimer.rs @@ -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>>> = - SpinLockMutex::new(RefCell::new(None)); static mut ALARM0: SpinLockMutex>>> = SpinLockMutex::new(RefCell::new(None)); static mut ALARM1: SpinLockMutex>>> = @@ -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, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET1, - interrupt::CpuInterrupt::Interrupt19LevelPriority2, - ); - - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::SYSTIMER_TARGET2, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); } + interrupt::enable( + pac::Interrupt::SYSTIMER_TARGET0, + Priority::Priority1, + ).unwrap(); + interrupt::enable( + pac::Interrupt::SYSTIMER_TARGET1, + Priority::Priority2, + ).unwrap(); + interrupt::enable( + pac::Interrupt::SYSTIMER_TARGET2, + 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| { diff --git a/esp32s3-hal/examples/timer_interrupt.rs b/esp32s3-hal/examples/timer_interrupt.rs index d12377566da..9311fdb1cc5 100644 --- a/esp32s3-hal/examples/timer_interrupt.rs +++ b/esp32s3-hal/examples/timer_interrupt.rs @@ -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,29 +57,10 @@ fn main() -> ! { wdt1.disable(); rtc_cntl.set_wdt_global_enable(false); - unsafe { - 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( - Cpu::ProCpu, - pac::Interrupt::TG1_T0_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); - interrupt::enable( - Cpu::ProCpu, - pac::Interrupt::TG1_T1_LEVEL, - interrupt::CpuInterrupt::Interrupt23LevelPriority3, - ); - } - + 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()); @@ -98,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(); @@ -130,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(); @@ -149,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(); @@ -172,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();