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:
parent
d761ec4def
commit
fd4f5592a4
@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user