diff --git a/.gdbinit b/.gdbinit
new file mode 100644
index 0000000000000000000000000000000000000000..7c72d4fb1f4064ffbe5275f665caa65846bf90da
--- /dev/null
+++ b/.gdbinit
@@ -0,0 +1,6 @@
+target remote :3333
+
+monitor arm semihosting enable
+
+load
+step
diff --git a/.gitignore b/.gitignore
index 7a8e51cd0f349176d8598b1afc05a376c25085de..8bc31d43a2d39b57699e85de873a64b479ab7556 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 **/*.rs.bk
 *.org
+.gdb_history
 Cargo.lock
 target/
diff --git a/Cargo.toml b/Cargo.toml
index 8ce7bdb23d1c88c8122418cea38ed3f86c3f4357..f7fe92abfc154f9ac0f273a2a6692bdd0aa6081b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ authors = [
   "Per Lindgren <per.lindgren@ltu.se>",
 ]
 categories = ["concurrency", "embedded", "no-std"]
-description = "Real Time For the Masses (RTFM), a framework for building concurrent applications, for ARM Cortex-M microcontrollers"
+description = "Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers"
 documentation = "https://docs.rs/cortex-m-rtfm"
 keywords = ["arm", "cortex-m"]
 license = "MIT OR Apache-2.0"
@@ -14,8 +14,8 @@ version = "0.2.0"
 
 [dependencies]
 cortex-m = "0.3.1"
+rtfm-core = "0.1.0"
 static-ref = "0.2.1"
-rtfm-core = { git = "https://github.com/japaric/rtfm-core" }
 
 [dependencies.cortex-m-rtfm-macros]
 path = "macros"
diff --git a/README.md b/README.md
index eb9555f68665162fe1c108e325e00316fe2424a0..240e2f8fa726ac52363401899afb4dacd8928493 100644
--- a/README.md
+++ b/README.md
@@ -3,10 +3,9 @@
 
 # `cortex-m-rtfm`
 
-> Real Time For the Masses (RTFM), a framework for building concurrent
-> applications, for ARM Cortex-M MCUs
+> Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
 
-# [Manual](https://docs.rs/cortex-m-rtfm)
+# [Documentation](https://docs.rs/cortex-m-rtfm)
 
 # License
 
diff --git a/examples/full-syntax.rs b/examples/full-syntax.rs
index 20e8dfbce7db6902478ccb9d6f3d26891129f0fb..9b6b394e5e7442d6149a155a9e6ba0e7e12435cb 100644
--- a/examples/full-syntax.rs
+++ b/examples/full-syntax.rs
@@ -1,6 +1,5 @@
 //! A showcase of the `app!` macro syntax
 #![deny(unsafe_code)]
-#![feature(const_fn)]
 #![feature(proc_macro)]
 #![no_std]
 
diff --git a/examples/nested.rs b/examples/nested.rs
index 7013170910fce47a274d0a43da0f345770d4c876..1c164f86b029d221f2bd2ce0a2302bc9143ebcf2 100644
--- a/examples/nested.rs
+++ b/examples/nested.rs
@@ -3,7 +3,6 @@
 //! If you run this program you'll hit the breakpoints as indicated by the
 //! letters in the comments: A, then B, then C, etc.
 #![deny(unsafe_code)]
-#![feature(const_fn)]
 #![feature(proc_macro)]
 #![no_std]
 
@@ -59,13 +58,14 @@ fn idle() -> ! {
     }
 }
 
-fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
+#[allow(non_snake_case)]
+fn exti0(
+    t: &mut Threshold,
+    EXTI0::Resources { mut LOW, mut HIGH }: EXTI0::Resources,
+) {
     // Because this task has a priority of 1 the preemption threshold `t` also
     // starts at 1
 
-    let mut low = r.LOW;
-    let mut high = r.HIGH;
-
     // B
     rtfm::bkpt();
 
@@ -73,7 +73,7 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
     rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
 
     // A claim creates a critical section
-    low.claim_mut(t, |_low, t| {
+    LOW.claim_mut(t, |_low, t| {
         // This claim increases the preemption threshold to 2
         //
         // 2 is just high enough to not race with task `exti1` for access to the
@@ -94,7 +94,7 @@ fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
         rtfm::bkpt();
 
         // Claims can be nested
-        high.claim_mut(t, |_high, _| {
+        HIGH.claim_mut(t, |_high, _| {
             // This claim increases the preemption threshold to 3
 
             // Now `exti2` can't preempt this task
diff --git a/examples/one-task.rs b/examples/one-task.rs
index 556177d0f1f179ab657bd23326ae9618da94992f..e58d9fcd90c543508c8b917fe50382d9d6a02c8f 100644
--- a/examples/one-task.rs
+++ b/examples/one-task.rs
@@ -1,6 +1,5 @@
 //! An application with one task
 #![deny(unsafe_code)]
-#![feature(const_fn)]
 #![feature(proc_macro)]
 #![no_std]
 
@@ -34,17 +33,6 @@ app! {
             // Path to the task handler
             path: sys_tick,
 
-            // This is the priority of the task.
-            //
-            // 1 is the lowest priority a task can have, and the maximum
-            // priority is determined by the number of priority bits the device
-            // has. `stm32f103xx` has 4 priority bits so 16 is the maximum valid
-            // value.
-            //
-            // You can omit this field. If you do the priority is assumed to be
-            // 1.
-            priority: 1,
-
             // These are the resources this task has access to.
             //
             // A resource can be a peripheral like `GPIOC` or a static variable
@@ -54,7 +42,10 @@ app! {
     }
 }
 
-fn init(p: init::Peripherals, _r: init::Resources) {
+fn init(p: init::Peripherals, r: init::Resources) {
+    // `init` can modify all the `resources` declared in `app!`
+    r.ON;
+
     // power on GPIOC
     p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
 
@@ -81,7 +72,7 @@ fn idle() -> ! {
 //
 // `_t` is the preemption threshold token. We won't use it in this program.
 //
-// `r` is the set of resources this task has access to. `TIMER0_A1::Resources`
+// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
 // has one field per resource declared in `app!`.
 fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
     // toggle state
diff --git a/examples/preemption.rs b/examples/preemption.rs
index 256b9bddfd0890e9bf2cd4e39d668593050294b2..5fda37d57e1902ae7164014d4de876589256d0a8 100644
--- a/examples/preemption.rs
+++ b/examples/preemption.rs
@@ -1,6 +1,5 @@
 //! Two tasks running at *different* priorities with access to the same resource
 #![deny(unsafe_code)]
-#![feature(const_fn)]
 #![feature(proc_macro)]
 #![no_std]
 
@@ -58,8 +57,11 @@ fn tim2(t: &mut Threshold, mut r: TIM2::Resources) {
     // As this task runs at lower priority it needs a critical section to
     // prevent `sys_tick` from preempting it while it modifies this resource
     // data. The critical section is required to prevent data races which can
-    // lead to undefined behavior
-    r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
+    // lead to undefined behavior.
+    r.COUNTER.claim_mut(t, |counter, _t| {
+        // `claim_mut` creates a critical section
+        **counter += 1;
+    });
 
     // ..
 }
diff --git a/examples/two-tasks.rs b/examples/two-tasks.rs
index ea059a024829f57b53a157e55c56eed2089f9336..2200e5baa0b7b2cd46f541a76d689ec00d34beec 100644
--- a/examples/two-tasks.rs
+++ b/examples/two-tasks.rs
@@ -1,7 +1,5 @@
 //! Two tasks running at the *same* priority with access to the same resource
-
 #![deny(unsafe_code)]
-#![feature(const_fn)]
 #![feature(proc_macro)]
 #![no_std]
 
@@ -31,8 +29,6 @@ app! {
     },
 }
 
-// When data resources are declared in the top `resources` field, `init` will
-// have full access to them
 fn init(_p: init::Peripherals, _r: init::Resources) {
     // ..
 }
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index 4237e21e8a5fa907bd6730374f61acd5ac1e4cda..a62d20892bd75e396b6ace60e3aa7ba0c344d960 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -6,11 +6,8 @@ version = "0.1.0"
 [dependencies]
 error-chain = "0.10.0"
 quote = "0.3.15"
+rtfm-syntax = "0.1.0"
 syn = "0.11.11"
 
-[dependencies.rtfm-syntax]
-git = "https://github.com/japaric/rtfm-syntax"
-optional = false
-
 [lib]
 proc-macro = true
diff --git a/macros/src/check.rs b/macros/src/check.rs
index 42dd3c9ecad4f3c097734004136f9dc3d75cb1bb..3cd112acfd1758d2847365cd91434dd005151d41 100644
--- a/macros/src/check.rs
+++ b/macros/src/check.rs
@@ -2,7 +2,7 @@ use std::collections::HashMap;
 
 use syn::{Ident, Path};
 use syntax::check::{self, Idle, Init};
-use syntax::{self, Idents, Statics};
+use syntax::{self, Resources, Statics};
 
 use syntax::error::*;
 
@@ -51,7 +51,7 @@ pub struct Task {
     pub kind: Kind,
     pub path: Path,
     pub priority: u8,
-    pub resources: Idents,
+    pub resources: Resources,
 }
 
 pub fn app(app: check::App) -> Result<App> {
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 8ea87fa07650a5b2d2b7a107721f7dc566b14344..2a1f72e418fc9b39ff5806ea5d38bc266d36bf4d 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -1,5 +1,4 @@
 //! Procedural macros for the RTFM framework
-
 #![deny(warnings)]
 #![feature(proc_macro)]
 #![recursion_limit = "128"]
@@ -14,7 +13,6 @@ extern crate syn;
 
 use proc_macro::TokenStream;
 use syntax::App;
-
 use syntax::error::*;
 
 mod analyze;
@@ -23,6 +21,148 @@ mod trans;
 
 /// The `app!` macro, a macro used to specify the tasks and resources of a
 /// RTFM application.
+///
+/// The contents of this macro uses a `key: value` syntax. All the possible keys
+/// are shown below:
+///
+/// ``` text
+/// app! {
+///     device: ..,
+///
+///     resources: { .. },
+///
+///     init: { .. },
+///
+///     idle: { .. },
+///
+///     tasks: { .. },
+/// }
+/// ```
+///
+/// # `device`
+///
+/// The value of this key is a Rust path, like `foo::bar::baz`, that must point to
+/// a *device crate*, a crate generated using `svd2rust`.
+///
+/// # `resources`
+///
+/// This key is optional. Its value is a list of `static` variables. These
+/// variables are the data that can be safely accessed, modified and shared by
+/// tasks.
+///
+/// ``` text
+/// resources: {
+///     static A: bool = false;
+///     static B: i32 = 0;
+///     static C: [u8; 16] = [0; 16];
+///     static D: Thing = Thing::new(..);
+/// }
+/// ```
+///
+/// If this key is omitted its value defaults to an empty list.
+///
+/// # `init`
+///
+/// This key is optional. Its value is a set of key values. All the possible
+/// keys are shown below:
+///
+/// ``` text
+/// init: {
+///     path: ..,
+/// }
+/// ```
+///
+/// ## `init.path`
+///
+/// This key is optional. Its value is a Rust path, like `foo::bar::baz`, that
+/// points to the initialization function.
+///
+/// If the key is omitted its value defaults to `init`.
+///
+/// # `idle`
+///
+/// This key is optional. Its value is a set of key values. All the possible
+/// keys are shown below:
+///
+/// ``` text
+/// idle: {
+///     path: ..,
+///     resources: [..],
+/// }
+/// ```
+///
+/// ## `idle.path`
+///
+/// This key is optional. Its value is a Rust path, like `foo::bar::baz`, that
+/// points to the idle loop function.
+///
+/// If the key is omitted its value defaults to `idle`.
+///
+/// ## `idle.resources`
+///
+/// This key is optional. Its value is a list of resources the `idle` loop has
+/// access to. The resources in this list can refer to the resources listed in
+/// the top `resources` key. If the name doesn't match one of the resources
+/// listed in the top `resources` key the resource is assumed to be a
+/// peripheral.
+///
+/// If omitted its value defaults to an empty list.
+///
+/// # `tasks`
+///
+/// This key is optional. Its value is a list of tasks. Each task itself is a
+/// set of key value pair. The full syntax is shown below:
+///
+/// ``` text
+/// tasks: {
+///     $TASK: {
+///         enabled: ..,
+///         path: ..,
+///         priority: ..,
+///         resources: [..],
+///     },
+/// }
+/// ```
+///
+/// If this key is omitted its value is assumed to be an empty list.
+///
+/// ## `tasks.$TASK`
+///
+/// The key must be either a Cortex-M exception or a device specific interrupt.
+/// `PENDSV`, `SVCALL`, `SYS_TICK` are considered as exceptions. All other names
+/// are assumed to be interrupts.
+///
+/// ## `tasks.$TASK.enabled`
+///
+/// This key is optional for interrupts and forbidden for exceptions. Its value
+/// must be a boolean and indicates whether the interrupt will be enabled
+/// (`true`) or disabled (`false`) after `init` ends and before `idle` starts.
+///
+/// If this key is omitted its value defaults to `true`.
+///
+/// ## `tasks.$TASK.path`
+///
+/// The value of this key is a Rust path, like `foo::bar::baz`, that points to
+/// the handler of this task.
+///
+/// ## `tasks.$TASK.priority`
+///
+/// This key is optional. Its value is an integer with type `u8` that specifies
+/// the priority of this task. The minimum valid priority is 1. The maximum
+/// valid priority depends on the number of the NVIC priority bits the device
+/// has; if the device has 4 priority bits the maximum allowed value would be
+/// 16.
+///
+/// If this key is omitted its value defaults to `1`.
+///
+/// ## `tasks.$TASK.resources`
+///
+/// This key is optional. Its value is a list of resources this task has access
+/// to. The resources in this list can refer to the resources listed in the top
+/// `resources` key. If the name doesn't match one of the resources listed in
+/// the top `resources` key the resource is assumed to be a peripheral.
+///
+/// If omitted its value defaults to an empty list.
 #[proc_macro]
 pub fn app(ts: TokenStream) -> TokenStream {
     match run(ts) {
diff --git a/src/examples/_1_one_task.rs b/src/examples/_1_one_task.rs
index 1bccc2199e6a7e9ec81c1be60d0a82da11b4e9e8..614db2aa8d3bbdf6a86976a0418eb9a455d6b863 100644
--- a/src/examples/_1_one_task.rs
+++ b/src/examples/_1_one_task.rs
@@ -2,7 +2,6 @@
 //!
 //! ```
 //! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
 //! #![feature(proc_macro)]
 //! #![no_std]
 //! 
@@ -36,17 +35,6 @@
 //!             // Path to the task handler
 //!             path: sys_tick,
 //! 
-//!             // This is the priority of the task.
-//!             //
-//!             // 1 is the lowest priority a task can have, and the maximum
-//!             // priority is determined by the number of priority bits the device
-//!             // has. `stm32f103xx` has 4 priority bits so 16 is the maximum valid
-//!             // value.
-//!             //
-//!             // You can omit this field. If you do the priority is assumed to be
-//!             // 1.
-//!             priority: 1,
-//! 
 //!             // These are the resources this task has access to.
 //!             //
 //!             // A resource can be a peripheral like `GPIOC` or a static variable
@@ -56,7 +44,10 @@
 //!     }
 //! }
 //! 
-//! fn init(p: init::Peripherals, _r: init::Resources) {
+//! fn init(p: init::Peripherals, r: init::Resources) {
+//!     // `init` can modify all the `resources` declared in `app!`
+//!     r.ON;
+//! 
 //!     // power on GPIOC
 //!     p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
 //! 
@@ -83,7 +74,7 @@
 //! //
 //! // `_t` is the preemption threshold token. We won't use it in this program.
 //! //
-//! // `r` is the set of resources this task has access to. `TIMER0_A1::Resources`
+//! // `r` is the set of resources this task has access to. `SYS_TICK::Resources`
 //! // has one field per resource declared in `app!`.
 //! fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
 //!     // toggle state
diff --git a/src/examples/_2_two_tasks.rs b/src/examples/_2_two_tasks.rs
index 451293cfe89d4c10f5fb4b754a28720f8407c583..5db991b0e2f10e6a4c98d8042f6369b5e879c0f2 100644
--- a/src/examples/_2_two_tasks.rs
+++ b/src/examples/_2_two_tasks.rs
@@ -1,9 +1,7 @@
 //! Two tasks running at the *same* priority with access to the same resource
 //!
 //! ```
-//! 
 //! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
 //! #![feature(proc_macro)]
 //! #![no_std]
 //! 
@@ -33,8 +31,6 @@
 //!     },
 //! }
 //! 
-//! // When data resources are declared in the top `resources` field, `init` will
-//! // have full access to them
 //! fn init(_p: init::Peripherals, _r: init::Resources) {
 //!     // ..
 //! }
diff --git a/src/examples/_3_preemption.rs b/src/examples/_3_preemption.rs
index 1f6b244bcb26b30fb8e571227552a1755fde7ef0..9dc8983b5a7d43afa17f0b4cf9a7dbd61c4e08b4 100644
--- a/src/examples/_3_preemption.rs
+++ b/src/examples/_3_preemption.rs
@@ -2,7 +2,6 @@
 //!
 //! ```
 //! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
 //! #![feature(proc_macro)]
 //! #![no_std]
 //! 
@@ -60,8 +59,11 @@
 //!     // As this task runs at lower priority it needs a critical section to
 //!     // prevent `sys_tick` from preempting it while it modifies this resource
 //!     // data. The critical section is required to prevent data races which can
-//!     // lead to undefined behavior
-//!     r.COUNTER.claim_mut(t, |counter, _t| { **counter += 1; });
+//!     // lead to undefined behavior.
+//!     r.COUNTER.claim_mut(t, |counter, _t| {
+//!         // `claim_mut` creates a critical section
+//!         **counter += 1;
+//!     });
 //! 
 //!     // ..
 //! }
diff --git a/src/examples/_4_nested.rs b/src/examples/_4_nested.rs
index d0306210d8638cfead30d178c66e710d84ecda32..94af0bee6d2a95285d7308bcfb05ef28cebe01db 100644
--- a/src/examples/_4_nested.rs
+++ b/src/examples/_4_nested.rs
@@ -5,7 +5,6 @@
 //!
 //! ```
 //! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
 //! #![feature(proc_macro)]
 //! #![no_std]
 //! 
@@ -61,13 +60,14 @@
 //!     }
 //! }
 //! 
-//! fn exti0(t: &mut Threshold, r: EXTI0::Resources) {
+//! #[allow(non_snake_case)]
+//! fn exti0(
+//!     t: &mut Threshold,
+//!     EXTI0::Resources { mut LOW, mut HIGH }: EXTI0::Resources,
+//! ) {
 //!     // Because this task has a priority of 1 the preemption threshold `t` also
 //!     // starts at 1
 //! 
-//!     let mut low = r.LOW;
-//!     let mut high = r.HIGH;
-//! 
 //!     // B
 //!     rtfm::bkpt();
 //! 
@@ -75,7 +75,7 @@
 //!     rtfm::set_pending(Interrupt::EXTI1); // ~> exti1
 //! 
 //!     // A claim creates a critical section
-//!     low.claim_mut(t, |_low, t| {
+//!     LOW.claim_mut(t, |_low, t| {
 //!         // This claim increases the preemption threshold to 2
 //!         //
 //!         // 2 is just high enough to not race with task `exti1` for access to the
@@ -96,7 +96,7 @@
 //!         rtfm::bkpt();
 //! 
 //!         // Claims can be nested
-//!         high.claim_mut(t, |_high, _| {
+//!         HIGH.claim_mut(t, |_high, _| {
 //!             // This claim increases the preemption threshold to 3
 //! 
 //!             // Now `exti2` can't preempt this task
diff --git a/src/examples/_6_full_syntax.rs b/src/examples/_6_full_syntax.rs
index 449bee6cddff11ec453801d8408e945850badaf8..805206578d357303e96b9afe542656d928f177e4 100644
--- a/src/examples/_6_full_syntax.rs
+++ b/src/examples/_6_full_syntax.rs
@@ -2,7 +2,6 @@
 //!
 //! ```
 //! #![deny(unsafe_code)]
-//! #![feature(const_fn)]
 //! #![feature(proc_macro)]
 //! #![no_std]
 //! 
diff --git a/src/lib.rs b/src/lib.rs
index dc856596df4c916a1428039b78153b63ed0222f4..6188ed317497e70ab58e215ef18b42a9792d11ad 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,4 @@
-//! Real Time For the Masses (RTFM), a framework for building concurrent
-//! applications, for ARM Cortex-M microcontrollers
+//! Real Time For the Masses (RTFM) framework for ARM Cortex-M microcontrollers
 //!
 //! This crate is based on [the RTFM framework] created by the Embedded Systems
 //! group at [LuleƄ University of Technology][ltu], led by Prof. Per Lindgren,
@@ -37,24 +36,24 @@
 //!
 //! # Dependencies
 //!
-//! - A device crate generated using [`svd2rust`] v0.11.x. The input SVD file
-//!   *must* contain [`<cpu>`] information.
-//! - A `start` lang time: Vanilla `main` must be supported in binary crates.
-//!   You can use the [`cortex-m-rt`] crate to fulfill the requirement
+//! The application crate must depend on a device crate generated using
+//! [`svd2rust`] v0.11.x and the "rt" feature of that crate must be enabled. The
+//! SVD file used to generate the device crate *must* contain [`<cpu>`]
+//! information.
 //!
 //! [`svd2rust`]: https://docs.rs/svd2rust/0..0/svd2rust/
 //! [`<cpu>`]: https://www.keil.com/pack/doc/CMSIS/SVD/html/elem_cpu.html
-//! [`cortex-m-rt`]: https://docs.rs/cortex-m-rt/0.3.0/cortex_m_rt/
+//!
+//! # More documentation
+//!
+//! The `app!` macro is documented [here](../cortex_m_rtfm_macros/fn.app.html).
 //!
 //! # Examples
 //!
-//! In increasing grade of complexity, see the [examples](./examples/index.html)
+//! In increasing grade of complexity. See the [examples](./examples/index.html)
 //! module.
 #![deny(missing_docs)]
 #![deny(warnings)]
-#![feature(asm)]
-#![feature(const_fn)]
-#![feature(optin_builtin_traits)]
 #![feature(proc_macro)]
 #![no_std]
 
@@ -74,7 +73,9 @@ use cortex_m::register::basepri;
 
 pub mod examples;
 
-/// Executes the closure `f` in an interrupt free context
+/// Executes the closure `f` in a preemption free context
+///
+/// During the execution of the closure no task can preempt the current task.
 pub fn atomic<R, F>(t: &mut Threshold, f: F) -> R
 where
     F: FnOnce(&mut Threshold) -> R,
@@ -127,11 +128,10 @@ where
     }
 }
 
-/// Sets an interrupt as pending
+/// Sets an interrupt, that is a task, as pending
 ///
-/// If the interrupt priority is high enough the interrupt will be serviced
-/// immediately, otherwise it will be serviced at some point after the current
-/// task ends.
+/// If the task priority is high enough the task will be serviced immediately,
+/// otherwise it will be serviced at some point after the current task ends.
 pub fn set_pending<I>(interrupt: I)
 where
     I: Nr,