From fd4f5592a4776afdce9565d0210ba6dedcf51eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Mon, 25 Mar 2024 14:54:03 +0100 Subject: [PATCH] RMT: allow driver to init as blocking or async (#1341) * RMT: allow driver to init as blocking or async * CHANGELOG and minor fixes --- esp-hal-procmacros/src/lib.rs | 56 ++- esp-hal/CHANGELOG.md | 1 + esp-hal/src/embassy/mod.rs | 3 - esp-hal/src/interrupt/xtensa.rs | 15 + esp-hal/src/lib.rs | 2 + esp-hal/src/rmt.rs | 587 +++++++++++++++++++++-------- esp-hal/src/soc/esp32/mod.rs | 2 + esp-hal/src/soc/esp32s2/mod.rs | 2 + esp-hal/src/soc/esp32s3/mod.rs | 2 + examples/src/bin/embassy_rmt_rx.rs | 4 +- examples/src/bin/embassy_rmt_tx.rs | 4 +- examples/src/bin/hello_rgb.rs | 4 +- examples/src/bin/rmt_rx.rs | 2 +- examples/src/bin/rmt_tx.rs | 2 +- 14 files changed, 500 insertions(+), 186 deletions(-) diff --git a/esp-hal-procmacros/src/lib.rs b/esp-hal-procmacros/src/lib.rs index 1f285faa8..fb5f094f5 100644 --- a/esp-hal-procmacros/src/lib.rs +++ b/esp-hal-procmacros/src/lib.rs @@ -361,9 +361,12 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream { /// Mark a function as an interrupt handler. /// -/// This is really just a nicer looking way to make a function `unsafe extern -/// "C"` +/// Optionally a priority can be specified, e.g. `#[handler("Priority3")]`, +/// "min" and "max" are special values. +/// +/// If no priority is given, "Priority::min()" is assumed #[cfg(feature = "interrupt")] +#[proc_macro_error::proc_macro_error] #[proc_macro_attribute] pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { use darling::ast::NestedMeta; @@ -385,9 +388,40 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { } }; - if attr_args.len() > 0 { - abort!(Span::call_site(), "This attribute accepts no arguments") - } + let root = Ident::new( + 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? @@ -419,17 +453,9 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { .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"); let orig = f.sig.ident; + let vis = f.vis.clone(); f.sig.ident = Ident::new( &format!("__esp_hal_internal_{}", orig), proc_macro2::Span::call_site(), @@ -440,7 +466,7 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream { #f #[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() } diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 3c4add5db..d039ad349 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -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) - 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) +- `Rmt` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument. (#1341) ### Removed diff --git a/esp-hal/src/embassy/mod.rs b/esp-hal/src/embassy/mod.rs index cba292ba7..ef3b907f0 100644 --- a/esp-hal/src/embassy/mod.rs +++ b/esp-hal/src/embassy/mod.rs @@ -150,9 +150,6 @@ pub fn init(clocks: &Clocks, td: time_driver::TimerType) { #[cfg(i2s1)] crate::interrupt::enable(Interrupt::I2S1, Priority::min()).unwrap(); - #[cfg(rmt)] - crate::interrupt::enable(Interrupt::RMT, Priority::min()).unwrap(); - #[cfg(usb_device)] crate::interrupt::enable(Interrupt::USB_DEVICE, Priority::min()).unwrap(); diff --git a/esp-hal/src/interrupt/xtensa.rs b/esp-hal/src/interrupt/xtensa.rs index 7545a951a..d8b37231a 100644 --- a/esp-hal/src/interrupt/xtensa.rs +++ b/esp-hal/src/interrupt/xtensa.rs @@ -68,6 +68,21 @@ pub const RESERVED_INTERRUPTS: &[usize] = &[ 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 /// /// Unless you are sure, you most likely want to use [`enable`] with the diff --git a/esp-hal/src/lib.rs b/esp-hal/src/lib.rs index fd4b4f5b8..78665da2e 100644 --- a/esp-hal/src/lib.rs +++ b/esp-hal/src/lib.rs @@ -158,9 +158,11 @@ extern "C" fn EspDefaultHandler(_interrupt: peripherals::Interrupt) { pub trait Mode: crate::private::Sealed {} /// Driver initialized in blocking mode. +#[derive(Debug)] pub struct Blocking; /// Driver initialized in async mode. +#[derive(Debug)] pub struct Async; impl crate::Mode for Blocking {} diff --git a/esp-hal/src/rmt.rs b/esp-hal/src/rmt.rs index 52820fd2f..543d03b64 100644 --- a/esp-hal/src/rmt.rs +++ b/esp-hal/src/rmt.rs @@ -83,11 +83,14 @@ //! channel = transaction.wait().unwrap(); //! ``` +use core::marker::PhantomData; + use fugit::HertzU32; use crate::{ clock::Clocks, gpio::{InputPin, OutputPin}, + interrupt::InterruptHandler, peripheral::Peripheral, rmt::private::CreateInstance, soc::constants, @@ -201,12 +204,18 @@ pub struct RxChannelConfig { pub use impl_for_chip::Rmt; -impl<'d> Rmt<'d> { - /// Create a new RMT instance - pub fn new( +#[cfg(feature = "async")] +use self::asynch::{RxChannelAsync, TxChannelAsync}; + +impl<'d, M> Rmt<'d, M> +where + M: crate::Mode, +{ + pub fn new_internal( peripheral: impl Peripheral

+ 'd, frequency: HertzU32, _clocks: &Clocks, + interrupt: Option, ) -> Result { let me = Rmt::create(peripheral); @@ -223,6 +232,17 @@ impl<'d> Rmt<'d> { #[cfg(any(esp32, esp32s2))] self::chip_specific::configure_clock(); + if let Some(interrupt) = interrupt { + unsafe { + crate::interrupt::bind_interrupt( + crate::peripherals::Interrupt::RMT, + interrupt.handler(), + ); + crate::interrupt::enable(crate::peripherals::Interrupt::RMT, interrupt.priority()) + .unwrap(); + } + } + Ok(me) } @@ -246,6 +266,35 @@ impl<'d> Rmt<'d> { } } +impl<'d> Rmt<'d, crate::Blocking> { + /// Create a new RMT instance + pub fn new( + peripheral: impl Peripheral

+ 'd, + frequency: HertzU32, + _clocks: &Clocks, + interrupt: Option, + ) -> Result { + Self::new_internal(peripheral, frequency, _clocks, interrupt) + } +} + +#[cfg(feature = "async")] +impl<'d> Rmt<'d, crate::Async> { + /// Create a new RMT instance + pub fn new_async( + peripheral: impl Peripheral

+ 'd, + frequency: HertzU32, + _clocks: &Clocks, + ) -> Result { + Self::new_internal( + peripheral, + frequency, + _clocks, + Some(asynch::async_interrupt_handler), + ) + } +} + pub trait TxChannelCreator<'d, T, P> where P: OutputPin, @@ -276,6 +325,37 @@ where } } +#[cfg(feature = "async")] +pub trait TxChannelCreatorAsync<'d, T, P> +where + P: OutputPin, + T: TxChannelAsync, +{ + /// Configure the TX channel + fn configure( + self, + pin: impl Peripheral

+ 'd, + config: TxChannelConfig, + ) -> Result + where + Self: Sized, + { + crate::into_ref!(pin); + pin.set_to_push_pull_output() + .connect_peripheral_to_output(T::output_signal()); + T::set_divider(config.clk_divider); + T::set_carrier( + config.carrier_modulation, + config.carrier_high, + config.carrier_low, + config.carrier_level, + ); + T::set_idle_output(config.idle_output, config.idle_output_level); + + Ok(T::new()) + } +} + pub trait RxChannelCreator<'d, T, P> where P: InputPin, @@ -321,6 +401,52 @@ where } } +#[cfg(feature = "async")] +pub trait RxChannelCreatorAsync<'d, T, P> +where + P: InputPin, + T: RxChannelAsync, +{ + /// Configure the RX channel + fn configure( + self, + pin: impl Peripheral

+ 'd, + config: RxChannelConfig, + ) -> Result + where + Self: Sized, + { + if config.filter_threshold > 0b111_1111 { + return Err(Error::InvalidArgument); + } + + #[cfg(any(esp32, esp32s2))] + if config.idle_threshold > 0b111_1111_1111_1111 { + return Err(Error::InvalidArgument); + } + + #[cfg(not(any(esp32, esp32s2)))] + if config.idle_threshold > 0b11_1111_1111_1111 { + return Err(Error::InvalidArgument); + } + + crate::into_ref!(pin); + pin.set_to_input() + .connect_input_to_peripheral(T::input_signal()); + T::set_divider(config.clk_divider); + T::set_carrier( + config.carrier_modulation, + config.carrier_high, + config.carrier_low, + config.carrier_level, + ); + T::set_filter_threshold(config.filter_threshold); + T::set_idle_threshold(config.idle_threshold); + + Ok(T::new()) + } +} + /// An in-progress transaction for a single shot TX transaction. pub struct SingleShotTxTransaction<'a, C, T: Into + Copy> where @@ -338,18 +464,18 @@ where /// Wait for the transaction to complete pub fn wait(mut self) -> Result { loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } if self.index < self.data.len() { // wait for TX-THR loop { - if ::is_threshold_set() { + if >::is_threshold_set() { break; } } - ::reset_threshold_set(); + >::reset_threshold_set(); // re-fill TX RAM let ram_index = (((self.index - constants::RMT_CHANNEL_RAM_SIZE) @@ -377,11 +503,11 @@ where } loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } @@ -404,15 +530,15 @@ where { /// Stop transaction when the current iteration ends. pub fn stop_next(self) -> Result { - ::set_continuous(false); - ::update(); + >::set_continuous(false); + >::update(); loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } @@ -422,8 +548,8 @@ where /// Stop transaction as soon as possible. pub fn stop(self) -> Result { - ::set_continuous(false); - ::update(); + >::set_continuous(false); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -435,11 +561,11 @@ where } loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } @@ -448,71 +574,110 @@ where } pub fn is_loopcount_interrupt_set(&self) -> bool { - ::is_loopcount_interrupt_set() + >::is_loopcount_interrupt_set() } } macro_rules! impl_tx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$channel>, P> - for ChannelCreator<$channel> + impl<'d, P> $crate::rmt::TxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::OutputPin, { } - impl $crate::rmt::TxChannel for $crate::rmt::Channel<$channel> {} + impl $crate::rmt::TxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} #[cfg(feature = "async")] - impl $crate::rmt::asynch::TxChannelAsync for $crate::rmt::Channel<$channel> {} + impl<'d, P> $crate::rmt::TxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + for ChannelCreator<$crate::Async, $channel> + where + P: $crate::gpio::OutputPin, + { + } + + #[cfg(feature = "async")] + impl $crate::rmt::asynch::TxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } macro_rules! impl_rx_channel_creator { ($channel:literal) => { - impl<'d, P> $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$channel>, P> - for ChannelCreator<$channel> + impl<'d, P> $crate::rmt::RxChannelCreator<'d, $crate::rmt::Channel<$crate::Blocking, $channel>, P> + for ChannelCreator<$crate::Blocking, $channel> where P: $crate::gpio::InputPin, { } - impl $crate::rmt::RxChannel for $crate::rmt::Channel<$channel> {} + impl $crate::rmt::RxChannel for $crate::rmt::Channel<$crate::Blocking, $channel> {} #[cfg(feature = "async")] - impl $crate::rmt::asynch::RxChannelAsync for $crate::rmt::Channel<$channel> {} + impl<'d, P> $crate::rmt::RxChannelCreatorAsync<'d, $crate::rmt::Channel<$crate::Async, $channel>, P> + for ChannelCreator<$crate::Async, $channel> + where + P: $crate::gpio::InputPin, + { + } + + #[cfg(feature = "async")] + impl $crate::rmt::asynch::RxChannelAsync for $crate::rmt::Channel<$crate::Async, $channel> {} }; } #[cfg(not(any(esp32, esp32s2, esp32s3)))] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -529,41 +694,72 @@ mod impl_for_chip { #[cfg(esp32)] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, - pub channel4: ChannelCreator<4>, - pub channel5: ChannelCreator<5>, - pub channel6: ChannelCreator<6>, - pub channel7: ChannelCreator<7>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + pub channel4: ChannelCreator, + pub channel5: ChannelCreator, + pub channel6: ChannelCreator, + pub channel7: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, - channel4: ChannelCreator {}, - channel5: ChannelCreator {}, - channel6: ChannelCreator {}, - channel7: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + channel4: ChannelCreator { + phantom: PhantomData, + }, + channel5: ChannelCreator { + phantom: PhantomData, + }, + channel6: ChannelCreator { + phantom: PhantomData, + }, + channel7: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -604,33 +800,56 @@ mod impl_for_chip { #[cfg(esp32s2)] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -655,41 +874,72 @@ mod impl_for_chip { #[cfg(esp32s3)] mod impl_for_chip { + use core::marker::PhantomData; + use super::private::CreateInstance; use crate::peripheral::{Peripheral, PeripheralRef}; /// RMT Instance - pub struct Rmt<'d> { + pub struct Rmt<'d, M> + where + M: crate::Mode, + { _peripheral: PeripheralRef<'d, crate::peripherals::RMT>, - pub channel0: ChannelCreator<0>, - pub channel1: ChannelCreator<1>, - pub channel2: ChannelCreator<2>, - pub channel3: ChannelCreator<3>, - pub channel4: ChannelCreator<4>, - pub channel5: ChannelCreator<5>, - pub channel6: ChannelCreator<6>, - pub channel7: ChannelCreator<7>, + pub channel0: ChannelCreator, + pub channel1: ChannelCreator, + pub channel2: ChannelCreator, + pub channel3: ChannelCreator, + pub channel4: ChannelCreator, + pub channel5: ChannelCreator, + pub channel6: ChannelCreator, + pub channel7: ChannelCreator, + phantom: PhantomData, } - impl<'d> CreateInstance<'d> for Rmt<'d> { + impl<'d, M> CreateInstance<'d> for Rmt<'d, M> + where + M: crate::Mode, + { fn create(peripheral: impl Peripheral

+ 'd) -> Self { crate::into_ref!(peripheral); Self { _peripheral: peripheral, - channel0: ChannelCreator {}, - channel1: ChannelCreator {}, - channel2: ChannelCreator {}, - channel3: ChannelCreator {}, - channel4: ChannelCreator {}, - channel5: ChannelCreator {}, - channel6: ChannelCreator {}, - channel7: ChannelCreator {}, + channel0: ChannelCreator { + phantom: PhantomData, + }, + channel1: ChannelCreator { + phantom: PhantomData, + }, + channel2: ChannelCreator { + phantom: PhantomData, + }, + channel3: ChannelCreator { + phantom: PhantomData, + }, + channel4: ChannelCreator { + phantom: PhantomData, + }, + channel5: ChannelCreator { + phantom: PhantomData, + }, + channel6: ChannelCreator { + phantom: PhantomData, + }, + channel7: ChannelCreator { + phantom: PhantomData, + }, + phantom: PhantomData, } } } - pub struct ChannelCreator {} + pub struct ChannelCreator + where + M: crate::Mode, + { + phantom: PhantomData, + } impl_tx_channel_creator!(0); impl_tx_channel_creator!(1); @@ -715,9 +965,14 @@ mod impl_for_chip { /// RMT Channel #[non_exhaustive] #[derive(Debug)] -pub struct Channel {} +pub struct Channel +where + M: crate::Mode, +{ + phantom: PhantomData, +} -pub trait TxChannel: private::TxChannelInternal { +pub trait TxChannel: private::TxChannelInternal { /// Start transmitting the given pulse code sequence. /// This returns a [`SingleShotTxTransaction`] which can be used to wait for /// the transaction to complete and get back the channel for further @@ -784,18 +1039,18 @@ where /// Wait for the transaction to complete pub fn wait(self) -> Result { loop { - if ::is_error() { + if >::is_error() { return Err((Error::TransmissionError, self.channel)); } - if ::is_done() { + if >::is_done() { break; } } - ::stop(); - ::clear_interrupts(); - ::update(); + >::stop(); + >::clear_interrupts(); + >::update(); let ptr = (constants::RMT_RAM_START + C::CHANNEL as usize * constants::RMT_CHANNEL_RAM_SIZE * 4) @@ -809,7 +1064,7 @@ where } } -pub trait RxChannel: private::RxChannelInternal { +pub trait RxChannel: private::RxChannelInternal { /// Start receiving pulse codes into the given buffer. /// This returns a [RxTransaction] which can be used to wait for receive to /// complete and get back the channel for further use. @@ -834,13 +1089,12 @@ pub trait RxChannel: private::RxChannelInternal { #[cfg(feature = "async")] pub mod asynch { use core::{ - marker::PhantomData, pin::Pin, task::{Context, Poll}, }; use embassy_sync::waitqueue::AtomicWaker; - use procmacros::interrupt; + use procmacros::handler; use super::{private::Event, *}; @@ -887,7 +1141,7 @@ pub mod asynch { } } - pub trait TxChannelAsync: private::TxChannelInternal { + pub trait TxChannelAsync: private::TxChannelInternal { /// Start transmitting the given pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. @@ -948,7 +1202,7 @@ pub mod asynch { } } - pub trait RxChannelAsync: private::RxChannelInternal { + pub trait RxChannelAsync: private::RxChannelInternal { /// Start receiving a pulse code sequence. /// The length of sequence cannot exceed the size of the allocated RMT /// RAM. @@ -988,49 +1242,48 @@ pub mod asynch { } #[cfg(not(any(esp32, esp32s2)))] - #[interrupt] - fn RMT() { + #[handler] + pub(super) fn async_interrupt_handler() { if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { use crate::rmt::private::{RxChannelInternal, TxChannelInternal}; match channel { 0 => { - super::Channel::<0>::unlisten_interrupt(Event::End); - super::Channel::<0>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } 1 => { - super::Channel::<1>::unlisten_interrupt(Event::End); - super::Channel::<1>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } 2 => { - super::Channel::<2>::unlisten_interrupt(Event::End); - super::Channel::<2>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } 3 => { - super::Channel::<3>::unlisten_interrupt(Event::End); - super::Channel::<3>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } - // TODO ... how to handle chips which can use a channel for tx AND rx? #[cfg(any(esp32, esp32s3))] 4 => { - super::Channel::<4>::unlisten_interrupt(Event::End); - super::Channel::<4>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } #[cfg(any(esp32, esp32s3))] 5 => { - super::Channel::<5>::unlisten_interrupt(Event::End); - super::Channel::<5>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } #[cfg(any(esp32, esp32s3))] 6 => { - super::Channel::<6>::unlisten_interrupt(Event::End); - super::Channel::<6>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } #[cfg(any(esp32, esp32s3))] 7 => { - super::Channel::<7>::unlisten_interrupt(Event::End); - super::Channel::<7>::unlisten_interrupt(Event::Error); + super::Channel::::unlisten_interrupt(Event::End); + super::Channel::::unlisten_interrupt(Event::Error); } _ => unreachable!(), @@ -1041,123 +1294,123 @@ pub mod asynch { } #[cfg(any(esp32, esp32s2))] - #[interrupt] - fn RMT() { + #[handler] + pub(super) fn async_interrupt_handler() { if let Some(channel) = super::chip_specific::pending_interrupt_for_channel() { match channel { 0 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } 1 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } 2 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } 3 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(esp32)] 4 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(any(esp32, esp32s3))] 5 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(any(esp32, esp32s3))] 6 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } #[cfg(any(esp32, esp32s3))] 7 => { - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::TxChannelInternal>::unlisten_interrupt( + as super::private::TxChannelInternal>::unlisten_interrupt( Event::Error, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::End, ); - as super::private::RxChannelInternal>::unlisten_interrupt( + as super::private::RxChannelInternal>::unlisten_interrupt( Event::Error, ); } @@ -1183,7 +1436,10 @@ mod private { fn create(peripheral: impl Peripheral

+ 'd) -> Self; } - pub trait TxChannelInternal { + pub trait TxChannelInternal + where + M: crate::Mode, + { const CHANNEL: u8; fn new() -> Self; @@ -1261,7 +1517,10 @@ mod private { fn unlisten_interrupt(event: Event); } - pub trait RxChannelInternal { + pub trait RxChannelInternal + where + M: crate::Mode, + { const CHANNEL: u8; fn new() -> Self; @@ -1396,11 +1655,13 @@ mod chip_specific { macro_rules! impl_tx_channel { ($channel:ident, $signal:ident, $ch_num:literal) => { paste::paste! { - impl $crate::rmt::private::TxChannelInternal for $crate::rmt::$channel<$ch_num> { + impl $crate::rmt::private::TxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn output_signal() -> crate::gpio::OutputSignal { @@ -1587,11 +1848,13 @@ mod chip_specific { macro_rules! impl_rx_channel { ($channel:ident, $signal:ident, $ch_num:literal, $ch_index:literal) => { paste::paste! { - impl $crate::rmt::private::RxChannelInternal for $crate::rmt::$channel<$ch_num> { + impl $crate::rmt::private::RxChannelInternal for $crate::rmt::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn input_signal() -> crate::gpio::InputSignal { @@ -1801,11 +2064,13 @@ mod chip_specific { macro_rules! impl_tx_channel { ($channel:ident, $signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::TxChannelInternal for super::$channel<$ch_num> { + impl super::private::TxChannelInternal for super::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn output_signal() -> crate::gpio::OutputSignal { @@ -1972,11 +2237,13 @@ mod chip_specific { macro_rules! impl_rx_channel { ($channel:ident, $signal:ident, $ch_num:literal) => { paste::paste! { - impl super::private::RxChannelInternal for super::$channel<$ch_num> { + impl super::private::RxChannelInternal for super::$channel where M: $crate::Mode { const CHANNEL: u8 = $ch_num; fn new() -> Self { - Self {} + Self { + phantom: core::marker::PhantomData, + } } fn input_signal() -> crate::gpio::InputSignal { diff --git a/esp-hal/src/soc/esp32/mod.rs b/esp-hal/src/soc/esp32/mod.rs index d9e1b5916..e065a5a6d 100644 --- a/esp-hal/src/soc/esp32/mod.rs +++ b/esp-hal/src/soc/esp32/mod.rs @@ -76,6 +76,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { stack_chk_guard.write_volatile(0xdeadbabe); } + crate::interrupt::setup_interrupts(); + // continue with default reset handler xtensa_lx_rt::Reset(); } diff --git a/esp-hal/src/soc/esp32s2/mod.rs b/esp-hal/src/soc/esp32s2/mod.rs index a54650347..94649c2d9 100644 --- a/esp-hal/src/soc/esp32s2/mod.rs +++ b/esp-hal/src/soc/esp32s2/mod.rs @@ -80,6 +80,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { stack_chk_guard.write_volatile(0xdeadbabe); } + crate::interrupt::setup_interrupts(); + // continue with default reset handler xtensa_lx_rt::Reset(); } diff --git a/esp-hal/src/soc/esp32s3/mod.rs b/esp-hal/src/soc/esp32s3/mod.rs index 5dc5918fc..b2bef618e 100644 --- a/esp-hal/src/soc/esp32s3/mod.rs +++ b/esp-hal/src/soc/esp32s3/mod.rs @@ -115,6 +115,8 @@ pub unsafe extern "C" fn ESP32Reset() -> ! { stack_chk_guard.write_volatile(0xdeadbabe); } + crate::interrupt::setup_interrupts(); + // continue with default reset handler xtensa_lx_rt::Reset(); } diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index 7b61478b7..d5e6637e8 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -18,7 +18,7 @@ use esp_hal::{ gpio::{Gpio5, Output, PushPull, IO}, peripherals::Peripherals, prelude::*, - rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreator}, + rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, }; 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 { clk_divider: 255, idle_threshold: 10000, diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 9cd84873a..ded064cb9 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -18,7 +18,7 @@ use esp_hal::{ gpio::IO, peripherals::Peripherals, prelude::*, - rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreator}, + rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync}, timer::TimerGroup, }; 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 .channel0 diff --git a/examples/src/bin/hello_rgb.rs b/examples/src/bin/hello_rgb.rs index 96e817e21..20ba84e88 100644 --- a/examples/src/bin/hello_rgb.rs +++ b/examples/src/bin/hello_rgb.rs @@ -56,9 +56,9 @@ fn main() -> ! { // Configure RMT peripheral globally #[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")] - 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 // be used directly with all `smart_led` implementations diff --git a/examples/src/bin/rmt_rx.rs b/examples/src/bin/rmt_rx.rs index 69e1123ad..ab2292134 100644 --- a/examples/src/bin/rmt_rx.rs +++ b/examples/src/bin/rmt_rx.rs @@ -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 { clk_divider: 1, diff --git a/examples/src/bin/rmt_tx.rs b/examples/src/bin/rmt_tx.rs index 284324acd..8b267ac3f 100644 --- a/examples/src/bin/rmt_tx.rs +++ b/examples/src/bin/rmt_tx.rs @@ -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 { clk_divider: 255,