diff --git a/Cargo.toml b/Cargo.toml index 55a1dfc..ef4c89c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "rp2040-hal", + "rp2040-hal-macros", "boards/adafruit-feather-rp2040", "boards/adafruit-itsy-bitsy-rp2040", "boards/adafruit-kb2040", diff --git a/rp2040-hal-macros/Cargo.toml b/rp2040-hal-macros/Cargo.toml new file mode 100644 index 0000000..64e6cfc --- /dev/null +++ b/rp2040-hal-macros/Cargo.toml @@ -0,0 +1,20 @@ +[package] +description = "Macros used by rp2040-hal" +license = "MIT OR Apache-2.0" +name = "rp2040-hal-macros" +readme = "README.md" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0" +proc-macro2 = "1.0" +cortex-m-rt = "0.7.0" + +[dependencies.syn] +features = ["extra-traits", "full"] +version = "1.0" + diff --git a/rp2040-hal-macros/README.md b/rp2040-hal-macros/README.md new file mode 100644 index 0000000..00c62c9 --- /dev/null +++ b/rp2040-hal-macros/README.md @@ -0,0 +1,27 @@ +# `rp2040-hal-macros` + +Macros used by rp2040-hal. + +## Entry macro + +Extension of the `cortex-m-rt` `#[entry]` with rp2040 specific initialization code. + +Currently, it just unlocks all spinlocks before calling the entry function. + +# License + +Licensed under either of + +- Apache License, Version 2.0 (`APACHE2.0` or + http://www.apache.org/licenses/LICENSE-2.0) + +- MIT license (`MIT` or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + diff --git a/rp2040-hal-macros/src/lib.rs b/rp2040-hal-macros/src/lib.rs new file mode 100644 index 0000000..f8e9c71 --- /dev/null +++ b/rp2040-hal-macros/src/lib.rs @@ -0,0 +1,59 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +use proc_macro2::Span; +use quote::quote; +use syn::{parse, parse_macro_input, Item, ItemFn, Stmt}; + +#[proc_macro_attribute] +pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { + let mut f = parse_macro_input!(input as ItemFn); + + if !args.is_empty() { + return parse::Error::new(Span::call_site(), "This attribute accepts no arguments") + .to_compile_error() + .into(); + } + + let clear_locks: TokenStream = quote!(unsafe { + const SIO_BASE: u32 = 0xd0000000; + const SPINLOCK0_PTR: *mut u32 = (SIO_BASE + 0x100) as *mut u32; + const SPINLOCK_COUNT: usize = 32; + for i in 0..SPINLOCK_COUNT { + SPINLOCK0_PTR.wrapping_add(i).write_volatile(1); + } + }) + .into(); + let clear_locks = parse_macro_input!(clear_locks as Stmt); + + // statics must stay first so cortex_m_rt::entry still finds them + let stmts = insert_after_static(f.block.stmts, clear_locks); + f.block.stmts = stmts; + + quote!( + #[::cortex_m_rt::entry] + #f + ) + .into() +} + +/// Insert new statements after initial block of statics +fn insert_after_static(stmts: impl IntoIterator, insert: Stmt) -> Vec { + let mut istmts = stmts.into_iter(); + let mut stmts = vec![]; + for stmt in istmts.by_ref() { + match stmt { + Stmt::Item(Item::Static(var)) => { + stmts.push(Stmt::Item(Item::Static(var))); + } + _ => { + stmts.push(insert); + stmts.push(stmt); + break; + } + } + } + stmts.extend(istmts); + + stmts +} diff --git a/rp2040-hal/Cargo.toml b/rp2040-hal/Cargo.toml index d9003be..ea0e1c3 100644 --- a/rp2040-hal/Cargo.toml +++ b/rp2040-hal/Cargo.toml @@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0" [dependencies] cortex-m = "0.7.2" +cortex-m-rt = ">=0.6.15,<0.8" embedded-hal = { version = "0.2.5", features = ["unproven"] } eh1_0_alpha = { version = "=1.0.0-alpha.7", package="embedded-hal", optional=true } embedded-time = "0.12.0" @@ -19,6 +20,7 @@ nb = "1.0" rp2040-pac = "0.3.0" paste = "1.0" pio = "0.2.0" +rp2040-hal-macros = { version = "0.1.0", path = "../rp2040-hal-macros" } usb-device = "0.2.8" vcell = "0.1" void = { version = "1.0.2", default-features = false } diff --git a/rp2040-hal/src/lib.rs b/rp2040-hal/src/lib.rs index 8d2db4e..3153868 100644 --- a/rp2040-hal/src/lib.rs +++ b/rp2040-hal/src/lib.rs @@ -49,6 +49,15 @@ pub mod xosc; pub use adc::Adc; pub use clocks::Clock; pub use i2c::I2C; +/// Attribute to declare the entry point of the program +/// +/// This is based on and can be used like the [entry attribute from +/// cortex-m-rt](https://docs.rs/cortex-m-rt/latest/cortex_m_rt/attr.entry.html). +/// +/// It extends that macro with code to unlock all spinlocks at the beginning +/// of `main`. As spinlocks are not automatically unlocked on software resets, +/// this can prevent unexpected deadlocks when running from a debugger. +pub use rp2040_hal_macros::entry; pub use sio::Sio; pub use spi::Spi; pub use timer::Timer;