diff --git a/Cargo.toml b/Cargo.toml
index 0029c8b9e10e46f747ed8d913deffd491e8fa30e..76ff65fca1fc0e15563c1daf41b133918e8e5cf7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,7 @@ cortex-m = { version = "0.7.1", features = ["linker-plugin-lto"] }
 cortex-m-rt = "0.6.13"
 cortex-m-semihosting = "0.3.7"
 cortex-m-rtic = "0.5.5"
+# embedded-hal = { version = "0.2.4", features = ["unproven"] }
 embedded-hal = "0.2.4"
 usb-device = "0.2.7"
 
@@ -17,7 +18,7 @@ usb-device = "0.2.7"
 panic-halt = "0.2.0"
 
 # Uncomment for the itm panic examples.
-#panic-itm = "0.4.2"
+panic-itm = "0.4.2"
 
 # Uncomment for the rtt-timing examples.
 panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
@@ -27,14 +28,13 @@ panic-semihosting = "0.5.6"
 
 # Tracing
 rtt-target = { version = "0.3.0", features = ["cortex-m"] }
+nb = "1.0.0"
+usbd-hid = "0.5.0"
 
 [dependencies.stm32f4]
 version = "0.13.0"
 features = ["stm32f411", "rt"]
 
-# Uncomment for the allocator example.
-# alloc-cortex-m = "0.4.0"
-
 
 [dependencies.stm32f4xx-hal]
 version = "0.8.3"
@@ -45,28 +45,18 @@ features = ["rt", "stm32f411", "usb_fs"]
 # path = "../stm32f4xx-hal"
 
 # this lets you use `cargo fix`!
-[[bin]]
-name = "app"
-test = false
-bench = false
+# [[bin]]
+# name = "app"
+# # test = false
+# bench = false
 
 [profile.dev]
 incremental = false
 codegen-units = 1
+overflow-checks = 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
 
-
-
-# [features]
-# nightly = ["cortex-m/inline-asm"]
-
-# # this lets you use `cargo fix`!
-# [[bin]]
-# name = "app"
-# test = false
-# bench = false
-
diff --git a/examples/usb-mouse.rs b/examples/usb-mouse.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8ce314810a04e6974f22238d765dc22fd15493d1
--- /dev/null
+++ b/examples/usb-mouse.rs
@@ -0,0 +1,110 @@
+// > cargo run usb-mouse
+// or
+// > cargo run usb-mouse --release
+
+#![no_main]
+#![no_std]
+
+use stm32f4xx_hal::{
+    gpio::{gpioc::PC13, Input, PullUp},
+    otg_fs::{UsbBus, UsbBusType, USB},
+    prelude::*,
+};
+use usb_device::{bus::UsbBusAllocator, prelude::*};
+use usbd_hid::{
+    descriptor::{generator_prelude::*, MouseReport},
+    hid_class::HIDClass,
+};
+
+use panic_rtt_target as _;
+use rtt_target::{rprintln, rtt_init_print};
+
+#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
+const APP: () = {
+    struct Resources {
+        btn: PC13<Input<PullUp>>,
+        hid: HIDClass<'static, UsbBusType>,
+        usb_dev: UsbDevice<'static, UsbBus<USB>>,
+    }
+
+    #[init]
+    fn init(ctx: init::Context) -> init::LateResources {
+        static mut EP_MEMORY: [u32; 1024] = [0; 1024];
+        static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None;
+
+        rtt_init_print!();
+        rprintln!("init");
+
+        // Set up the system clock.
+        let rcc = ctx.device.RCC.constrain();
+        let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
+
+        let gpioc = ctx.device.GPIOC.split();
+        let btn = gpioc.pc13.into_pull_up_input();
+
+        let gpioa = ctx.device.GPIOA.split();
+        let usb = USB {
+            usb_global: ctx.device.OTG_FS_GLOBAL,
+            usb_device: ctx.device.OTG_FS_DEVICE,
+            usb_pwrclk: ctx.device.OTG_FS_PWRCLK,
+            pin_dm: gpioa.pa11.into_alternate_af10(),
+            pin_dp: gpioa.pa12.into_alternate_af10(),
+        };
+        USB_BUS.replace(UsbBus::new(usb, EP_MEMORY));
+
+        let hid = HIDClass::new(USB_BUS.as_ref().unwrap(), MouseReport::desc(), 1);
+        let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000))
+            .manufacturer("E70011E")
+            .product("Mouse")
+            .serial_number("1.0")
+            .device_class(0)
+            .build();
+
+        init::LateResources { btn, hid, usb_dev }
+    }
+
+    #[task(binds=OTG_FS, resources = [btn, hid, usb_dev])]
+    fn on_usb(ctx: on_usb::Context) {
+        static mut COUNTER: u16 = 0;
+
+        // destruct the context
+        let (btn, usb_dev, hid) = (ctx.resources.btn, ctx.resources.usb_dev, ctx.resources.hid);
+
+        let report = MouseReport {
+            x: match *COUNTER {
+                // reached after 100ms
+                100 => {
+                    rprintln!("10");
+                    10
+                }
+                // reached after 199ms
+                199 => {
+                    rprintln!("-10");
+                    -10
+                }
+                _ => 0,
+            },
+            y: 0,
+            buttons: btn.is_low().unwrap().into(), // (into takes a bool into an integer)
+            wheel: 0,
+        };
+        // wraps around after 200ms
+        *COUNTER = (*COUNTER + 1) % 200;
+
+        // push the report
+        hid.push_input(&report).ok();
+
+        // update the usb device state
+        if usb_dev.poll(&mut [hid]) {
+            return;
+        }
+    }
+
+    #[idle]
+    fn idle(_cx: idle::Context) -> ! {
+        rprintln!("idle");
+        loop {
+            continue;
+        }
+    }
+};