Skip to content

Commit

Permalink
Runtime DMA interrupt binding
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoernQ committed Mar 26, 2024
1 parent 7792d67 commit 9d8c91b
Show file tree
Hide file tree
Showing 25 changed files with 1,254 additions and 594 deletions.
41 changes: 16 additions & 25 deletions esp-hal-procmacros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,15 +369,19 @@ pub fn interrupt(args: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_error::proc_macro_error]
#[proc_macro_attribute]
pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
use darling::ast::NestedMeta;
use darling::{ast::NestedMeta, FromMeta};
use proc_macro::Span;
use proc_macro2::Ident;
use proc_macro_crate::{crate_name, FoundCrate};
use proc_macro_error::abort;
use syn::{parse::Error as ParseError, spanned::Spanned, ItemFn, ReturnType, Type};

use self::interrupt::{check_attr_whitelist, WhiteListCaller};

#[derive(Debug, FromMeta)]
struct MacroArgs {
priority: Option<syn::Expr>,
}

let mut f: ItemFn = syn::parse(input).expect("`#[handler]` must be applied to a function");
let original_span = f.span();

Expand All @@ -388,6 +392,13 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
}
};

let args = match MacroArgs::from_list(&attr_args) {
Ok(v) => v,
Err(e) => {
return TokenStream::from(e.write_errors());
}
};

let root = Ident::new(
if let Ok(FoundCrate::Name(ref name)) = crate_name("esp-hal") {
&name
Expand All @@ -397,30 +408,10 @@ pub fn handler(args: TokenStream, input: TokenStream) -> TokenStream {
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"
),
}
let priority = if let Some(priority) = args.priority {
quote::quote!( #priority )
} 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)
}
quote::quote! { #root::interrupt::Priority::min() }
};

// XXX should we blacklist other attributes?
Expand Down
1 change: 1 addition & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `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)
- All `Instance` traits are now sealed, and can no longer be implemented for arbitrary types (#1346)
- DMA channels can/have to be explicitly created for async or blocking drivers, added `set_interrupt_handler` to DMA channels, SPI, I2S, PARL_IO, don't enable interrupts on startup for DMA, I2S, PARL_IO, GPIO (#1300)

### Removed

Expand Down
16 changes: 8 additions & 8 deletions esp-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ xtensa-lx = { version = "0.9.0", optional = true }
# IMPORTANT:
# Each supported device MUST have its PAC included below along with a
# corresponding feature.
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "963c280", features = ["critical-section"], optional = true }
esp32 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32c2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32c3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32s2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }
esp32s3 = { git = "https://github.com/esp-rs/esp-pacs", rev = "f5d274d", features = ["critical-section"], optional = true }

[target.'cfg(target_arch = "riscv32")'.dependencies]
esp-riscv-rt = { version = "0.7.0", optional = true, path = "../esp-riscv-rt" }
Expand Down
6 changes: 3 additions & 3 deletions esp-hal/src/aes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,23 +277,23 @@ pub mod dma {
{
pub aes: super::Aes<'d>,

pub(crate) channel: Channel<'d, C>,
pub(crate) channel: Channel<'d, C, crate::Blocking>,
}

pub trait WithDmaAes<'d, C>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
fn with_dma(self, channel: Channel<'d, C>) -> AesDma<'d, C>;
fn with_dma(self, channel: Channel<'d, C, crate::Blocking>) -> AesDma<'d, C>;
}

impl<'d, C> WithDmaAes<'d, C> for crate::aes::Aes<'d>
where
C: ChannelTypes,
C::P: AesPeripheral,
{
fn with_dma(self, mut channel: Channel<'d, C>) -> AesDma<'d, C> {
fn with_dma(self, mut channel: Channel<'d, C, crate::Blocking>) -> AesDma<'d, C> {
channel.tx.init_channel(); // no need to call this for both, TX and RX

AesDma { aes: self, channel }
Expand Down
77 changes: 65 additions & 12 deletions esp-hal/src/dma/gdma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,30 @@ use crate::{
};

macro_rules! impl_channel {
($num: literal) => {
($num: literal, $async_handler: path, $($interrupt: ident),* ) => {
paste::paste! {
#[non_exhaustive]
pub struct [<Channel $num InterruptBinder>] {}

impl InterruptBinder for [<Channel $num InterruptBinder>] {
#[cfg(feature = "vectored")]
fn set_isr(handler: $crate::interrupt::InterruptHandler) {
let mut dma = unsafe { crate::peripherals::DMA::steal() };
$(
dma.[< bind_ $interrupt:lower _interrupt >](handler.handler());
$crate::interrupt::enable($crate::peripherals::Interrupt::$interrupt, handler.priority()).unwrap();
)*
}
}

#[non_exhaustive]
pub struct [<Channel $num>] {}

impl ChannelTypes for [<Channel $num>] {
type P = [<SuitablePeripheral $num>];
type Tx<'a> = ChannelTx<'a, [<Channel $num TxImpl>], [<Channel $num>]>;
type Rx<'a> = ChannelRx<'a, [<Channel $num RxImpl>], [<Channel $num>]>;
type Binder = [<Channel $num InterruptBinder>];
}

impl RegisterAccess for [<Channel $num>] {
Expand Down Expand Up @@ -550,7 +565,7 @@ macro_rules! impl_channel {
pub struct [<ChannelCreator $num>] {}

impl [<ChannelCreator $num>] {
/// Configure the channel for use
/// Configure the channel for use with blocking APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
Expand All @@ -560,16 +575,44 @@ macro_rules! impl_channel {
tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority,
) -> Channel<'a, [<Channel $num>]> {
) -> Channel<'a, [<Channel $num>], $crate::Blocking> {
let mut tx_impl = [<Channel $num TxImpl>] {};
tx_impl.init(burst_mode, priority);

let mut rx_impl = [<Channel $num RxImpl>] {};
rx_impl.init(burst_mode, priority);

Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
phantom: PhantomData,
}
}

/// Configure the channel for use with async APIs
///
/// Descriptors should be sized as `(CHUNK_SIZE + 4091) / 4092`. I.e., to
/// transfer buffers of size `1..=4092`, you need 1 descriptor.
#[cfg(feature = "async")]
pub fn configure_for_async<'a>(
self,
burst_mode: bool,
tx_descriptors: &'a mut [DmaDescriptor],
rx_descriptors: &'a mut [DmaDescriptor],
priority: DmaPriority,
) -> Channel<'a, [<Channel $num>], $crate::Async> {
let mut tx_impl = [<Channel $num TxImpl>] {};
tx_impl.init(burst_mode, priority);

let mut rx_impl = [<Channel $num RxImpl>] {};
rx_impl.init(burst_mode, priority);

<[<Channel $num>] as ChannelTypes>::Binder::set_isr($async_handler);

Channel {
tx: ChannelTx::new(tx_descriptors, tx_impl, burst_mode),
rx: ChannelRx::new(rx_descriptors, rx_impl, burst_mode),
phantom: PhantomData,
}
}
}
Expand All @@ -596,15 +639,25 @@ macro_rules! impl_channel {
};
}

impl_channel!(0);
#[cfg(not(esp32c2))]
impl_channel!(1);
#[cfg(not(esp32c2))]
impl_channel!(2);
#[cfg(esp32s3)]
impl_channel!(3);
#[cfg(esp32s3)]
impl_channel!(4);
cfg_if::cfg_if! {
if #[cfg(esp32c2)] {
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
} else if #[cfg(esp32c3)] {
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_CH0);
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_CH1);
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_CH2);
} else if #[cfg(any(esp32c6, esp32h2))] {
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0);
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1);
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2);
} else if #[cfg(esp32s3)] {
impl_channel!(0, super::asynch::interrupt::interrupt_handler_ch0, DMA_IN_CH0, DMA_OUT_CH0);
impl_channel!(1, super::asynch::interrupt::interrupt_handler_ch1, DMA_IN_CH1, DMA_OUT_CH1);
impl_channel!(2, super::asynch::interrupt::interrupt_handler_ch2, DMA_IN_CH2, DMA_OUT_CH2);
impl_channel!(3, super::asynch::interrupt::interrupt_handler_ch3, DMA_IN_CH3, DMA_OUT_CH3);
impl_channel!(4, super::asynch::interrupt::interrupt_handler_ch4, DMA_IN_CH4, DMA_OUT_CH4);
}
}

/// GDMA Peripheral
///
Expand Down
Loading

0 comments on commit 9d8c91b

Please sign in to comment.