RMT: allow driver to init as blocking or async (#1341)

* RMT: allow driver to init as blocking or async

* CHANGELOG and minor fixes
This commit is contained in:
Björn Quentin 2024-03-25 14:54:03 +01:00 committed by GitHub
parent d761ec4def
commit fd4f5592a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 500 additions and 186 deletions

View File

@ -361,9 +361,12 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
/// Mark a function as an interrupt handler. /// Mark a function as an interrupt handler.
/// ///
/// This is really just a nicer looking way to make a function `unsafe extern /// Optionally a priority can be specified, e.g. `#[handler("Priority3")]`,
/// "C"` /// "min" and "max" are special values.
///
/// If no priority is given, "Priority::min()" is assumed
#[cfg(feature = "interrupt")] #[cfg(feature = "interrupt")]
#[proc_macro_error::proc_macro_error]
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
use darling::ast::NestedMeta; use darling::ast::NestedMeta;
@ -385,9 +388,40 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
} }
}; };
if attr_args.len() > 0 { let root = Ident::new(
abort!(Span::call_site(), "This attribute accepts no arguments") if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
} &name
} else {
"crate"
},
Span::call_site().into(),
);
let priority = if attr_args.len() > 1 {
abort!(
Span::call_site(),
"This attribute accepts one optional argument"
)
} else if attr_args.len() == 1 {
match &attr_args[0] {
NestedMeta::Lit(syn::Lit::Str(priority)) => priority.value(),
_ => abort!(
Span::call_site(),
"The priority must be provided as a string"
),
}
} else {
String::from("min")
};
let priority = match priority.as_str() {
"min" => quote::quote_spanned!(original_span => #root::interrupt::Priority::min()),
"max" => quote::quote_spanned!(original_span => #root::interrupt::Priority::max()),
_ => {
let priority = Ident::new(&priority, proc_macro2::Span::call_site());
quote::quote_spanned!(original_span => #root::interrupt::Priority::#priority)
}
};
// XXX should we blacklist other attributes? // XXX should we blacklist other attributes?
@ -419,17 +453,9 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
.into(); .into();
} }
let root = Ident::new(
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
&name
} else {
"crate"
},
Span::call_site().into(),
);
f.sig.abi = syn::parse_quote_spanned!(original_span => extern "C"); f.sig.abi = syn::parse_quote_spanned!(original_span => extern "C");
let orig = f.sig.ident; let orig = f.sig.ident;
let vis = f.vis.clone();
f.sig.ident = Ident::new( f.sig.ident = Ident::new(
&format!("__esp_hal_internal_{}", orig), &format!("__esp_hal_internal_{}", orig),
proc_macro2::Span::call_site(), proc_macro2::Span::call_site(),
@ -440,7 +466,7 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
#f #f
#[allow(non_upper_case_globals)] #[allow(non_upper_case_globals)]
static #orig: #root::interrupt::InterruptHandler = #root::interrupt::InterruptHandler::new(#new, #root::interrupt::Priority::min()); #vis static #orig: #root::interrupt::InterruptHandler = #root::interrupt::InterruptHandler::new(#new, #priority);
) )
.into() .into()
} }

View File

@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Renamed `eh1` feature to `embedded-hal`, feature-gated `embedded-hal@0.2.x` trait implementations (#1273) - Renamed `eh1` feature to `embedded-hal`, feature-gated `embedded-hal@0.2.x` trait implementations (#1273)
- Enable `embedded-hal` feature by default, instead of the `embedded-hal-02` feature (#1313) - Enable `embedded-hal` feature by default, instead of the `embedded-hal-02` feature (#1313)
- `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294) - `Uart` structs now take a `Mode` parameter which defines how the driver is initialized (#1294)
- `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341)
### Removed ### Removed

View File

@ -150,9 +150,6 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) {
#[cfg(i2s1)] #[cfg(i2s1)]
crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap();
#[cfg(rmt)]
crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap();
#[cfg(usb_device)] #[cfg(usb_device)]
crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap(); crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap();

View File

@ -68,6 +68,21 @@ pub const RESERVED_INTERRUPTS: &[usize] = &[
CpuInterrupt::Interrupt22EdgePriority3 as _, CpuInterrupt::Interrupt22EdgePriority3 as _,
]; ];
pub(crate) fn setup_interrupts() {
// disable all known interrupts
// at least after the 2nd stage bootloader there are some interrupts enabled
// (e.g. UART)
for peripheral_interrupt in 0..255 {
crate::soc::peripherals::Interrupt::try_from(peripheral_interrupt)
.map(|intr| {
#[cfg(multi_core)]
disable(Cpu::AppCpu, intr);
disable(Cpu::ProCpu, intr);
})
.ok();
}
}
/// Enable an interrupt by directly binding it to a available CPU interrupt /// Enable an interrupt by directly binding it to a available CPU interrupt
/// ///
/// Unless you are sure, you most likely want to use [`enable`] with the /// Unless you are sure, you most likely want to use [`enable`] with the

View File

@ -158,9 +158,11 @@ extern "C" fn EspDefaultHandler(_interrupt: peripherals::Interrupt) {
pub trait Mode: crate::private::Sealed {} pub trait Mode: crate::private::Sealed {}
/// Driver initialized in blocking mode. /// Driver initialized in blocking mode.
#[derive(Debug)]
pub struct Blocking; pub struct Blocking;
/// Driver initialized in async mode. /// Driver initialized in async mode.
#[derive(Debug)]
pub struct Async; pub struct Async;
impl crate::Mode for Blocking {} impl crate::Mode for Blocking {}

File diff suppressed because it is too large Load Diff

View File

@ -76,6 +76,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
stack_chk_guard.write_volatile(0xdeadbabe); stack_chk_guard.write_volatile(0xdeadbabe);
} }
crate::interrupt::setup_interrupts();
// continue with default reset handler // continue with default reset handler
xtensa_lx_rt::Reset(); xtensa_lx_rt::Reset();
} }

View File

@ -80,6 +80,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
stack_chk_guard.write_volatile(0xdeadbabe); stack_chk_guard.write_volatile(0xdeadbabe);
} }
crate::interrupt::setup_interrupts();
// continue with default reset handler // continue with default reset handler
xtensa_lx_rt::Reset(); xtensa_lx_rt::Reset();
} }

View File

@ -115,6 +115,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! {
stack_chk_guard.write_volatile(0xdeadbabe); stack_chk_guard.write_volatile(0xdeadbabe);
} }
crate::interrupt::setup_interrupts();
// continue with default reset handler // continue with default reset handler
xtensa_lx_rt::Reset(); xtensa_lx_rt::Reset();
} }

View File

@ -18,7 +18,7 @@ use esp_hal::{
gpio::{Gpio5, Output, PushPull, IO}, gpio::{Gpio5, Output, PushPull, IO},
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreator}, rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync},
}; };
use esp_println::{print, println}; use esp_println::{print, println};
@ -58,7 +58,7 @@ async fn main(spawner: Spawner) {
} }
}; };
let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); let rmt = Rmt::new_async(peripherals.RMT, freq, &clocks).unwrap();
let rx_config = RxChannelConfig { let rx_config = RxChannelConfig {
clk_divider: 255, clk_divider: 255,
idle_threshold: 10000, idle_threshold: 10000,

View File

@ -18,7 +18,7 @@ use esp_hal::{
gpio::IO, gpio::IO,
peripherals::Peripherals, peripherals::Peripherals,
prelude::*, prelude::*,
rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreator}, rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync},
timer::TimerGroup, timer::TimerGroup,
}; };
use esp_println::println; use esp_println::println;
@ -43,7 +43,7 @@ async fn main(_spawner: Spawner) {
} }
}; };
let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); let rmt = Rmt::new_async(peripherals.RMT, freq, &clocks).unwrap();
let mut channel = rmt let mut channel = rmt
.channel0 .channel0

View File

@ -56,9 +56,9 @@ fn main() -> ! {
// Configure RMT peripheral globally // Configure RMT peripheral globally
#[cfg(not(feature = "esp32h2"))] #[cfg(not(feature = "esp32h2"))]
let rmt = Rmt::new(peripherals.RMT, 80.MHz(), &clocks).unwrap(); let rmt = Rmt::new(peripherals.RMT, 80.MHz(), &clocks, None).unwrap();
#[cfg(feature = "esp32h2")] #[cfg(feature = "esp32h2")]
let rmt = Rmt::new(peripherals.RMT, 32.MHz(), &clocks).unwrap(); let rmt = Rmt::new(peripherals.RMT, 32.MHz(), &clocks, None).unwrap();
// We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can // We use one of the RMT channels to instantiate a `SmartLedsAdapter` which can
// be used directly with all `smart_led` implementations // be used directly with all `smart_led` implementations

View File

@ -38,7 +38,7 @@ fn main() -> ! {
} }
}; };
let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); let rmt = Rmt::new(peripherals.RMT, freq, &clocks, None).unwrap();
let rx_config = RxChannelConfig { let rx_config = RxChannelConfig {
clk_divider: 1, clk_divider: 1,

View File

@ -33,7 +33,7 @@ fn main() -> ! {
} }
}; };
let rmt = Rmt::new(peripherals.RMT, freq, &clocks).unwrap(); let rmt = Rmt::new(peripherals.RMT, freq, &clocks, None).unwrap();
let tx_config = TxChannelConfig { let tx_config = TxChannelConfig {
clk_divider: 255, clk_divider: 255,