diff --git a/app/.cargo/config b/app/.cargo/config
new file mode 100644
index 0000000000000000000000000000000000000000..a7fff23b1f1a64f56520c03fe462d30a9c963c25
--- /dev/null
+++ b/app/.cargo/config
@@ -0,0 +1,33 @@
+[target.thumbv7m-none-eabi]
+# uncomment this to make `cargo run` execute programs on QEMU
+# runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel"
+
+[target.'cfg(all(target_arch = "arm", target_os = "none"))']
+# uncomment ONE of these three option to make `cargo run` start a GDB session
+# which option to pick depends on your system
+# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
+# runner = "gdb-multiarch -q -x openocd.gdb"
+# runner = "gdb -q -x openocd.gdb"
+
+rustflags = [
+  # LLD (shipped with the Rust toolchain) is used as the default linker
+  "-C", "link-arg=-Tlink.x",
+
+  # if you run into problems with LLD switch to the GNU linker by commenting out
+  # this line
+  # "-C", "linker=arm-none-eabi-ld",
+
+  # if you need to link to pre-compiled C libraries provided by a C toolchain
+  # use GCC as the linker by commenting out both lines above and then
+  # uncommenting the three lines below
+  # "-C", "linker=arm-none-eabi-gcc",
+  # "-C", "link-arg=-Wl,-Tlink.x",
+  # "-C", "link-arg=-nostartfiles",
+]
+
+[build]
+# Pick ONE of these compilation targets
+# target = "thumbv6m-none-eabi"    # Cortex-M0 and Cortex-M0+
+# target = "thumbv7m-none-eabi"    # Cortex-M3
+# target = "thumbv7em-none-eabi"   # Cortex-M4 and Cortex-M7 (no FPU)
+target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..59a4524385b07ca938c09f854be9919754938cfd
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1,5 @@
+**/*.rs.bk
+.#*
+.gdb_history
+Cargo.lock
+target/
diff --git a/app/.vscode/.cortex-debug.peripherals.state.json b/app/.vscode/.cortex-debug.peripherals.state.json
new file mode 100644
index 0000000000000000000000000000000000000000..0637a088a01e8ddab3bf3fa98dbe804cbde1a0dc
--- /dev/null
+++ b/app/.vscode/.cortex-debug.peripherals.state.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/app/.vscode/.cortex-debug.registers.state.json b/app/.vscode/.cortex-debug.registers.state.json
new file mode 100644
index 0000000000000000000000000000000000000000..0637a088a01e8ddab3bf3fa98dbe804cbde1a0dc
--- /dev/null
+++ b/app/.vscode/.cortex-debug.registers.state.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/app/.vscode/launch.json b/app/.vscode/launch.json
new file mode 100644
index 0000000000000000000000000000000000000000..1e718798312c78749d41c1445fd335d3bf2f8e4e
--- /dev/null
+++ b/app/.vscode/launch.json
@@ -0,0 +1,68 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "cortex-debug",
+            "request": "launch",
+            "servertype": "openocd",
+            "name": "app",
+            "executable": "./target/thumbv7em-none-eabihf/release/app",
+            "configFiles": [
+                "interface/stlink-v2-1.cfg",
+                "target/stm32f4x.cfg"
+            ],
+            "postLaunchCommands": [
+                "monitor arm semihosting enable",
+                //"monitor tpiu config internal /tmp/itm.log uart off 64000000",
+                //"monitor itm port 0 on",
+            ],
+            "swoConfig": {
+                "enabled": true,
+                "cpuFrequency": 16000000,
+                "swoFrequency": 2000000, // you may try 1000000 if not working
+                "source": "probe",
+                "decoders": [
+                    {
+                        "type": "console",
+                        "label": "Name",
+                        "port": 0
+                    }
+                ]
+            },
+            "cwd": "${workspaceRoot}"
+        },
+        {
+            "type": "cortex-debug",
+            "request": "launch",
+            "servertype": "openocd",
+            "name": "hello - semihosting",
+            "executable": "./target/thumbv7em-none-eabihf/release/examples/hello",
+            "configFiles": [
+                "interface/stlink.cfg",
+                "target/stm32f4x.cfg"
+            ],
+            "postLaunchCommands": [
+                "monitor arm semihosting enable",
+                //"monitor tpiu config internal /tmp/itm.log uart off 64000000",
+                //"monitor itm port 0 on",
+            ],
+            "swoConfig": {
+                "enabled": true,
+                "cpuFrequency": 16000000,
+                "swoFrequency": 2000000, // you may try 1000000 if not working
+                "source": "probe",
+                "decoders": [
+                    {
+                        "type": "console",
+                        "label": "Name",
+                        "port": 0
+                    }
+                ]
+            },
+            "cwd": "${workspaceRoot}"
+        },
+    ]
+}
\ No newline at end of file
diff --git a/app/.vscode/tasks.json b/app/.vscode/tasks.json
new file mode 100644
index 0000000000000000000000000000000000000000..ba1ffb80f0f0bb6227c89e31c31337d18512dcbb
--- /dev/null
+++ b/app/.vscode/tasks.json
@@ -0,0 +1,115 @@
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "type": "shell",
+            "label": "cargo clean",
+            "command": "cargo clean",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --release",
+            "command": "cargo build --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example hello --release",
+            "command": "cargo build --example hello --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example itm --release",
+            "command": "cargo build --example itm --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example panic-itm --release",
+            "command": "cargo build --example panic-itm --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example panic-halt --release",
+            "command": "cargo build --example panic-halt --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example panic-semihosting --release",
+            "command": "cargo build --example panic-semihosting --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --example blinky --release",
+            "command": "cargo build --example blinky --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        },
+        {
+            "type": "shell",
+            "label": "cargo build --examples --release",
+            "command": "cargo build --examples --release",
+            "problemMatcher": [
+                "$rustc"
+            ],
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/app/Cargo.toml b/app/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..24cf25908d93e70981128131d39ed8d9b95cd885
--- /dev/null
+++ b/app/Cargo.toml
@@ -0,0 +1,39 @@
+[package]
+authors = ["Per Lindgren <per.lindgren@ltu.se>"]
+edition = "2018"
+readme = "README.md"
+name = "app"
+version = "0.1.0"
+
+[dependencies.cortex-m]
+version = "0.5.8"
+features = ["inline-asm"]
+
+[dependencies]
+cortex-m-rt = "0.6.5"
+cortex-m-semihosting = "0.3.2"
+
+# panic handlers, you may comment out those not used
+panic-halt = "0.2.0"
+panic-itm = "0.4.0"
+panic-semihosting = "0.5.1"
+
+# Uncomment for the allocator example.
+alloc-cortex-m = "0.3.5"
+
+# Uncomment for the device example.
+[dependencies.stm32f413]
+git = "https://gitlab.henriktjader.com/pln/stm32f413.git" 
+features = ["rt"]
+version = "0.3.0"
+
+# this lets you use `cargo fix`!
+[[bin]]
+name = "app"
+test = false
+bench = false
+
+[profile.release]
+codegen-units = 1 # better optimizations
+debug = true # symbols are nice and they don't increase the size on Flash
+lto = true # better optimizations
diff --git a/app/README.md b/app/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..56dc79674ae4e9b2371a752526b0afa6cc5fb27a
--- /dev/null
+++ b/app/README.md
@@ -0,0 +1,129 @@
+# `cortex-m-quickstart`
+
+> A template for building applications for ARM Cortex-M microcontrollers
+
+This project is developed and maintained by the [Cortex-M team][team].
+
+## Dependencies
+
+To build embedded programs using this template you'll need:
+
+- Rust 1.31, 1.30-beta, nightly-2018-09-13 or a newer toolchain. e.g. `rustup
+  default beta`
+
+- The `cargo generate` subcommand. [Installation
+  instructions](https://github.com/ashleygwilliams/cargo-generate#installation).
+
+- `rust-std` components (pre-compiled `core` crate) for the ARM Cortex-M
+  targets. Run:
+
+``` console
+$ rustup target add thumbv6m-none-eabi thumbv7m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf
+```
+
+## Using this template
+
+**NOTE**: This is the very short version that only covers building programs. For
+the long version, which additionally covers flashing, running and debugging
+programs, check [the embedded Rust book][book].
+
+[book]: https://rust-embedded.github.io/book
+
+0. Before we begin you need to identify some characteristics of the target
+  device as these will be used to configure the project:
+
+- The ARM core. e.g. Cortex-M3.
+
+- Does the ARM core include an FPU? Cortex-M4**F** and Cortex-M7**F** cores do.
+
+- How much Flash memory and RAM does the target device has? e.g. 256 KiB of
+  Flash and 32 KiB of RAM.
+
+- Where are Flash memory and RAM mapped in the address space? e.g. RAM is
+  commonly located at address `0x2000_0000`.
+
+You can find this information in the data sheet or the reference manual of your
+device.
+
+In this example we'll be using the STM32F3DISCOVERY. This board contains an
+STM32F303VCT6 microcontroller. This microcontroller has:
+
+- A Cortex-M4F core that includes a single precision FPU
+
+- 256 KiB of Flash located at address 0x0800_0000.
+
+- 40 KiB of RAM located at address 0x2000_0000. (There's another RAM region but
+  for simplicity we'll ignore it).
+
+1. Instantiate the template.
+
+``` console
+$ cargo generate --git https://github.com/rust-embedded/cortex-m-quickstart
+ Project Name: app
+ Creating project called `app`...
+ Done! New project created /tmp/app
+
+$ cd app
+```
+
+2. Set a default compilation target. There are four options as mentioned at the
+   bottom of `.cargo/config`. For the STM32F303VCT6, which has a Cortex-M4F
+   core, we'll pick the `thumbv7em-none-eabihf` target.
+
+``` console
+$ tail -n6 .cargo/config
+```
+
+``` toml
+[build]
+# Pick ONE of these compilation targets
+# target = "thumbv6m-none-eabi"    # Cortex-M0 and Cortex-M0+
+# target = "thumbv7m-none-eabi"    # Cortex-M3
+# target = "thumbv7em-none-eabi"   # Cortex-M4 and Cortex-M7 (no FPU)
+target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
+```
+
+3. Enter the memory region information into the `memory.x` file.
+
+``` console
+$ cat memory.x
+/* Linker script for the STM32F303VCT6 */
+MEMORY
+{
+  /* NOTE 1 K = 1 KiBi = 1024 bytes */
+  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
+  RAM : ORIGIN = 0x20000000, LENGTH = 40K
+}
+```
+
+4. Build the template application or one of the examples.
+
+``` console
+$ cargo build
+```
+
+# License
+
+This template is licensed under either of
+
+- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
+  http://www.apache.org/licenses/LICENSE-2.0)
+
+- MIT license ([LICENSE-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.
+
+## Code of Conduct
+
+Contribution to this crate is organized under the terms of the [Rust Code of
+Conduct][CoC], the maintainer of this crate, the [Cortex-M team][team], promises
+to intervene to uphold that code of conduct.
+
+[CoC]: CODE_OF_CONDUCT.md
+[team]: https://github.com/rust-embedded/wg#the-cortex-m-team
diff --git a/app/build.rs b/app/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..98f603edca220793729c92ff608e25d6bf0e8e7e
--- /dev/null
+++ b/app/build.rs
@@ -0,0 +1,18 @@
+use std::env;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+
+fn main() {
+    // Put the linker script somewhere the linker can find it
+    let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+    File::create(out.join("memory.x"))
+        .unwrap()
+        .write_all(include_bytes!("memory.x"))
+        .unwrap();
+    println!("cargo:rustc-link-search={}", out.display());
+
+    // Only re-run the build script when memory.x is changed,
+    // instead of when any part of the source code changes.
+    println!("cargo:rerun-if-changed=memory.x");
+}
diff --git a/app/examples/allocator.rs b/app/examples/allocator.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e45458cd8a850b52bf425a008aa8ba8a5f3076a8
--- /dev/null
+++ b/app/examples/allocator.rs
@@ -0,0 +1,58 @@
+//! How to use the heap and a dynamic memory allocator
+//!
+//! This example depends on the alloc-cortex-m crate so you'll have to add it to your Cargo.toml:
+//!
+//! ``` text
+//! # or edit the Cargo.toml file manually
+//! $ cargo add alloc-cortex-m
+//! ```
+//!
+//! ---
+
+#![feature(alloc)]
+#![feature(alloc_error_handler)]
+#![no_main]
+#![no_std]
+
+extern crate alloc;
+extern crate panic_halt;
+extern crate stm32f413;
+
+use self::alloc::vec;
+use core::alloc::Layout;
+
+use alloc_cortex_m::CortexMHeap;
+use cortex_m::asm;
+use cortex_m_rt::entry;
+use cortex_m_semihosting::hprintln;
+
+// this is the allocator the application will use
+#[global_allocator]
+static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
+
+const HEAP_SIZE: usize = 1024; // in bytes
+
+#[entry]
+fn main() -> ! {
+    // Initialize the allocator BEFORE you use it
+    unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) }
+
+    // Growable array allocated on the heap
+    let xs = vec![0, 1, 2];
+
+    hprintln!("{:?}", xs).unwrap();
+
+    // exit QEMU
+    // NOTE do not run this on hardware; it can corrupt OpenOCD state
+    //debug::exit(debug::EXIT_SUCCESS);
+
+    loop {}
+}
+
+// define what happens in an Out Of Memory (OOM) condition
+#[alloc_error_handler]
+fn alloc_error(_layout: Layout) -> ! {
+    asm::bkpt();
+
+    loop {}
+}
diff --git a/app/examples/blinky.rs b/app/examples/blinky.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d0fd1b9397e282f24c43e208d816ccc1ae1b4882
--- /dev/null
+++ b/app/examples/blinky.rs
@@ -0,0 +1,61 @@
+#![no_main]
+#![no_std]
+#![feature(asm)]
+
+extern crate panic_semihosting;
+extern crate stm32f413;
+
+// use cortex_m::asm;
+use cortex_m::{iprintln, peripheral::syst::SystClkSource};
+use cortex_m_rt::{entry, exception};
+// use cortex_m_semihosting::hprint;
+
+#[entry]
+fn main() -> ! {
+    unsafe { asm!("bkpt" :::: "volatile") };
+    let mut p = cortex_m::Peripherals::take().unwrap();
+    let mut syst = p.SYST;
+    let stim = &mut p.ITM.stim[0];
+    iprintln!(stim, "Hello, plepps!");
+
+    let p = stm32f413::Peripherals::take().unwrap();
+    let rcc = p.RCC;
+    let gpioa = p.GPIOA;
+
+    // power on GPIOA, RM0368 6.3.11
+    rcc.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
+
+    // configure PA5 as output, RM0368 8.4.1
+    unsafe {
+        gpioa.moder.modify(|_, w| w.moder5().bits(1));
+    }
+
+    // configures the system timer to trigger a SysTick exception every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(16_000_000); // period = 1s
+    syst.enable_counter();
+    syst.enable_interrupt();
+
+    loop {}
+}
+
+#[exception]
+fn SysTick() {
+    static mut TOGGLE: bool = false;
+
+    let gpioa = unsafe { &*stm32f413::GPIOA::ptr() };
+
+    if *TOGGLE {
+        //unsafe { asm!("bkpt" :::: "volatile") };
+        // set PA5 high, RM0368 8.4.7
+        gpioa.bsrr.write(|w| w.bs5().set_bit());
+    } else {
+        //unsafe { asm!("bkpt" :::: "volatile") };
+        // set PA5 low, RM0368 8.4.7
+        gpioa.bsrr.write(|w| w.br5().set_bit());
+    }
+
+    *TOGGLE = !*TOGGLE;
+
+    //hprint!(".").unwrap();
+}
diff --git a/app/examples/crash-semihosting.rs b/app/examples/crash-semihosting.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8969e68fc65e173946b8a462a203f080a833b44f
--- /dev/null
+++ b/app/examples/crash-semihosting.rs
@@ -0,0 +1,138 @@
+//! Debugging a crash (exception)
+//!
+//! Most crash conditions trigger a hard fault exception, whose handler is defined via
+//! `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a
+//! snapshot of the CPU registers at the moment of the exception.
+//!
+//! This program crashes and the `HardFault` handler prints to the console the contents of the
+//! `ExceptionFrame` and then triggers a breakpoint in `rust_begin_unwind`.
+//!
+//! ``` text
+//! Program received signal SIGTRAP, Trace/breakpoint trap.
+//! rust_begin_unwind (info=<optimized out>)
+//!    at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.5.1/src/lib.rs:91
+//! 91              () => asm::bkpt(),
+//! ```
+//!
+//! In the openocd console, you will find the exception frame (printed over semihosting).
+//! ``` text
+//! panicked at 'HardFault at ExceptionFrame {
+//!     r0: 0x2fffffff,
+//!     r1: 0x2fffffff,
+//!     r2: 0x080051d4,
+//!     r3: 0x080051d4,
+//!     r12: 0x20000000,
+//!     lr: 0x08000435,
+//!     pc: 0x08000ab6,
+//!     xpsr: 0x61000000
+//! }', examples/crash.rs:106:5
+//! ```
+//! The program counter (pc) contains the address of the instruction that caused the exception. In GDB one can
+//! disassemble the program around this address to observe the instruction that caused the
+//! exception.
+//!
+//! ``` text
+//! (gdb) backtrace
+//! #0  rust_begin_unwind (info=<optimized out>)
+//!     at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-semihosting-0.5.1/src/lib.rs:91
+//! #1  0x080006dc in cortex_m_semihosting::syscall1 (_nr=5, _arg=134228092)
+//!     at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.2/src/lib.rs:177
+//! #2  cortex_m_semihosting::syscall (nr=5,
+//!     arg=0x800287c <.Lanon.ab45de9cc324a5fa34048c530e72b662.0>)
+//!     at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.2/src/lib.rs:169
+//! #3  cortex_m_semihosting::hio::write_all (fd=0, buffer=...)
+//!     at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.2/src/hio.rs:67
+//! #4  cortex_m_semihosting::hio::HStderr::write_all (self=<optimized out>,
+//!     buffer=...)
+//!     at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.2/src/hio.rs:14
+//! #5  <cortex_m_semihosting::hio::HStderr as core::fmt::Write>::write_str (
+//!     self=<optimized out>, s=...)
+//!     at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-semihosting-0.3.2/src/hio.rs:20
+//! #6  <core::fmt::Write::write_fmt::Adapter<'_, T> as core::fmt::Write>::write_str (
+//!     self=<optimized out>, s=...)
+//!     at /rustc/14997d56a550f4aa99fe737593cd2758227afc56/src/libcore/fmt/mod.rs:214
+//! #7  0x2000ffe0 in ?? ()
+//! Backtrace stopped: previous frame identical to this frame (corrupt stack?)
+//! ```
+//!
+//! ``` text
+//! (gdb) disassemble/m 0x08000ab6
+//! Dump of assembler code for function core::ptr::read_volatile:
+//! 451     pub unsafe fn read_volatile<T>(src: *const T) -> T {
+//!    0x08000aae <+0>:     sub     sp, #16
+//!    0x08000ab0 <+2>:     mov     r1, r0
+//!    0x08000ab2 <+4>:     str     r0, [sp, #8]
+//!
+//! 452         intrinsics::volatile_load(src)
+//!    0x08000ab4 <+6>:     ldr     r0, [sp, #8]
+//! -> 0x08000ab6 <+8>:     ldr     r0, [r0, #0]
+//!    0x08000ab8 <+10>:    str     r0, [sp, #12]
+//!    0x08000aba <+12>:    ldr     r0, [sp, #12]
+//!    0x08000abc <+14>:    str     r1, [sp, #4]
+//!    0x08000abe <+16>:    str     r0, [sp, #0]
+//!    0x08000ac0 <+18>:    b.n     0x8000ac2 <core::ptr::read_volatile+20>
+//!
+//! 453     }
+//!    0x08000ac2 <+20>:    ldr     r0, [sp, #0]
+//!    0x08000ac4 <+22>:    add     sp, #16
+//!    0x08000ac6 <+24>:    bx      lr
+//!
+//! End of assembler dump.
+//! ```
+//!
+//! `ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word
+//! from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame`
+//! we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed.
+//!
+//! ---
+
+#![no_main]
+#![no_std]
+
+//extern crate panic_semihosting;
+extern crate panic_halt;
+extern crate stm32f413;
+
+use core::ptr;
+use cortex_m::asm;
+use cortex_m_rt::{entry, exception};
+//use cortex_m_semihosting::hprintln;
+
+#[entry]
+#[inline(never)]
+fn main() -> ! {
+    asm::bkpt();
+    testf();
+    unsafe {
+        // read an address outside of the RAM region; this causes a HardFault exception
+        ptr::read_volatile(0x2FFF_FFFF as *const u32);
+    }
+    loop {
+        asm::nop();
+    }
+}
+
+#[inline(never)]
+fn testf() {
+    asm::bkpt();
+}
+
+#[exception]
+fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
+    // (gdb) p/x *ef
+    // prints the exception frame,
+    asm::bkpt();
+    unsafe {
+        ptr::read_volatile(ef);
+    }
+
+    panic!();
+
+    // testf();
+    // asm::bkpt();
+    // let _ = hprintln!("{:#?}", ef);
+    // asm::bkpt();
+    // loop {
+    //     asm::bkpt();
+    // }
+}
diff --git a/app/examples/crash.rs b/app/examples/crash.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b3a8ef39e0cc34372561a6038a30f73a0d32cffe
--- /dev/null
+++ b/app/examples/crash.rs
@@ -0,0 +1,88 @@
+//! Debugging a crash (exception)
+//!
+//! Most crash conditions trigger a hard fault exception, whose handler is defined via
+//! `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a
+//! snapshot of the CPU registers at the moment of the exception.
+//!
+//!
+//! ``` text
+//! (gdb) continue
+//! Continuing.
+//! 
+//! Program received signal SIGTRAP, Trace/breakpoint trap.
+//! HardFault (ef=0x2000ffe0) at examples/crash.rs:82
+//! 122         asm::bkpt();
+//! (gdb) p/x *ef
+//! $16 = cortex_m_rt::ExceptionFrame {
+//!     r0: 0x2fffffff, 
+//!     r1: 0xf00000, 
+//!     r2: 0x20000000, 
+//!     r3: 0x0, 
+//!     r12: 0x0, 
+//!     lr: 0x8000477, 
+//!     pc: 0x8000200, 
+//!     xpsr: 0x61000000
+//!     }     
+//! ```
+//! 
+//! The program counter (pc) contains the address of the instruction that caused the exception. In GDB one can
+//! disassemble the program around this address to observe the instruction that caused the
+//! exception.
+//! 
+//! ```
+//! (gdb) disassemble 0x8000200
+//! Dump of assembler code for function main:
+//!    0x080001fc <+0>:     mvn.w   r0, #3489660928 ; 0xd0000000
+//!    0x08000200 <+4>:     ldr     r0, [r0, #0]
+//!    0x08000202 <+6>:     movw    r0, #1228       ; 0x4cc
+//!    0x08000206 <+10>:    movt    r0, #2048       ; 0x800
+//!    0x0800020a <+14>:    bl      0x8000484 <core::panicking::panic>
+//!    0x0800020e <+18>:    udf     #254    ; 0xfe
+//! End of assembler dump.
+//! ```
+//!
+//! `ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word
+//! from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame`
+//! we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed.
+//! 
+//! We can further backtrace the calls leading up to the fault. 
+//! ``` text
+//! (gdb) bt
+//! #0  HardFault (ef=0x2000ffe0) at examples/crash.rs:82
+//! #1  <signal handler called>
+//! #2  core::ptr::read_volatile (src=0x2fffffff) at /rustc/14997d56a550f4aa99fe737593cd2758227afc56/src/libcore/ptr.rs:885
+//! #3  main () at examples/crash.rs:72
+//! ```
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+extern crate stm32f413;
+
+use core::ptr;
+use cortex_m::asm;
+use cortex_m_rt::{entry, exception};
+
+#[entry]
+#[inline(never)]
+fn main() -> ! {
+    unsafe {
+        // read an address outside of the RAM region; this causes a HardFault exception
+        ptr::read_volatile(0x2FFF_FFFF as *const u32);
+    }
+    panic!();
+}
+
+
+#[exception]
+fn HardFault(ef: &cortex_m_rt::ExceptionFrame) -> ! {
+    // (gdb) p/x *ef
+    // prints the exception frame.
+    asm::bkpt();
+    unsafe {
+        ptr::read_volatile(ef);
+    }
+
+    panic!();
+}
diff --git a/app/examples/device.rs b/app/examples/device.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dd296c06d3dcb82eac3860d78500d57a78ed1eb6
--- /dev/null
+++ b/app/examples/device.rs
@@ -0,0 +1,56 @@
+//! Using a device crate
+//!
+//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provide an
+//! API to access the peripherals of a device.
+//!
+//! [`svd2rust`]: https://crates.io/crates/svd2rust
+//!
+//! Device crates also provide an `interrupt!` macro (behind the "rt" feature) to register interrupt
+//! handlers.
+//!
+//! This example depends on the [`stm32f413`] crate so you'll have to add it to your Cargo.toml.
+//!
+//! [`stm32f413`]: https://gitlab.henriktjader.com/pln/stm32f413.git
+//!
+//! ---
+
+#![no_main]
+#![no_std]
+
+#[allow(unused_extern_crates)]
+extern crate panic_halt;
+
+use cortex_m::peripheral::syst::SystClkSource;
+use cortex_m_rt::entry;
+use cortex_m_semihosting::hprint;
+use stm32f413::{interrupt, Interrupt, NVIC};
+
+#[entry]
+fn main() -> ! {
+    let p = cortex_m::Peripherals::take().unwrap();
+
+    let mut syst = p.SYST;
+    let mut nvic = p.NVIC;
+
+    nvic.enable(Interrupt::EXTI0);
+
+    // configure the system timer to wrap around every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(16_000_000); // 1s
+    syst.enable_counter();
+
+    loop {
+        // busy wait until the timer wraps around
+        while !syst.has_wrapped() {}
+
+        // trigger the `EXTI0` interrupt
+        NVIC::pend(Interrupt::EXTI0);
+    }
+}
+
+// try commenting out this line: you'll end in `default_handler` instead of in `exti0`
+#[interrupt]
+
+fn EXTI0() {
+    hprint!(",").unwrap();
+}
diff --git a/app/examples/exception.rs b/app/examples/exception.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ef7683ec4b8c6c13d173dd06d2428e53e6097fc4
--- /dev/null
+++ b/app/examples/exception.rs
@@ -0,0 +1,40 @@
+//! Overriding an exception handler
+//!
+//! You can override an exception handler using the [`#[exception]`][1] attribute.
+//!
+//! [1]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html
+//!
+//! ---
+
+#![deny(unsafe_code)]
+#![no_main]
+#![no_std]
+
+extern crate panic_semihosting;
+extern crate stm32f413;
+
+use cortex_m::asm;
+use cortex_m::peripheral::syst::SystClkSource;
+use cortex_m::Peripherals;
+use cortex_m_rt::{entry, exception};
+use cortex_m_semihosting::hprint;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt();
+    let p = Peripherals::take().unwrap();
+    let mut syst = p.SYST;
+
+    // configures the system timer to trigger a SysTick exception every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(16_000_000); // period = 1s
+    syst.enable_counter();
+    syst.enable_interrupt();
+
+    loop {}
+}
+
+#[exception]
+fn SysTick() {
+    hprint!(".").unwrap();
+}
diff --git a/app/examples/hello-itm.rs b/app/examples/hello-itm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d53a11fce1dc5ef9602cb98e7beea908aa572f14
--- /dev/null
+++ b/app/examples/hello-itm.rs
@@ -0,0 +1,36 @@
+//! Sends "Hello, world!" through the ITM port 0
+//!
+//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
+//!
+//! **NOTE** Cortex-M0 chips don't support ITM.
+//!
+//! You'll have to connect the microcontroller's SWO pin to the SWD interface. Note that some
+//! development boards don't provide this option.
+//!
+//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two
+//! `monitor` commands in the `.gdbinit` file.
+//!
+//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/
+//!
+//! ---
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+extern crate stm32f413;
+
+use cortex_m::asm;
+use cortex_m::{iprintln, Peripherals};
+use cortex_m_rt::entry;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt();
+    let mut p = Peripherals::take().unwrap();
+    let stim = &mut p.ITM.stim[0];
+
+    iprintln!(stim, "Hello, plepps!");
+
+    loop {}
+}
diff --git a/app/examples/hello-semihosting.rs b/app/examples/hello-semihosting.rs
new file mode 100644
index 0000000000000000000000000000000000000000..392e3f74fea36ec04c1c5e91be4ecaee5b83a5df
--- /dev/null
+++ b/app/examples/hello-semihosting.rs
@@ -0,0 +1,19 @@
+//! Prints "Hello, world!" on the host console using semihosting
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+extern crate stm32f413;
+
+use cortex_m::asm;
+use cortex_m_rt::entry;
+use cortex_m_semihosting::hprintln;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt();
+    hprintln!("Hello, world semihosting!").unwrap();
+
+    loop {}
+}
diff --git a/app/examples/hello.rs b/app/examples/hello.rs
new file mode 100644
index 0000000000000000000000000000000000000000..392e3f74fea36ec04c1c5e91be4ecaee5b83a5df
--- /dev/null
+++ b/app/examples/hello.rs
@@ -0,0 +1,19 @@
+//! Prints "Hello, world!" on the host console using semihosting
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+extern crate stm32f413;
+
+use cortex_m::asm;
+use cortex_m_rt::entry;
+use cortex_m_semihosting::hprintln;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt();
+    hprintln!("Hello, world semihosting!").unwrap();
+
+    loop {}
+}
diff --git a/app/examples/panic-halt.rs b/app/examples/panic-halt.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dd67b6e3e4bb96f3bbc35bc3c3ef659e88b78e6f
--- /dev/null
+++ b/app/examples/panic-halt.rs
@@ -0,0 +1,22 @@
+//! Changing the panicking behavior
+//!
+//! The easiest way to change the panicking behavior is to use a different [panic handler crate][0].
+//!
+//! [0]: https://crates.io/keywords/panic-impl
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+extern crate stm32f413;
+
+use cortex_m::asm;
+use cortex_m_rt::entry;
+
+#[entry]
+#[inline(never)]
+#[no_mangle]
+fn main() -> ! {
+    asm::bkpt();
+    panic!("Oops, no output");
+}
diff --git a/app/examples/panic-itm.rs b/app/examples/panic-itm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..062f5f1f3e499d3ee17f64be071a58cbeb396db5
--- /dev/null
+++ b/app/examples/panic-itm.rs
@@ -0,0 +1,19 @@
+//! Changing the panicking behavior
+//!
+//! The easiest way to change the panicking behavior is to use a different [panic handler crate][0].
+//!
+//! [0]: https://crates.io/keywords/panic-impl
+
+#![no_main]
+#![no_std]
+
+extern crate panic_itm;
+extern crate stm32f413;
+use cortex_m::asm;
+use cortex_m_rt::entry;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt();
+    panic!("Oops Panic ITM")
+}
diff --git a/app/examples/panic-semihosting.rs b/app/examples/panic-semihosting.rs
new file mode 100644
index 0000000000000000000000000000000000000000..4902cca0a8546f02810157c2af6ab28cd1135251
--- /dev/null
+++ b/app/examples/panic-semihosting.rs
@@ -0,0 +1,19 @@
+//! Changing the panicking behavior
+//!
+//! The easiest way to change the panicking behavior is to use a different [panic handler crate][0].
+//!
+//! [0]: https://crates.io/keywords/panic-impl
+
+#![no_main]
+#![no_std]
+
+extern crate panic_semihosting;
+extern crate stm32f413;
+use cortex_m::asm;
+use cortex_m_rt::entry;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt();
+    panic!("Oops Panic Semihosting")
+}
diff --git a/app/examples/systic-interrupt-itm.rs b/app/examples/systic-interrupt-itm.rs
new file mode 100644
index 0000000000000000000000000000000000000000..aa9fdca2c03a009261079bdb42db483504b3da0e
--- /dev/null
+++ b/app/examples/systic-interrupt-itm.rs
@@ -0,0 +1,61 @@
+//! Using a device crate
+//!
+//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provide an
+//! API to access the peripherals of a device.
+//!
+//! [`svd2rust`]: https://crates.io/crates/svd2rust
+//!
+//! Device crates also provide an `interrupt!` macro (behind the "rt" feature) to register interrupt
+//! handlers.
+//!
+//! This example depends on the [`stm32f413`] crate so you'll have to add it to your Cargo.toml.
+//!
+//! [`stm32f413`]: https://gitlab.henriktjader.com/pln/stm32f413.git
+//!
+//! ---
+
+#![no_main]
+#![no_std]
+
+#[allow(unused_extern_crates)]
+extern crate panic_semihosting;
+
+use cortex_m::{iprint, iprintln, peripheral::syst::SystClkSource, Peripherals};
+use cortex_m_rt::entry;
+use stm32f413::{interrupt, Interrupt, ITM, NVIC};
+
+#[entry]
+fn main() -> ! {
+    let mut p = Peripherals::take().unwrap();
+
+    let mut syst = p.SYST;
+    let mut nvic = p.NVIC;
+    let stim = &mut p.ITM.stim[0];
+
+    iprintln!(stim, "Hello, plepps!");
+
+    nvic.enable(Interrupt::EXTI0);
+
+    // configure the system timer to wrap around every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(64_000_000); // 1s
+    syst.enable_counter();
+
+    loop {
+        // busy wait until the timer wraps around
+        while !syst.has_wrapped() {}
+
+        // trigger the `EXTI0` interrupt
+        NVIC::pend(Interrupt::EXTI0);
+    }
+}
+
+// try commenting out this line: you'll end in `default_handler` instead of in `exti0`
+#[interrupt]
+
+fn EXTI0() {
+    unsafe {
+        let stim = &mut (*ITM::ptr()).stim[0];
+        iprint!(stim, ",");
+    }
+}
diff --git a/app/memory.x b/app/memory.x
new file mode 100644
index 0000000000000000000000000000000000000000..124391e57f8f71b73b51acfc7eab2538f5f7b483
--- /dev/null
+++ b/app/memory.x
@@ -0,0 +1,34 @@
+MEMORY
+{
+  /* NOTE 1 K = 1 KiBi = 1024 bytes */
+  /* TODO Adjust these memory regions to match your device memory layout */
+  /* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
+  FLASH : ORIGIN = 0x08000000, LENGTH = 256K
+  RAM : ORIGIN = 0x20000000, LENGTH = 64K
+}
+
+/* This is where the call stack will be allocated. */
+/* The stack is of the full descending type. */
+/* You may want to use this variable to locate the call stack and static
+   variables in different memory regions. Below is shown the default value */
+/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */
+
+/* You can use this symbol to customize the location of the .text section */
+/* If omitted the .text section will be placed right after the .vector_table
+   section */
+/* This is required only on microcontrollers that store some configuration right
+   after the vector table */
+/* _stext = ORIGIN(FLASH) + 0x400; */
+
+/* Example of putting non-initialized variables into custom RAM locations. */
+/* This assumes you have defined a region RAM2 above, and in the Rust
+   sources added the attribute `#[link_section = ".ram2bss"]` to the data
+   you want to place there. */
+/* Note that the section will not be zero-initialized by the runtime! */
+/* SECTIONS {
+     .ram2bss (NOLOAD) : ALIGN(4) {
+       *(.ram2bss);
+       . = ALIGN(4);
+     } > RAM2
+   } INSERT AFTER .bss;
+*/
diff --git a/app/openocd.cfg_no_use b/app/openocd.cfg_no_use
new file mode 100644
index 0000000000000000000000000000000000000000..f510b6bb16327dd4eb6da0d0e2365afe00162970
--- /dev/null
+++ b/app/openocd.cfg_no_use
@@ -0,0 +1,13 @@
+# Sample OpenOCD configuration for the STM32F3DISCOVERY development board
+
+# Depending on the hardware revision you got you'll have to pick ONE of these
+# interfaces. At any time only one interface should be commented out.
+
+# Revision C (newer revision)
+#source [find interface/stlink-v2-1.cfg]
+source [find interface/stlink.cfg]
+
+# Revision A and B (older revisions)
+# source [find interface/stlink-v2.cfg]
+
+source [find target/stm32f4x.cfg]
diff --git a/app/openocd.gdb b/app/openocd.gdb
new file mode 100644
index 0000000000000000000000000000000000000000..60b9ef40bc2b6be0cd6a60d762d8c7ed9459a83a
--- /dev/null
+++ b/app/openocd.gdb
@@ -0,0 +1,36 @@
+target remote :3333
+#target extended-remote :3333
+
+# print demangled symbols
+set print asm-demangle on
+
+# detect unhandled exceptions, hard faults and panics
+#break DefaultHandler
+#break UserHardFault
+#break rust_begin_unwind
+
+# *try* to stop at the user entry point (it might be gone due to inlining)
+#break main
+
+monitor arm semihosting enable
+
+# # send captured ITM to the file itm.fifo
+# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
+# # 8000000 must match the core clock frequency
+monitor tpiu config internal /tmp/itm.log uart off 16000000 2000000
+
+# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
+# # 8000000 must match the core clock frequency
+# # 2000000 is the frequency of the SWO pin
+# monitor tpiu config external uart off 8000000 2000000
+
+# # enable ITM port 0
+monitor itm port 0 on
+
+load
+
+# puts the MCU in 64MHz
+#monitor reset init
+
+# start the process but immediately halt the processor
+stepi
diff --git a/app/openocd.gdb_no_use b/app/openocd.gdb_no_use
new file mode 100644
index 0000000000000000000000000000000000000000..60b9ef40bc2b6be0cd6a60d762d8c7ed9459a83a
--- /dev/null
+++ b/app/openocd.gdb_no_use
@@ -0,0 +1,36 @@
+target remote :3333
+#target extended-remote :3333
+
+# print demangled symbols
+set print asm-demangle on
+
+# detect unhandled exceptions, hard faults and panics
+#break DefaultHandler
+#break UserHardFault
+#break rust_begin_unwind
+
+# *try* to stop at the user entry point (it might be gone due to inlining)
+#break main
+
+monitor arm semihosting enable
+
+# # send captured ITM to the file itm.fifo
+# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
+# # 8000000 must match the core clock frequency
+monitor tpiu config internal /tmp/itm.log uart off 16000000 2000000
+
+# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
+# # 8000000 must match the core clock frequency
+# # 2000000 is the frequency of the SWO pin
+# monitor tpiu config external uart off 8000000 2000000
+
+# # enable ITM port 0
+monitor itm port 0 on
+
+load
+
+# puts the MCU in 64MHz
+#monitor reset init
+
+# start the process but immediately halt the processor
+stepi
diff --git a/app/src/main.rs b/app/src/main.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ebd84f9319deea68c3ef177b0bd119aa9812024f
--- /dev/null
+++ b/app/src/main.rs
@@ -0,0 +1,22 @@
+#![no_std]
+#![no_main]
+
+// pick a panicking behavior
+extern crate panic_halt; // you can put a breakpoint on `rust_begin_unwind` to catch panics
+                         // extern crate panic_abort; // requires nightly
+                         // extern crate panic_itm; // logs messages over ITM; requires ITM support
+                         // extern crate panic_semihosting; // logs messages to the host stderr; requires a debugger
+
+extern crate stm32f413;
+
+use cortex_m::asm;
+use cortex_m_rt::entry;
+
+#[entry]
+fn main() -> ! {
+    asm::bkpt(); // To not have main optimize to abort in release mode, remove when you add code
+
+    loop {
+        // your code goes here
+    }
+}
diff --git a/app/stlink.cfg b/app/stlink.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..735ad5a4ec9cdb9df62a14bf7af213ea61c8b160
--- /dev/null
+++ b/app/stlink.cfg
@@ -0,0 +1,17 @@
+#
+# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 in-circuit
+# debugger/programmer
+#
+
+interface hla
+hla_layout stlink
+hla_device_desc "ST-LINK"
+hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b 0x0483 0x374d 0x0483 0x374e 0x0483 0x374f 0x0483 0x3752 0x0483 0x3753
+
+# Optionally specify the serial number of ST-LINK/V2 usb device.  ST-LINK/V2
+# devices seem to have serial numbers with unreadable characters.  ST-LINK/V2
+# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial
+# number reset issues.
+# eg.
+#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f"
+
diff --git a/app/stm32f4x.cfg b/app/stm32f4x.cfg
new file mode 100644
index 0000000000000000000000000000000000000000..20c6815e773f92e175ed8b97109d0d979871d8c6
--- /dev/null
+++ b/app/stm32f4x.cfg
@@ -0,0 +1,108 @@
+# script for stm32f4x family
+
+#
+# stm32 devices support both JTAG and SWD transports.
+#
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+   set _CHIPNAME $CHIPNAME
+} else {
+   set _CHIPNAME stm32f4x
+}
+
+set _ENDIAN little
+
+# Work-area is a space in RAM used for flash programming
+# By default use 32kB (Available RAM in smallest device STM32F410)
+if { [info exists WORKAREASIZE] } {
+   set _WORKAREASIZE $WORKAREASIZE
+} else {
+   set _WORKAREASIZE 0x8000
+}
+
+#jtag scan chain
+if { [info exists CPUTAPID] } {
+   set _CPUTAPID $CPUTAPID
+} else {
+   if { [using_jtag] } {
+      # See STM Document RM0090
+      # Section 38.6.3 - corresponds to Cortex-M4 r0p1
+      set _CPUTAPID 0x4ba00477
+   } {
+      set _CPUTAPID 0x2ba01477
+   }
+}
+
+swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
+dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+
+if {[using_jtag]} {
+   jtag newtap $_CHIPNAME bs -irlen 5
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+set _FLASHNAME $_CHIPNAME.flash
+flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME
+
+# JTAG speed should be <= F_CPU/6. F_CPU after reset is 16MHz, so use F_JTAG = 2MHz
+#
+# Since we may be running of an RC oscilator, we crank down the speed a
+# bit more to be on the safe side. Perhaps superstition, but if are
+# running off a crystal, we can run closer to the limit. Note
+# that there can be a pretty wide band where things are more or less stable.
+adapter_khz 2000
+
+adapter_nsrst_delay 100
+if {[using_jtag]} {
+ jtag_ntrst_delay 100
+}
+
+reset_config srst_nogate
+
+if {![using_hla]} {
+   # if srst is not fitted use SYSRESETREQ to
+   # perform a soft reset
+   cortex_m reset_config sysresetreq
+}
+
+$_TARGETNAME configure -event examine-end {
+	# Enable debug during low power modes (uses more power)
+	# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
+	mmw 0xE0042004 0x00000007 0
+
+	# Stop watchdog counters during halt
+	# DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP
+	mmw 0xE0042008 0x00001800 0
+}
+
+$_TARGETNAME configure -event trace-config {
+	# Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
+	# change this value accordingly to configure trace pins
+	# assignment
+	mmw 0xE0042004 0x00000020 0
+}
+
+$_TARGETNAME configure -event reset-init {
+	# Configure PLL to boost clock to HSI x 4 (64 MHz)
+	#mww 0x40023804 0x08012008   ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P)
+	#mww 0x40023C00 0x00000102   ;# FLASH_ACR = PRFTBE | 2(Latency)
+	#mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON
+	#sleep 10                    ;# Wait for PLL to lock
+	#mmw 0x40023808 0x00001000 0 ;# RCC_CFGR |= RCC_CFGR_PPRE1_DIV2
+	#mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL
+
+	# Boost JTAG frequency
+	#adapter_khz 8000
+	adapter_khz 4000
+}
+
+$_TARGETNAME configure -event reset-start {
+	# Reduce speed since CPU speed will slow down to 16MHz with the reset
+	adapter_khz 2000
+}