diff options
| author | Dummyc0m <[email protected]> | 2024-10-06 23:23:33 -0700 |
|---|---|---|
| committer | Dummyc0m <[email protected]> | 2024-10-06 23:33:34 -0700 |
| commit | 9e6e09a8d747ec90aae215df8471dfe349993487 (patch) | |
| tree | 0cd116be26fea69f9b770b3f36c87fc1273ae20b /embassy-executor-macros | |
| parent | 8f273497453d3ca3f297465b67820d4d36705d11 (diff) | |
executor/spin: introduce an architecture agnostic executor
Spin polls the raw executor and never sleeps. It is useful for disabling
any power features associated with wfi/wfe-like instructions.
When implementing support for the CH32V30x MCU, the wfi instruction
had issues interacting with the USB OTG peripheral and appeared to be
non-spec-compliant.
1. When sending a USB Data-in packet, the USB peripheral appears to be
unable to read the system main memory while in WFI. This manifests in
the USB peripheral sending all or partially zeroed DATA packets.
Disabling WFI works around this issue.
2. The WFI instruction does not wake up the processor when MIE is
disabled. The MCU provides a WFITOWFE bit to emulate the WFE instruction
on arm, which, when enabled, ignores the MIE and allows the processor to
wake up. This works around the non-compliant WFI implementation.
Co-authored-by: Codetector <[email protected]>
Co-authored-by: Dummyc0m <[email protected]>
Diffstat (limited to 'embassy-executor-macros')
| -rw-r--r-- | embassy-executor-macros/src/lib.rs | 29 | ||||
| -rw-r--r-- | embassy-executor-macros/src/macros/main.rs | 29 |
2 files changed, 57 insertions, 1 deletions
diff --git a/embassy-executor-macros/src/lib.rs b/embassy-executor-macros/src/lib.rs index 5461fe04c..61d388b9e 100644 --- a/embassy-executor-macros/src/lib.rs +++ b/embassy-executor-macros/src/lib.rs | |||
| @@ -94,6 +94,35 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { | |||
| 94 | main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into() | 94 | main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into() |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /// Creates a new `executor` instance and declares an architecture agnostic application entry point spawning | ||
| 98 | /// the corresponding function body as an async task. | ||
| 99 | /// | ||
| 100 | /// The following restrictions apply: | ||
| 101 | /// | ||
| 102 | /// * The function must accept exactly 1 parameter, an `embassy_executor::Spawner` handle that it can use to spawn additional tasks. | ||
| 103 | /// * The function must be declared `async`. | ||
| 104 | /// * The function must not use generics. | ||
| 105 | /// * Only a single `main` task may be declared. | ||
| 106 | /// | ||
| 107 | /// A user-defined entry macro must provided via the `entry` argument | ||
| 108 | /// | ||
| 109 | /// ## Examples | ||
| 110 | /// Spawning a task: | ||
| 111 | /// ``` rust | ||
| 112 | /// #[embassy_executor::main(entry = "qingke_rt::entry")] | ||
| 113 | /// async fn main(_s: embassy_executor::Spawner) { | ||
| 114 | /// // Function body | ||
| 115 | /// } | ||
| 116 | /// ``` | ||
| 117 | #[proc_macro_attribute] | ||
| 118 | pub fn main_spin(args: TokenStream, item: TokenStream) -> TokenStream { | ||
| 119 | let args = syn::parse_macro_input!(args as Args); | ||
| 120 | let f = syn::parse_macro_input!(item as syn::ItemFn); | ||
| 121 | main::run(&args.meta, f, main::spin(&args.meta)) | ||
| 122 | .unwrap_or_else(|x| x) | ||
| 123 | .into() | ||
| 124 | } | ||
| 125 | |||
| 97 | /// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. | 126 | /// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. |
| 98 | /// | 127 | /// |
| 99 | /// The following restrictions apply: | 128 | /// The following restrictions apply: |
diff --git a/embassy-executor-macros/src/macros/main.rs b/embassy-executor-macros/src/macros/main.rs index 26dfa2397..66a3965d0 100644 --- a/embassy-executor-macros/src/macros/main.rs +++ b/embassy-executor-macros/src/macros/main.rs | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | use darling::export::NestedMeta; | 1 | use darling::export::NestedMeta; |
| 2 | use darling::FromMeta; | 2 | use darling::{Error, FromMeta}; |
| 3 | use proc_macro2::TokenStream; | 3 | use proc_macro2::TokenStream; |
| 4 | use quote::quote; | 4 | use quote::quote; |
| 5 | use syn::{Expr, ReturnType, Type}; | 5 | use syn::{Expr, ReturnType, Type}; |
| @@ -50,6 +50,33 @@ pub fn riscv(args: &[NestedMeta]) -> TokenStream { | |||
| 50 | } | 50 | } |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | pub fn spin(args: &[NestedMeta]) -> TokenStream { | ||
| 54 | let maybe_entry = match Args::from_list(args) { | ||
| 55 | Ok(args) => args.entry, | ||
| 56 | Err(e) => return e.write_errors(), | ||
| 57 | }; | ||
| 58 | |||
| 59 | let entry = match maybe_entry { | ||
| 60 | Some(str) => str, | ||
| 61 | None => return Error::missing_field("entry").write_errors(), | ||
| 62 | }; | ||
| 63 | let entry = match Expr::from_string(&entry) { | ||
| 64 | Ok(expr) => expr, | ||
| 65 | Err(e) => return e.write_errors(), | ||
| 66 | }; | ||
| 67 | |||
| 68 | quote! { | ||
| 69 | #[#entry] | ||
| 70 | fn main() -> ! { | ||
| 71 | let mut executor = ::embassy_executor::Executor::new(); | ||
| 72 | let executor = unsafe { __make_static(&mut executor) }; | ||
| 73 | executor.run(|spawner| { | ||
| 74 | spawner.must_spawn(__embassy_main(spawner)); | ||
| 75 | }) | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 53 | pub fn cortex_m() -> TokenStream { | 80 | pub fn cortex_m() -> TokenStream { |
| 54 | quote! { | 81 | quote! { |
| 55 | #[cortex_m_rt::entry] | 82 | #[cortex_m_rt::entry] |
