diff --git a/Cargo.toml b/Cargo.toml
index 5675d76749c55cdaadcf5b7a6ae8a50e6730d71a..37db8565e5758e0ca98f3a451e97ee41e76aa8b8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,13 +10,13 @@ keywords = ["arm", "cortex-m"]
 license = "MIT OR Apache-2.0"
 name = "cortex-m-rtfm"
 repository = "https://github.com/japaric/cortex-m-rtfm"
-version = "0.2.2"
+version = "0.3.0"
 
 [dependencies]
-cortex-m = "0.3.1"
+cortex-m = { git = "https://github.com/japaric/cortex-m" }
 untagged-option = "0.1.1"
 rtfm-core = "0.1.0"
-cortex-m-rtfm-macros = "0.2.1"
+cortex-m-rtfm-macros = { path = "macros" }
 
 [target.'cfg(target_arch = "x86_64")'.dev-dependencies]
 compiletest_rs = "0.3.3"
@@ -27,7 +27,8 @@ version = "0.3.3"
 
 [dev-dependencies.stm32f103xx]
 features = ["rt"]
-version = "0.7.5"
+git = "https://github.com/japaric/stm32f103xx"
+# version = "0.8.0"
 
 [profile.release]
 lto = true
diff --git a/examples/generics.rs b/examples/generics.rs
index 57c9b8ebc600e12d4c74abcede583272f884da55..afcafa0a4026a50497667761ff409fd9bfcf6d75 100644
--- a/examples/generics.rs
+++ b/examples/generics.rs
@@ -12,6 +12,11 @@ use stm32f103xx::{SPI1, GPIOA};
 app! {
     device: stm32f103xx,
 
+    resources: {
+        static GPIOA: GPIOA;
+        static SPI1: SPI1;
+    },
+
     tasks: {
         EXTI0: {
             path: exti0,
@@ -27,7 +32,12 @@ app! {
     },
 }
 
-fn init(_p: init::Peripherals) {}
+fn init(p: init::Peripherals) -> init::LateResourceValues {
+    init::LateResourceValues {
+        GPIOA: p.device.GPIOA,
+        SPI1: p.device.SPI1,
+    }
+}
 
 fn idle() -> ! {
     loop {
diff --git a/examples/one-task.rs b/examples/one-task.rs
index e58d9fcd90c543508c8b917fe50382d9d6a02c8f..38f0135467fdff1705668a8c32ede7010f0bdd96 100644
--- a/examples/one-task.rs
+++ b/examples/one-task.rs
@@ -7,8 +7,9 @@ extern crate cortex_m;
 extern crate cortex_m_rtfm as rtfm;
 extern crate stm32f103xx;
 
-use cortex_m::peripheral::SystClkSource;
+use cortex_m::peripheral::syst::SystClkSource;
 use rtfm::{app, Threshold};
+use stm32f103xx::GPIOC;
 
 app! {
     device: stm32f103xx,
@@ -35,9 +36,8 @@ app! {
 
             // These are the resources this task has access to.
             //
-            // A resource can be a peripheral like `GPIOC` or a static variable
-            // like `ON`
-            resources: [GPIOC, ON],
+            // The resources listed here must also appear in `app.resources`
+            resources: [ON],
         },
     }
 }
@@ -47,19 +47,20 @@ fn init(p: init::Peripherals, r: init::Resources) {
     r.ON;
 
     // power on GPIOC
-    p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
+    p.device.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
 
     // configure PC13 as output
-    p.GPIOC.bsrr.write(|w| w.bs13().set());
-    p.GPIOC
+    p.device.GPIOC.bsrr.write(|w| w.bs13().set());
+    p.device
+        .GPIOC
         .crh
         .modify(|_, w| w.mode13().output().cnf13().push());
 
     // configure the system timer to generate one interrupt every second
-    p.SYST.set_clock_source(SystClkSource::Core);
-    p.SYST.set_reload(8_000_000); // 1s
-    p.SYST.enable_interrupt();
-    p.SYST.enable_counter();
+    p.core.SYST.set_clock_source(SystClkSource::Core);
+    p.core.SYST.set_reload(8_000_000); // 1s
+    p.core.SYST.enable_interrupt();
+    p.core.SYST.enable_counter();
 }
 
 fn idle() -> ! {
@@ -74,15 +75,22 @@ fn idle() -> ! {
 //
 // `r` is the set of resources this task has access to. `SYS_TICK::Resources`
 // has one field per resource declared in `app!`.
+#[allow(unsafe_code)]
 fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
     // toggle state
     **r.ON = !**r.ON;
 
     if **r.ON {
         // set the pin PC13 high
-        r.GPIOC.bsrr.write(|w| w.bs13().set());
+        // NOTE(unsafe) atomic write to a stateless register
+        unsafe {
+            (*GPIOC::ptr()).bsrr.write(|w| w.bs13().set());
+        }
     } else {
         // set the pin PC13 low
-        r.GPIOC.bsrr.write(|w| w.br13().reset());
+        // NOTE(unsafe) atomic write to a stateless register
+        unsafe {
+            (*GPIOC::ptr()).bsrr.write(|w| w.br13().reset());
+        }
     }
 }
diff --git a/examples/zero-tasks.rs b/examples/zero-tasks.rs
index 9176103d434d8159bcc6bffaa10740e6cfbcfd59..58e6afc76c65cc1c6f3a0f81cb42b4a19805cbc4 100644
--- a/examples/zero-tasks.rs
+++ b/examples/zero-tasks.rs
@@ -25,8 +25,9 @@ app! {
 // this function.
 fn init(p: init::Peripherals) {
     // This function has access to all the peripherals of the device
-    p.GPIOA;
-    p.RCC;
+    p.core.SYST;
+    p.device.GPIOA;
+    p.device.RCC;
     // ..
 }
 
diff --git a/macros/src/check.rs b/macros/src/check.rs
index 3cd112acfd1758d2847365cd91434dd005151d41..63cac1fa5eda47cf63199be704db8d8df9b5b800 100644
--- a/macros/src/check.rs
+++ b/macros/src/check.rs
@@ -63,16 +63,15 @@ pub fn app(app: check::App) -> Result<App> {
         tasks: app.tasks
             .into_iter()
             .map(|(k, v)| {
-                let v = ::check::task(k.as_ref(), v)
-                    .chain_err(|| format!("checking task `{}`", k))?;
+                let v =
+                    ::check::task(k.as_ref(), v).chain_err(|| format!("checking task `{}`", k))?;
 
                 Ok((k, v))
             })
             .collect::<Result<_>>()?,
     };
 
-    ::check::resources(&app)
-        .chain_err(|| "checking `resources`")?;
+    ::check::resources(&app).chain_err(|| "checking `resources`")?;
 
     Ok(app)
 }
@@ -93,6 +92,17 @@ fn resources(app: &App) -> Result<()> {
         bail!("resource `{}` is unused", resource);
     }
 
+    for (name, task) in &app.tasks {
+        for resource in &task.resources {
+            ensure!(
+                app.resources.contains_key(&resource),
+                "task {} contains an undeclared resource with name {}",
+                name,
+                resource
+            );
+        }
+    }
+
     Ok(())
 }
 
diff --git a/macros/src/trans.rs b/macros/src/trans.rs
index 96ff770b64f2982de7ae088fbf5ad0f646a68d21..bc69f24e95ae7101e9280a7926918fcfa9db9af2 100644
--- a/macros/src/trans.rs
+++ b/macros/src/trans.rs
@@ -27,12 +27,7 @@ pub fn app(app: &App, ownerships: &Ownerships) -> Tokens {
     quote!(#(#root)*)
 }
 
-fn idle(
-    app: &App,
-    ownerships: &Ownerships,
-    main: &mut Vec<Tokens>,
-    root: &mut Vec<Tokens>,
-) {
+fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
     let krate = krate();
 
     let mut mod_items = vec![];
@@ -45,8 +40,6 @@ fn idle(
     }
 
     if !app.idle.resources.is_empty() {
-        let device = &app.device;
-
         let mut needs_reexport = false;
         for name in &app.idle.resources {
             if ownerships[name].is_owned() {
@@ -66,32 +59,26 @@ fn idle(
         let mut rfields = vec![];
         for name in &app.idle.resources {
             if ownerships[name].is_owned() {
-                if let Some(resource) = app.resources.get(name) {
-                    let ty = &resource.ty;
+                let resource = app.resources.get(name).expect(&format!(
+                    "BUG: resource {} assigned to `idle` has no definition",
+                    name
+                ));
+                let ty = &resource.ty;
 
-                    rfields.push(quote! {
-                        pub #name: &'static mut #ty,
-                    });
+                rfields.push(quote! {
+                    pub #name: &'static mut #ty,
+                });
 
-                    let _name = Ident::new(format!("_{}", name.as_ref()));
-                    rexprs.push(if resource.expr.is_some() {
-                        quote! {
-                            #name: &mut #super_::#_name,
-                        }
-                    } else {
-                        quote! {
-                            #name: #super_::#_name.as_mut(),
-                        }
-                    });
+                let _name = Ident::new(format!("_{}", name.as_ref()));
+                rexprs.push(if resource.expr.is_some() {
+                    quote! {
+                        #name: &mut #super_::#_name,
+                    }
                 } else {
-                    rfields.push(quote! {
-                        pub #name: &'static mut ::#device::#name,
-                    });
-
-                    rexprs.push(quote! {
-                        #name: &mut *::#device::#name.get(),
-                    });
-                }
+                    quote! {
+                        #name: #super_::#_name.as_mut(),
+                    }
+                });
             } else {
                 rfields.push(quote! {
                     pub #name: #super_::_resource::#name,
@@ -161,12 +148,20 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
     let device = &app.device;
     let krate = krate();
 
-    let mut tys = vec![quote!(#device::Peripherals)];
-    let mut exprs = vec![quote!(#device::Peripherals::all())];
+    let mut tys = vec![quote!(init::Peripherals)];
+    let mut exprs = vec![
+        quote!{
+            init::Peripherals {
+                core: ::#device::CorePeripherals::steal(),
+                device: ::#device::Peripherals::steal(),
+            }
+        },
+    ];
     let mut ret = None;
     let mut mod_items = vec![];
 
-    let (init_resources, late_resources): (Vec<_>, Vec<_>) = app.resources.iter()
+    let (init_resources, late_resources): (Vec<_>, Vec<_>) = app.resources
+        .iter()
         .partition(|&(_, res)| res.expr.is_some());
 
     if !init_resources.is_empty() {
@@ -255,7 +250,10 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
     root.push(quote! {
         #[allow(unsafe_code)]
         mod init {
-            pub use ::#device::Peripherals;
+            pub struct Peripherals {
+                pub core: ::#device::CorePeripherals,
+                pub device: ::#device::Peripherals,
+            }
 
             #(#mod_items)*
         }
@@ -268,7 +266,7 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
             Kind::Exception(ref e) => {
                 if exceptions.is_empty() {
                     exceptions.push(quote! {
-                        let scb = &*#device::SCB.get();
+                        let scb = &*#device::SCB::ptr();
                     });
                 }
 
@@ -284,7 +282,7 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
                 // Interrupt. These can be enabled / disabled through the NVIC
                 if interrupts.is_empty() {
                     interrupts.push(quote! {
-                        let nvic = &*#device::NVIC.get();
+                        let nvic = &*#device::NVIC::ptr();
                     });
                 }
 
@@ -355,154 +353,81 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
                 // For owned resources we don't need claim() or borrow()
             }
             Ownership::Shared { ceiling } => {
-                if let Some(resource) = app.resources.get(name) {
-                    let ty = &resource.ty;
-                    let res_rvalue = if resource.expr.is_some() {
-                        quote!(#_name)
-                    } else {
-                        quote!(#_name.some)
-                    };
-
-                    impl_items.push(quote! {
-                        type Data = #ty;
-
-                        fn borrow<'cs>(
-                            &'cs self,
-                            t: &'cs #krate::Threshold,
-                        ) -> &'cs #krate::Static<#ty> {
-                            assert!(t.value() >= #ceiling);
-
-                            unsafe { #krate::Static::ref_(&#res_rvalue) }
-                        }
-
-                        fn borrow_mut<'cs>(
-                            &'cs mut self,
-                            t: &'cs #krate::Threshold,
-                        ) -> &'cs mut #krate::Static<#ty> {
-                            assert!(t.value() >= #ceiling);
-
-                            unsafe {
-                                #krate::Static::ref_mut(&mut #res_rvalue)
-                            }
-                        }
-
-                        fn claim<R, F>(
-                            &self,
-                            t: &mut #krate::Threshold,
-                            f: F,
-                        ) -> R
-                        where
-                            F: FnOnce(
-                                &#krate::Static<#ty>,
-                                &mut #krate::Threshold) -> R
-                        {
-                            unsafe {
-                                #krate::claim(
-                                    #krate::Static::ref_(&#res_rvalue),
-                                    #ceiling,
-                                    #device::NVIC_PRIO_BITS,
-                                    t,
-                                    f,
-                                )
-                            }
-                        }
-
-                        fn claim_mut<R, F>(
-                            &mut self,
-                            t: &mut #krate::Threshold,
-                            f: F,
-                        ) -> R
-                        where
-                            F: FnOnce(
-                                &mut #krate::Static<#ty>,
-                                &mut #krate::Threshold) -> R
-                        {
-                            unsafe {
-                                #krate::claim(
-                                    #krate::Static::ref_mut(&mut #res_rvalue),
-                                    #ceiling,
-                                    #device::NVIC_PRIO_BITS,
-                                    t,
-                                    f,
-                                )
-                            }
-                        }
-                    });
+                let resource = app.resources
+                    .get(name)
+                    .expect(&format!("BUG: resource {} has no definition", name));
+                let ty = &resource.ty;
+                let res_rvalue = if resource.expr.is_some() {
+                    quote!(#_name)
                 } else {
-                    impl_items.push(quote! {
-                        type Data = #device::#name;
+                    quote!(#_name.some)
+                };
 
-                        fn borrow<'cs>(
-                            &'cs self,
-                            t: &'cs #krate::Threshold,
-                        ) -> &'cs #krate::Static<#device::#name> {
-                            assert!(t.value() >= #ceiling);
+                impl_items.push(quote! {
+                    type Data = #ty;
 
-                            unsafe {
-                                #krate::Static::ref_(&*#device::#name.get())
-                            }
-                        }
+                    fn borrow<'cs>(
+                        &'cs self,
+                        t: &'cs #krate::Threshold,
+                    ) -> &'cs #krate::Static<#ty> {
+                        assert!(t.value() >= #ceiling);
 
-                        fn borrow_mut<'cs>(
-                            &'cs mut self,
-                            t: &'cs #krate::Threshold,
-                        ) -> &'cs mut #krate::Static<#device::#name> {
-                            assert!(t.value() >= #ceiling);
+                        unsafe { #krate::Static::ref_(&#res_rvalue) }
+                    }
 
-                            unsafe {
-                                #krate::Static::ref_mut(
-                                    &mut *#device::#name.get(),
-                                )
-                            }
+                    fn borrow_mut<'cs>(
+                        &'cs mut self,
+                        t: &'cs #krate::Threshold,
+                    ) -> &'cs mut #krate::Static<#ty> {
+                        assert!(t.value() >= #ceiling);
+
+                        unsafe {
+                            #krate::Static::ref_mut(&mut #res_rvalue)
                         }
+                    }
 
-                        fn claim<R, F>(
-                            &self,
-                            t: &mut #krate::Threshold,
-                            f: F,
-                        ) -> R
-                        where
-                            F: FnOnce(
-                                &#krate::Static<#device::#name>,
-                                &mut #krate::Threshold) -> R
-                        {
-                            unsafe {
-                                #krate::claim(
-                                    #krate::Static::ref_(
-                                        &*#device::#name.get(),
-                                    ),
-                                    #ceiling,
-                                    #device::NVIC_PRIO_BITS,
-                                    t,
-                                    f,
-                                )
-                            }
+                    fn claim<R, F>(
+                        &self,
+                        t: &mut #krate::Threshold,
+                        f: F,
+                    ) -> R
+                    where
+                        F: FnOnce(
+                            &#krate::Static<#ty>,
+                            &mut #krate::Threshold) -> R
+                    {
+                        unsafe {
+                            #krate::claim(
+                                #krate::Static::ref_(&#res_rvalue),
+                                #ceiling,
+                                #device::NVIC_PRIO_BITS,
+                                t,
+                                f,
+                            )
                         }
+                    }
 
-                        fn claim_mut<R, F>(
-                            &mut self,
-                            t: &mut #krate::Threshold,
-                            f: F,
-                        ) -> R
-                        where
-                            F: FnOnce(
-                                &mut #krate::Static<#device::#name>,
-                                &mut #krate::Threshold) -> R
-                        {
-                            unsafe {
-                                #krate::claim(
-                                    #krate::Static::ref_mut(
-                                        &mut *#device::#name.get(),
-                                    ),
-                                    #ceiling,
-                                    #device::NVIC_PRIO_BITS,
-                                    t,
-                                    f,
-                                )
-                            }
+                    fn claim_mut<R, F>(
+                        &mut self,
+                        t: &mut #krate::Threshold,
+                        f: F,
+                    ) -> R
+                    where
+                        F: FnOnce(
+                            &mut #krate::Static<#ty>,
+                            &mut #krate::Threshold) -> R
+                    {
+                        unsafe {
+                            #krate::claim(
+                                #krate::Static::ref_mut(&mut #res_rvalue),
+                                #ceiling,
+                                #device::NVIC_PRIO_BITS,
+                                t,
+                                f,
+                            )
                         }
-                    });
-                }
+                    }
+                });
 
                 impls.push(quote! {
                     #[allow(unsafe_code)]
@@ -560,9 +485,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
                 let _name = Ident::new(format!("_{}", name.as_ref()));
 
                 match ownerships[name] {
-                    Ownership::Shared { ceiling }
-                        if ceiling > task.priority =>
-                    {
+                    Ownership::Shared { ceiling } if ceiling > task.priority => {
                         needs_threshold = true;
 
                         fields.push(quote! {
@@ -577,35 +500,26 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
                     }
                     _ => {
                         lifetime = Some(quote!('a));
-                        if let Some(resource) = app.resources.get(name) {
-                            needs_reexport = true;
-                            let ty = &resource.ty;
-
-                            fields.push(quote! {
-                                pub #name: &'a mut ::#krate::Static<#ty>,
-                            });
-
-                            exprs.push(if resource.expr.is_some() {
-                                quote! {
-                                    #name: ::#krate::Static::ref_mut(&mut ::#_name),
-                                }
-                            } else {
-                                quote! {
-                                    #name: ::#krate::Static::ref_mut(::#_name.as_mut()),
-                                }
-                            });
+                        let resource = app.resources
+                            .get(name)
+                            .expect(&format!("BUG: resource {} has no definition", name));
+
+                        needs_reexport = true;
+                        let ty = &resource.ty;
+
+                        fields.push(quote! {
+                            pub #name: &'a mut ::#krate::Static<#ty>,
+                        });
+
+                        exprs.push(if resource.expr.is_some() {
+                            quote! {
+                                #name: ::#krate::Static::ref_mut(&mut ::#_name),
+                            }
                         } else {
-                            fields.push(quote! {
-                                pub #name:
-                                &'a mut ::#krate::Static<::#device::#name>,
-                            });
-
-                            exprs.push(quote! {
-                                #name: ::#krate::Static::ref_mut(
-                                    &mut *::#device::#name.get(),
-                                ),
-                            });
-                        }
+                            quote! {
+                                #name: ::#krate::Static::ref_mut(::#_name.as_mut()),
+                            }
+                        });
                     }
                 }
             }
@@ -666,8 +580,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
 
         let path = &task.path;
         let _name = Ident::new(format!("_{}", name));
-        let export_name =
-            Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked);
+        let export_name = Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked);
         root.push(quote! {
             #[allow(non_snake_case)]
             #[allow(unsafe_code)]
diff --git a/src/lib.rs b/src/lib.rs
index 4ab8ec58d927accfcea548553ac223c673b50359..f5481bc401b83b1e406ee66bd04656ca13886d11 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -160,6 +160,6 @@ where
     I: Nr,
 {
     // NOTE(safe) atomic write
-    let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
+    let nvic = unsafe { &*cortex_m::peripheral::NVIC::ptr() };
     nvic.set_pending(interrupt);
 }