diff --git a/examples/nuttali_mouse.rs b/examples/nuttali_mouse.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8ce314810a04e6974f22238d765dc22fd15493d1
--- /dev/null
+++ b/examples/nuttali_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;
+        }
+    }
+};