diff --git a/Cargo.toml b/Cargo.toml
index f345689e92d85857b4decc1b2e0004296dcac146..448282d2ba9340bdbec1bb30684128e722222ed2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,9 +14,10 @@ version = "0.2.1"
 
 [dependencies]
 cortex-m = "0.3.1"
-cortex-m-rtfm-macros = "=0.2.0"
-rtfm-core = "0.1.0"
-static-ref = "0.2.1"
+# TODO should this have been a `path` dep all along?
+cortex-m-rtfm-macros = { path = "macros" }
+# TODO revert before merging
+rtfm-core = { git = "https://github.com/jonas-schievink/rtfm-core.git", branch = "init-resources" }
 
 [target.'cfg(target_arch = "x86_64")'.dev-dependencies]
 compiletest_rs = "0.2.8"
@@ -30,4 +31,4 @@ features = ["rt"]
 version = "0.7.1"
 
 [profile.release]
-lto = true
\ No newline at end of file
+lto = true
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index eda10c57ddf223afd6e454316a10613fe8a6613f..b825de2ebc8b845b56d2ea1831494adec589168f 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -12,7 +12,8 @@ version = "0.2.0"
 [dependencies]
 error-chain = "0.10.0"
 quote = "0.3.15"
-rtfm-syntax = "0.1.0"
+# TODO undo change
+rtfm-syntax = { git = "https://github.com/jonas-schievink/rtfm-syntax.git", branch = "init-resources" }
 syn = "0.11.11"
 
 [lib]
diff --git a/macros/src/trans.rs b/macros/src/trans.rs
index c65aaa522e1d0c52a0ff7879589746d4c35ecf90..ef23aa5fd7e3c6f2787c14f0994f2e568ff064d5 100644
--- a/macros/src/trans.rs
+++ b/macros/src/trans.rs
@@ -157,14 +157,23 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
 
     let mut tys = vec![quote!(#device::Peripherals)];
     let mut exprs = vec![quote!(#device::Peripherals::all())];
+    let mut ret = None;
     let mut mod_items = vec![];
 
-    if !app.resources.is_empty() {
+    // Write resources usable by `init`, if any
+
+
+    // Are there any resources that have an initializer? Those can be used by `init`.
+    let has_initialized_resources = app.resources.iter()
+        .find(|&(_, res)| res.expr.is_some()).is_some();
+
+    if has_initialized_resources {
         let mut fields = vec![];
         let mut lifetime = None;
         let mut rexprs = vec![];
 
-        for (name, resource) in &app.resources {
+        for (name, resource) in app.resources.iter()
+                .filter(|&(_, res)| res.expr.is_some()) {
             let _name = Ident::new(format!("_{}", name.as_ref()));
             lifetime = Some(quote!('a));
 
@@ -204,6 +213,46 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
         exprs.push(quote!(init::Resources::new()));
     }
 
+    let mut late_resources = vec![];
+    let has_late_resources = app.resources.iter()
+        .find(|&(_, res)| res.expr.is_none()).is_some();
+
+    if has_late_resources {
+        // `init` must initialize and return resources
+
+        let mut fields = vec![];
+
+        for (name, resource) in app.resources.iter()
+            .filter(|&(_, res)| res.expr.is_none()) {
+            let _name = Ident::new(format!("_{}", name.as_ref()));
+
+            let ty = &resource.ty;
+
+            fields.push(quote! {
+                pub #name: #ty,
+            });
+
+            late_resources.push(quote! {
+                #_name = #krate::LateResource { init: _late_resources.#name };
+            });
+        }
+
+        root.push(quote! {
+            #[allow(non_camel_case_types)]
+            #[allow(non_snake_case)]
+            pub struct _initLateResourceValues {
+                #(#fields)*
+            }
+        });
+
+        mod_items.push(quote! {
+            pub use ::_initLateResourceValues as LateResourceValues;
+        });
+
+        // `init` must return the initialized resources
+        ret = Some(quote!( -> ::init::LateResourceValues));
+    }
+
     root.push(quote! {
         #[allow(unsafe_code)]
         mod init {
@@ -263,10 +312,11 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
     let init = &app.init.path;
     main.push(quote! {
         // type check
-        let init: fn(#(#tys,)*) = #init;
+        let init: fn(#(#tys,)*) #ret = #init;
 
         #krate::atomic(unsafe { &mut #krate::Threshold::new(0) }, |_t| unsafe {
-            init(#(#exprs,)*);
+            let _late_resources = init(#(#exprs,)*);
+            #(#late_resources)*
 
             #(#exceptions)*
             #(#interrupts)*
@@ -281,33 +331,34 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
     let mut items = vec![];
     let mut impls = vec![];
     for (name, ownership) in ownerships {
+        let _name = Ident::new(format!("_{}", name.as_ref()));
+
+        if let Some(resource) = app.resources.get(name) {
+            // Declare the static that holds the resource
+            let expr = &resource.expr;
+            let ty = &resource.ty;
+
+            root.push(match *expr {
+                Some(ref expr) => quote! {
+                    static mut #_name: #ty = #expr;
+                },
+                None => quote! {
+                    // Resource initialized in `init`
+                    static mut #_name: #krate::LateResource<#ty> = #krate::LateResource { uninit: () };
+                },
+            });
+        }
+
         let mut impl_items = vec![];
 
-        let _name = Ident::new(format!("_{}", name.as_ref()));
         match *ownership {
             Ownership::Owned { .. } => {
-                if let Some(resource) = app.resources.get(name) {
-                    // For owned resources we don't need claim() or borrow()
-                    let expr = &resource.expr;
-                    let ty = &resource.ty;
-
-                    root.push(quote! {
-                        static mut #_name: #ty = #expr;
-                    });
-                } else {
-                    // Peripheral
-                    continue;
-                }
+                // For owned resources we don't need claim() or borrow()
             }
             Ownership::Shared { ceiling } => {
                 if let Some(resource) = app.resources.get(name) {
-                    let expr = &resource.expr;
                     let ty = &resource.ty;
 
-                    root.push(quote! {
-                        static mut #_name: #ty = #expr;
-                    });
-
                     impl_items.push(quote! {
                         type Data = #ty;
 
@@ -530,8 +581,14 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
                                 pub #name: &'a mut ::#krate::Static<#ty>,
                             });
 
-                            exprs.push(quote! {
-                                #name: ::#krate::Static::ref_mut(&mut ::#_name),
+                            exprs.push(if resource.expr.is_some() {
+                                quote! {
+                                    #name: ::#krate::Static::ref_mut(&mut ::#_name),
+                                }
+                            } else {
+                                quote! {
+                                    #name: ::#krate::Static::ref_mut(&mut ::#_name.init),
+                                }
                             });
                         } else {
                             fields.push(quote! {
diff --git a/src/lib.rs b/src/lib.rs
index 3fde2ddc10a2e8d9c17b64cd322dbd1604753122..072e635969cad2cfc9d59ba3676dcfe373438370 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -80,11 +80,10 @@
 extern crate cortex_m;
 extern crate cortex_m_rtfm_macros;
 extern crate rtfm_core;
-extern crate static_ref;
 
 use core::u8;
 
-pub use rtfm_core::{Resource, Static, Threshold};
+pub use rtfm_core::{Resource, LateResource, Static, Threshold};
 pub use cortex_m::asm::{bkpt, wfi};
 pub use cortex_m_rtfm_macros::app;
 use cortex_m::interrupt::{self, Nr};