From 5e2f0e81bb2bccfb08341a06c06e45fb78fd49ca Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Wed, 23 Jun 2021 14:09:26 +0200
Subject: [PATCH] fixed st-flash (instead of st-util)

---
 .vscode/launch.json            |   2 +-
 CHANGELOG.md                   |  38 +++---
 Cargo.toml                     |   7 +-
 README.md                      |   6 +-
 examples/itm_rtic_hello.rs     |   4 +
 examples/pmw3389.rs            |  14 +--
 examples/rtic_bare1.rs         |   2 +
 examples/rtic_bare7.rs         |  14 +--
 examples/rtt-pmw3389-sine.rs   | 206 ++++++++++++++++++++++++++-------
 examples/rtt-pwm-sine-task.rs  |  15 ++-
 examples/rtt-pwm-sine.rs       |   2 +-
 examples/rtt-timing.rs         |   4 +-
 examples/rtt_rtic_i2c.rs       | 138 +++++++++++++---------
 examples/rtt_rtic_usb_mouse.rs |   1 +
 examples/usb-mouse.rs          |  13 ++-
 openocd.gdb                    |   2 +-
 src/main.rs                    |  20 ----
 src/pmw3389.rs                 |  23 +---
 src/pmw3389e.rs                |  16 +--
 19 files changed, 341 insertions(+), 186 deletions(-)
 delete mode 100644 src/main.rs

diff --git a/.vscode/launch.json b/.vscode/launch.json
index 3fcc60a..b0ce2bf 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -150,4 +150,4 @@
             "cpu": "cortex-m4",
         }
     ]
-}
\ No newline at end of file
+}.
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39a885d..ec61480 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,47 +1,53 @@
 # Changelog
 
+## 2021-03-19
+
+- `examples/itm_rtic_hello_48MHz.rs`, example to trace ITM, when processor runs at 48MHz, useful to debug USB applications.
+  
+- `.vscode/launch.json`, added 48MHz itm tracing profiles. (Now consistenly using `stlink.cfg`.)
+  
 ## 2021-03-18
 
-- examples/usb-mouse.rs, a very small example using external hid library.
+- `examples/usb-mouse.rs`, a very small example using external hid library.
   
 ## 2021-03-07
 
-- examples/rtic_bare7.rs, using embedded HAL.
-- examples/rtic_bare8.rs, serial communication, bad design.
-- examples/rtic_bare9.rs, serial communication, good design.
+- `examples/rtic_bare7.rs`, using embedded HAL.
+- `examples/rtic_bare8.rs`, serial communication, bad design.
+- `examples/rtic_bare9.rs`, serial communication, good design.
   
 ## 2021-03-05
 
-- examples/rtic_bare6.rs, setup and validate the clock tree.
+- `examples/rtic_bare6.rs`, setup and validate the clock tree.
 
 ## 2021-02-28
 
-- examples/rtic_bare2.rs, raw timer access.
-- examples/rtic_bare3.rs, timing abstractions.
-- examples/rtic_bare4.rs, a simple bare metal peripheral access API.
-- examples/rtic_bare5.rs, write your own C-like peripheral access API.
+- `examples/rtic_bare2.rs`, raw timer access.
+- `examples/rtic_bare3.rs`, timing abstractions.
+- `examples/rtic_bare4.rs`, a simple bare metal peripheral access API.
+- `examples/rtic_bare5.rs`, write your own C-like peripheral access API.
 
 ## 2021-02-26
 
-- examples/bare1.rs, bare metal 101!
+- `examples/bare1.rs`, bare metal 101!
   
 ## 2021-02-23
 
-- examples/rtic_blinky.rs, added instructions to terminal based debugging
+- `examples/rtic_blinky.rs`, added instructions to terminal based debugging
   
 ## 2021-02-22
 
-- memory.x, reduced flash size to 128k to match light-weight target
-- Cargo.toml, updated dependencies to latest stm32f4xx-hal/pac
+- `memory.x`, reduced flash size to 128k to match light-weight target
+- `Cargo.toml`, updated dependencies to latest `stm32f4xx-hal/pac`
 
 Some experiments (wip):
 
-- examples/rtt_rtic_i2c.rs, spi emulation over i2c
-- src/pwm3389e, driver using emulated spi
+- `examples/rtt_rtic_i2c.rs`, spi emulation over i2c
+- `src/pwm3389e`, driver using emulated spi
 
 ## 2021-02-16
 
-- rtt_rtic_usb_mouse updated
+- `rtt_rtic_usb_mouse` updated
   Notice, requires release build
 
 ## 2021-02-15
diff --git a/Cargo.toml b/Cargo.toml
index 76ff65f..e4af31a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ version = "0.1.0"
 
 [dependencies]
 cortex-m = { version = "0.7.1", features = ["linker-plugin-lto"] }
+# cortex-m = { version = "0.7.1" }
 cortex-m-rt = "0.6.13"
 cortex-m-semihosting = "0.3.7"
 cortex-m-rtic = "0.5.5"
@@ -27,9 +28,10 @@ panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
 panic-semihosting = "0.5.6"
 
 # Tracing
-rtt-target = { version = "0.3.0", features = ["cortex-m"] }
+rtt-target = { version = "0.3.1", features = ["cortex-m"] }
 nb = "1.0.0"
 usbd-hid = "0.5.0"
+micromath = "1.1.0"
 
 [dependencies.stm32f4]
 version = "0.13.0"
@@ -37,7 +39,7 @@ features = ["stm32f411", "rt"]
 
 
 [dependencies.stm32f4xx-hal]
-version = "0.8.3"
+version = "0.9.0"
 features = ["rt", "stm32f411", "usb_fs"] 
 # Enable to use the latest git version
 # gitgit = "https://github.com/stm32-rs/stm32f4xx-hal"
@@ -56,6 +58,7 @@ codegen-units = 1
 overflow-checks = false  
 
 [profile.release]
+incremental = false
 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/README.md b/README.md
index 88e331d..c1b6a8a 100644
--- a/README.md
+++ b/README.md
@@ -197,9 +197,9 @@ D+ used for re-enumeration. You don't need to connect the V+ from the USB cable,
   - If this does not work you can try to erase the flash memory (the program running on the STM32F401/F11).
 
     ``` shell
-    > st-util erase
-    st-flash 1.6.1
-    2021-01-11T16:02:14 INFO common.c: F4xx (Dynamic Efficency): 96 KiB SRAM, 512 KiB flash in at least 16 KiB pages.
+    > st-flash erase
+    st-flash 1.7.0
+    2021-06-23T14:07:35 INFO common.c: F4xx (Dynamic Efficency): 96 KiB SRAM, 512 KiB flash in at least 16 KiB pages.
     Mass erasing.......
     ```
 
diff --git a/examples/itm_rtic_hello.rs b/examples/itm_rtic_hello.rs
index 963183d..013f4fd 100644
--- a/examples/itm_rtic_hello.rs
+++ b/examples/itm_rtic_hello.rs
@@ -9,6 +9,10 @@ use stm32f4;
 const APP: () = {
     #[init]
     fn init(cx: init::Context) {
+        // Set up the system clock.
+        let rcc = ctx.device.RCC.constrain();
+        let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
+
         let mut p = cx.core;
         let stim = &mut p.ITM.stim[0];
         for a in 0..=10 {
diff --git a/examples/pmw3389.rs b/examples/pmw3389.rs
index 746cf15..20795ac 100644
--- a/examples/pmw3389.rs
+++ b/examples/pmw3389.rs
@@ -86,15 +86,15 @@ const APP: () = {
             device.SPI2,
             (sck, miso, mosi),
             MODE_3,
-            stm32f4xx_hal::time::KiloHertz(2000).into(),
+            stm32f4xx_hal::time::KiloHertz(200).into(),
             clocks,
         );
 
-        let mut delay = DwtDelay::new(&mut core.DWT, clocks);
+        let delay = DwtDelay::new(&mut core.DWT, clocks);
         let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap();
 
         // set in burst mode
-        pmw3389.write_register(Register::MotionBurst, 0x00);
+        pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
 
         // semantically, the monotonic timer is frozen at time "zero" during `init`
         // NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
@@ -111,8 +111,10 @@ const APP: () = {
         static mut COUNTER: u32 = 0;
         static mut POS_X: i64 = 0;
 
+        // run each ms
         *COUNTER += 1;
-        if *COUNTER == 1000 / RATIO {
+        if *COUNTER == 1000 {
+            // run each s
             cx.spawn.trace(*POS_X).unwrap();
             *COUNTER = 0;
         }
@@ -121,9 +123,7 @@ const APP: () = {
         *POS_X += x as i64;
 
         // task should run each second N ms (16_000 cycles at 16MHz)
-        cx.schedule
-            .poll(cx.scheduled + (RATIO * 16_000).cycles())
-            .unwrap();
+        cx.schedule.poll(cx.scheduled + 16_000.cycles()).unwrap();
     }
 
     #[task(priority = 1)]
diff --git a/examples/rtic_bare1.rs b/examples/rtic_bare1.rs
index 11248f4..261388d 100644
--- a/examples/rtic_bare1.rs
+++ b/examples/rtic_bare1.rs
@@ -9,6 +9,7 @@
 #![no_main]
 #![no_std]
 
+use cortex_m_semihosting::hprintln;
 use panic_semihosting as _;
 use stm32f4;
 
@@ -18,6 +19,7 @@ const APP: () = {
     #[inline(never)] // avoid inlining of this function/task
     #[no_mangle] // to strip hash from symbols (easier to read)
     fn init(_cx: init::Context) {
+        hprintln!("hello");
         let mut x = core::u32::MAX - 1;
         loop {
             // cortex_m::asm::bkpt();
diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs
index 0f2dea1..cd3b2c8 100644
--- a/examples/rtic_bare7.rs
+++ b/examples/rtic_bare7.rs
@@ -17,7 +17,7 @@ use stm32f4xx_hal::{
     gpio::{gpioa::PA5, Output, PushPull},
     prelude::*,
 };
-;
+
 use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
 
 const OFFSET: u32 = 8_000_000;
@@ -144,7 +144,7 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) {
 //
 //    Our `PA5<Output<PushPull>>` implements `OutputPin` trait, thus
 //    we can pass the `led` resource to `_toggle_generic`.
-//    
+//
 //    The error type is given by the stm32f4xx-hal implementation:
 //    where `core::convert::Infallible` is used to indicate
 //    there are no errors to be expected (hence infallible).
@@ -205,16 +205,16 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) {
 //    is the same behind drivers for USART communication, USB, PMW3389 etc.
 //
 // 5. More details:
-//    
+//
 //    Looking closer at the implementation:
 //    `led: &mut dyn OutputPin<Error = E>`
 //
 //    You may ask what kind of mumbo jumbo is at play here.
 //
-//    This is the way to express that we expect a mutable reference to a trait object 
+//    This is the way to express that we expect a mutable reference to a trait object
 //    that implements the `OutputPin`. Since we will change the underlying object
 //    (in this case an GPIOA pin 5) the reference needs to be mutable.
-// 
+//
 //    Trait objects are further explained in the Rust book.
 //    The `dyn` keyword indicates dynamic dispatch (through a VTABLE).
 //    https://doc.rust-lang.org/std/keyword.dyn.html
@@ -237,5 +237,5 @@ fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) {
 //
 //    You might find Rust to have long compile times. Yes you are right,
 //    and this type of deep analysis done in release mode is part of the story.
-//    On the other hand, the aggressive optimization allows us to code 
-//    in a generic high level fashion and still have excellent performing binaries.
\ No newline at end of file
+//    On the other hand, the aggressive optimization allows us to code
+//    in a generic high level fashion and still have excellent performing binaries.
diff --git a/examples/rtt-pmw3389-sine.rs b/examples/rtt-pmw3389-sine.rs
index 0aae89b..b007b37 100644
--- a/examples/rtt-pmw3389-sine.rs
+++ b/examples/rtt-pmw3389-sine.rs
@@ -6,9 +6,8 @@
 #![no_main]
 #![no_std]
 
-// use core::f32::consts::PI;
 use cortex_m::{asm, peripheral::DWT};
-// use panic_halt as _;
+
 use panic_rtt_target as _;
 use rtic::cyccnt::{Instant, U32Ext as _};
 use rtt_target::{rprint, rprintln, rtt_init_print};
@@ -16,7 +15,41 @@ use rtt_target::{rprint, rprintln, rtt_init_print};
 use core::f32::consts::PI;
 use micromath::F32Ext;
 
-use stm32f4xx_hal::{bb, gpio::Speed, prelude::*, pwm, stm32};
+use stm32f4xx_hal::{
+    bb,
+    dwt::Dwt,
+    gpio::Speed,
+    gpio::{
+        gpiob::{PB10, PB4},
+        gpioc::{PC2, PC3},
+        Alternate, Output, PushPull,
+    },
+    prelude::*,
+    pwm,
+    rcc::Clocks,
+    spi::Spi,
+    stm32,
+};
+
+use embedded_hal::spi::MODE_3;
+use panic_rtt_target as _;
+
+use app::{
+    pmw3389::{self, Register},
+    DwtDelay,
+};
+
+type PMW3389T = pmw3389::Pmw3389<
+    Spi<
+        stm32f4xx_hal::stm32::SPI2,
+        (
+            PB10<Alternate<stm32f4xx_hal::gpio::AF5>>,
+            PC2<Alternate<stm32f4xx_hal::gpio::AF5>>,
+            PC3<Alternate<stm32f4xx_hal::gpio::AF5>>,
+        ),
+    >,
+    PB4<Output<PushPull>>,
+>;
 
 include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs"));
 
@@ -25,28 +58,64 @@ const APP: () = {
     struct Resources {
         // late resources
         TIM1: stm32::TIM1,
+        pmw3389: PMW3389T,
     }
-    #[init(schedule = [pwm_out])]
+    #[init(schedule = [pwm_out, poll])]
     fn init(mut cx: init::Context) -> init::LateResources {
         rtt_init_print!();
         rprintln!("init");
-        let dp = cx.device;
+
+        let device = cx.device;
+        let mut core = cx.core;
 
         // Initialize (enable) the monotonic timer (CYCCNT)
-        cx.core.DCB.enable_trace();
-        cx.core.DWT.enable_cycle_counter();
-
-        let rcc = dp.RCC.constrain();
-        // Set up the system clock. 48 MHz?
-        let clocks = rcc
-            .cfgr
-            // .use_hse(8.mhz())
-            // .sysclk(48.mhz())
-            .sysclk(96.mhz())
-            .pclk1(24.mhz())
-            .freeze();
-
-        let gpioa = dp.GPIOA.split();
+        core.DCB.enable_trace();
+        core.DWT.enable_cycle_counter();
+
+        let rcc = device.RCC.constrain();
+        // Set up the system clock. 96 MHz?
+        let clocks = rcc.cfgr.sysclk(96.mhz()).pclk1(24.mhz()).freeze();
+
+        // Configure SPI
+        // spi2
+        // sck    - pb10, (yellow)
+        // miso   - pc2, (red)
+        // mosi   - pc3, (orange)
+        // ncs    - pb4, (long yellow)
+        // motion - (brown)
+        //
+        // +5, (white)
+        // gnd, (black)
+
+        cortex_m::asm::dsb(); // chip errata
+        let gpiob = device.GPIOB.split();
+        cortex_m::asm::dsb(); // chip errata
+        let gpioc = device.GPIOC.split();
+        cortex_m::asm::dsb(); // chip errata
+
+        let sck = gpiob.pb10.into_alternate_af5().set_speed(Speed::VeryHigh);
+        let miso = gpioc.pc2.into_alternate_af5().set_speed(Speed::High);
+        let mosi = gpioc.pc3.into_alternate_af5().set_speed(Speed::High);
+        let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High);
+
+        let spi = Spi::spi2(
+            device.SPI2,
+            (sck, miso, mosi),
+            MODE_3,
+            stm32f4xx_hal::time::KiloHertz(2000).into(),
+            clocks,
+        );
+
+        let delay = DwtDelay::new(&mut core.DWT, clocks);
+        let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap();
+
+        // // set in burst mode
+        // pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
+
+        // setup TIM1 as PWM (for implementing an 8 bit DA)
+        let gpioa = device.GPIOA.split();
+        cortex_m::asm::dsb(); // chip errata
+
         // we set the pins to VeryHigh to get the sharpest waveform possible
         // (rise and fall times should have similar characteristics)
         let _channels = (
@@ -55,7 +124,7 @@ const APP: () = {
         );
 
         // Setup PWM RAW
-        let tim1 = dp.TIM1;
+        let tim1 = device.TIM1;
         // Here we need unsafe as we are "stealing" the RCC peripheral
         // At this point it has been contrained into SysConf and used to set clocks
         let rcc = unsafe { &(*stm32::RCC::ptr()) };
@@ -77,7 +146,7 @@ const APP: () = {
         tim1.cr1.modify(|_, w| w.arpe().set_bit());
 
         let clk = clocks.pclk2().0 * if clocks.ppre2() == 1 { 1 } else { 2 };
-        // check that its actually 48_000_000
+        // check the actual clock setup
         rprintln!("clk {}", clk);
 
         // we want maximum performance, thus we set the prescaler to 0
@@ -128,18 +197,20 @@ const APP: () = {
         tim1.dier.write(|w| w.uie().enabled());
         tim1.sr.modify(|_, w| w.uif().clear());
 
-        // Set divider to 4, (48_000_000/256)/4
-        // tim1.rcr.modify(|_, w| unsafe { w.rep().bits(4) });
-
+        // just to check that we actually get update events
         while tim1.sr.read().uif().is_clear() {
             rprint!("-");
         }
         rprintln!("here");
         tim1.sr.modify(|_, w| w.uif().clear());
 
+        cx.schedule.pwm_out(cx.start + PWM_CYCLES.cycles()).ok();
+        cx.schedule.poll(cx.start + POLL_CYCLES.cycles()).ok();
         // pass on late resources
-        cx.schedule.pwm_out(cx.start + PERIOD.cycles()).ok();
-        init::LateResources { TIM1: tim1 }
+        init::LateResources {
+            TIM1: tim1,
+            pmw3389,
+        }
     }
 
     #[idle]
@@ -147,41 +218,98 @@ const APP: () = {
         rprintln!("idle");
         // panic!("panic");
         loop {
-            continue;
+            asm::nop()
+        }
+    }
+
+    #[task(priority = 1)]
+    fn trace(_cx: trace::Context, pos_x: i64, pos_y: i64) {
+        static mut OLD_POS_X: i64 = 0;
+        static mut OLD_POS_Y: i64 = 0;
+        rprintln!(
+            "@{:?}, pos_x {:010}, diff {:010}, pos_y {:010}, diff {:010} ",
+            Instant::now(),
+            pos_x,
+            pos_x.wrapping_sub(*OLD_POS_X),
+            pos_y,
+            pos_y.wrapping_sub(*OLD_POS_Y),
+        );
+        *OLD_POS_X = pos_x;
+        *OLD_POS_Y = pos_y;
+    }
+
+    #[task(priority = 2, resources = [pmw3389], schedule = [poll], spawn = [trace])]
+    fn poll(cx: poll::Context) {
+        static mut COUNTER: u32 = 0;
+        static mut POS_X: i64 = 0;
+        static mut POS_Y: i64 = 0;
+
+        // run each ms
+        *COUNTER += 1;
+        if *COUNTER == 1000 {
+            // run each s
+            cx.spawn.trace(*POS_X, *POS_Y).unwrap();
+            *COUNTER = 0;
         }
+
+        let pmw3389 = cx.resources.pmw3389;
+
+        //write 0x01 to Motion register and read from it to freeze the motion values and make them available
+        pmw3389.write_register(Register::Motion, 0x01).unwrap();
+        let _ = pmw3389.read_register(Register::Motion).unwrap();
+
+        let xl: u8 = pmw3389.read_register(Register::DeltaXL).unwrap();
+        let xh: u8 = pmw3389.read_register(Register::DeltaXH).unwrap();
+        let yl = pmw3389.read_register(Register::DeltaYL).unwrap();
+        let yh = pmw3389.read_register(Register::DeltaYH).unwrap();
+
+        // let (x, _y) = cx.resources.pmw3389.read_status().unwrap();
+        *POS_X += (((xl as u16) | ((xh as u16) << 8)) as i16) as i64;
+        *POS_Y += (((yl as u16) | ((yh as u16) << 8)) as i16) as i64;
+
+        // task should run each second N ms (96_000 cycles at 96MHz)
+        cx.schedule
+            .poll(cx.scheduled + POLL_CYCLES.cycles())
+            .unwrap();
     }
 
-    #[task(resources = [TIM1], schedule = [pwm_out])]
+    #[task(priority = 3, resources = [TIM1], schedule = [pwm_out])]
     fn pwm_out(cx: pwm_out::Context) {
         static mut INDEX: u16 = 0;
         static mut LEFT: u16 = 0;
         static mut RIGHT: u16 = 0;
-        static mut FLOAT: u16 = 0;
+        // static mut FLOAT: u16 = 0;
 
         let tim1 = cx.resources.TIM1;
 
         tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) });
-        // tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
-        tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) });
+        tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
+        // tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) });
+
+        cx.schedule
+            .pwm_out(cx.scheduled + PWM_CYCLES.cycles())
+            .unwrap();
 
-        *INDEX = (*INDEX).wrapping_add(10_000);
-        let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0;
-        *FLOAT = (128.0 + f.sin() * 128.0) as u16;
-        cx.schedule.pwm_out(cx.scheduled + PERIOD.cycles()).ok();
+        *INDEX = (*INDEX).wrapping_add(1_000);
+        // let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0;
+        // *FLOAT = (128.0 + f.sin() * 128.0) as u16;
 
         *LEFT = SINE_BUF[*INDEX as usize] as u16;
         *RIGHT = SINE_BUF[*INDEX as usize] as u16;
 
-        if cx.scheduled.elapsed() > 500.cycles() {
-            panic!("task overrun");
-        }
+        // if cx.scheduled.elapsed() > 1500.cycles() {
+        //     panic!("task overrun");
+        // }
     }
 
     extern "C" {
         fn EXTI0();
+        fn EXTI1();
+        fn EXTI2();
     }
 };
 
 // We aim for a sampling rate of 48kHz, assuming that the input filter of the
 // sound card used to sample the generated signal has an appropriate input filter
-const PERIOD: u32 = 2000; // 96_000_000 / 48_000;
+const PWM_CYCLES: u32 = 2000; // 96_000_000 / 2_000 = 48_000 Hz
+const POLL_CYCLES: u32 = 96_000; // 96_000_000 / 96_000 = 1_000 Hz
diff --git a/examples/rtt-pwm-sine-task.rs b/examples/rtt-pwm-sine-task.rs
index 4858241..0aae89b 100644
--- a/examples/rtt-pwm-sine-task.rs
+++ b/examples/rtt-pwm-sine-task.rs
@@ -6,14 +6,17 @@
 #![no_main]
 #![no_std]
 
-use core::f32::consts::PI;
+// use core::f32::consts::PI;
 use cortex_m::{asm, peripheral::DWT};
 // use panic_halt as _;
 use panic_rtt_target as _;
 use rtic::cyccnt::{Instant, U32Ext as _};
 use rtt_target::{rprint, rprintln, rtt_init_print};
 
-use stm32f4xx_hal::{bb, dma, gpio::Speed, prelude::*, pwm, stm32};
+use core::f32::consts::PI;
+use micromath::F32Ext;
+
+use stm32f4xx_hal::{bb, gpio::Speed, prelude::*, pwm, stm32};
 
 include!(concat!(env!("OUT_DIR"), "/sin_abs_const.rs"));
 
@@ -153,19 +156,23 @@ const APP: () = {
         static mut INDEX: u16 = 0;
         static mut LEFT: u16 = 0;
         static mut RIGHT: u16 = 0;
+        static mut FLOAT: u16 = 0;
 
         let tim1 = cx.resources.TIM1;
 
         tim1.ccr1.write(|w| unsafe { w.ccr().bits(*LEFT) });
-        tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
+        // tim1.ccr2.write(|w| unsafe { w.ccr().bits(*RIGHT) });
+        tim1.ccr2.write(|w| unsafe { w.ccr().bits(*FLOAT) });
 
         *INDEX = (*INDEX).wrapping_add(10_000);
+        let f: f32 = (*INDEX as f32 * 2.0 * PI) / 65536.0;
+        *FLOAT = (128.0 + f.sin() * 128.0) as u16;
         cx.schedule.pwm_out(cx.scheduled + PERIOD.cycles()).ok();
 
         *LEFT = SINE_BUF[*INDEX as usize] as u16;
         *RIGHT = SINE_BUF[*INDEX as usize] as u16;
 
-        if cx.scheduled.elapsed() > 300.cycles() {
+        if cx.scheduled.elapsed() > 500.cycles() {
             panic!("task overrun");
         }
     }
diff --git a/examples/rtt-pwm-sine.rs b/examples/rtt-pwm-sine.rs
index 726f5cb..e9fdb2e 100644
--- a/examples/rtt-pwm-sine.rs
+++ b/examples/rtt-pwm-sine.rs
@@ -47,7 +47,7 @@ const APP: () = {
         // Setup PWM RAW
         let tim1 = dp.TIM1;
         // Here we need unsafe as we are "stealing" the RCC peripheral
-        // At this point it has been contrained into SysConf and used to set clocks
+        // At this point it has been constrained into SysConf and used to set clocks
         let rcc = unsafe { &(*stm32::RCC::ptr()) };
 
         rcc.apb2enr.modify(|_, w| w.tim1en().set_bit());
diff --git a/examples/rtt-timing.rs b/examples/rtt-timing.rs
index 720e799..7e1ee06 100644
--- a/examples/rtt-timing.rs
+++ b/examples/rtt-timing.rs
@@ -1,8 +1,8 @@
 //! examples/rtt_timing.rs
 //! cargo run --examples rtt-timing
 
-#![deny(unsafe_code)]
-#![deny(warnings)]
+// #![deny(unsafe_code)]
+// #![deny(warnings)]
 #![no_main]
 #![no_std]
 
diff --git a/examples/rtt_rtic_i2c.rs b/examples/rtt_rtic_i2c.rs
index c3bca53..e057177 100644
--- a/examples/rtt_rtic_i2c.rs
+++ b/examples/rtt_rtic_i2c.rs
@@ -6,7 +6,6 @@
 #![no_std]
 
 use cortex_m::{asm::delay, delay};
-// use panic_halt as _;
 use panic_rtt_target as _;
 use rtt_target::{rprintln, rtt_init_print};
 
@@ -21,15 +20,36 @@ use stm32f4xx_hal::{
     stm32::I2C1,
 };
 
+use rtic::cyccnt::{Instant, U32Ext as _};
+
 use app::{
     pmw3389e::{self, Register},
     DwtDelay,
 };
 
-#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)]
+const OFFSET: u32 = 8_000_000 / 10;
+const LOG_OFFSET: u32 = 8_000_000;
+
+#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
 const APP: () = {
-    #[init]
-    fn init(cx: init::Context) {
+    struct Resources {
+        pmw3389: pmw3389e::Pmw3389e<
+            SC18IS602::SH18IS602<
+                I2c<
+                    I2C1,
+                    (
+                        PB8<AlternateOD<stm32f4xx_hal::gpio::AF4>>,
+                        PB9<AlternateOD<stm32f4xx_hal::gpio::AF4>>,
+                    ),
+                >,
+            >,
+            SC18IS602::Error,
+        >,
+        #[init((0, 0))]
+        pos: (i64, i64),
+    }
+    #[init(schedule = [poll, log])]
+    fn init(cx: init::Context) -> init::LateResources {
         rtt_init_print!();
         rprintln!("init");
         let dp = cx.device;
@@ -41,6 +61,7 @@ const APP: () = {
 
         // Initialize (enable) the monotonic timer (CYCCNT)
         cp.DCB.enable_trace();
+        cp.DWT.enable_cycle_counter();
 
         // Set up I2C.
         let gpiob = dp.GPIOB.split();
@@ -52,54 +73,17 @@ const APP: () = {
 
         use embedded_hal::spi::MODE_3;
         use SC18IS602::{Order, Speed, SH18IS602};
-        let mut spi_emu =
-            SH18IS602::new(i2c, 0, Order::MsbFirst, MODE_3, Speed::Speed1843kHz, true);
+        let spi_emu = SH18IS602::new(i2c, 0, Order::MsbFirst, MODE_3, Speed::Speed1843kHz, true);
 
         rprintln!("spi_emu initialized");
 
-        // reset SPI transfer
-        spi_emu.set_low().ok();
-        cortex_m::asm::delay(1_000_000);
-        spi_emu.set_high().ok();
-        cortex_m::asm::delay(1_000_000);
-
-        rprintln!("set to gpio management");
-
-        // try split transaction
-        rprintln!("try split transaction");
-        // the write part
-        spi_emu.set_low().unwrap();
-        let mut req = [0x00];
-        spi_emu.transfer(&mut req).unwrap();
-        rprintln!("id request {:02x?}", req);
-
-        cortex_m::asm::delay(1_000);
-        // the read part
-        let mut req = [00];
-        spi_emu.transfer(&mut req).unwrap();
-        rprintln!("id resp {:02x?}", req);
-
-        spi_emu.set_high().unwrap();
-
-        rprintln!("try split transaction");
-        // the write part
-        spi_emu.set_low().unwrap();
-        let mut req = [0x01];
-        spi_emu.transfer(&mut req).unwrap();
-        rprintln!("version request {:02x?}", req);
-
-        cortex_m::asm::delay(1_000);
-        // the read part
-        let mut req = [00];
-        spi_emu.transfer(&mut req).unwrap();
-        rprintln!("version resp {:02x?}", req);
-
-        spi_emu.set_high().unwrap();
-
         let delay = DwtDelay::new(&mut cp.DWT, clocks);
         let pmw3389 = pmw3389e::Pmw3389e::new(spi_emu, delay).unwrap();
 
         rprintln!("success");
+        cx.schedule.poll(cx.start + OFFSET.cycles()).unwrap();
+        cx.schedule.log(cx.start + LOG_OFFSET.cycles()).unwrap();
+        init::LateResources { pmw3389 }
     }
 
     #[idle]
@@ -109,6 +93,52 @@ const APP: () = {
             continue;
         }
     }
+
+    #[task(priority = 2, resources = [pmw3389, pos], schedule = [poll])]
+    fn poll(cx: poll::Context) {
+        // rprintln!("poll  @ {:?}", Instant::now());
+
+        // static mut X: i64 = 0;
+        // static mut Y: i64 = 0;
+
+        cx.schedule.poll(cx.scheduled + OFFSET.cycles()).unwrap();
+        let pmw3389 = cx.resources.pmw3389;
+
+        pmw3389.write_register(Register::Motion, 0x01).unwrap();
+
+        let motion = pmw3389.read_register(Register::Motion).unwrap();
+        let xl = pmw3389.read_register(Register::DeltaXL).unwrap();
+        let xh = pmw3389.read_register(Register::DeltaXH).unwrap();
+        let yl = pmw3389.read_register(Register::DeltaYL).unwrap();
+        let yh = pmw3389.read_register(Register::DeltaYH).unwrap();
+
+        let x = (xl as u16 + (xh as u16) << 8) as i16;
+        let y = (yl as u16 + (yh as u16) << 8) as i16;
+
+        cx.resources.pos.0 += x as i64;
+        cx.resources.pos.1 += y as i64;
+
+        // let surface = motion & 0x08;
+        // let motion_detect = motion & 0x80;
+
+        // rprintln!(
+        //     "motion {}, surface {}, (x, y) {:?}",
+        //     motion_detect,
+        //     surface,
+        //     (x, y),
+        // );
+    }
+
+    #[task(priority = 1, resources = [pos], schedule = [log])]
+    fn log(mut cx: log::Context) {
+        cx.schedule.log(cx.scheduled + LOG_OFFSET.cycles()).unwrap();
+        cx.resources.pos.lock(|pos| rprintln!("(x, y) {:?}", pos));
+    }
+
+    extern "C" {
+        fn EXTI0();
+        fn EXTI1();
+    }
 };
 
 // SC18IS602
@@ -222,8 +252,12 @@ mod SC18IS602 {
                 | (mode.phase as u8) << 2
                 | speed as u8;
 
+            rprintln!("configuring i2c->spi bridge");
+
             device.i2c.write(addr, &mut [SpiConfigure.id(), cfg]).ok();
 
+            rprintln!("spi bridge configured");
+
             if gpio {
                 device.set_ss0_gpio();
             } else {
@@ -258,8 +292,6 @@ mod SC18IS602 {
         }
     }
 
-    // impl<I2C> Default for SH18IS602<I2C> where I2C: i2c::Write + i2c::Read {}
-
     impl<I2C> Transfer<u8> for SH18IS602<I2C>
     where
         I2C: i2c::Write + i2c::Read,
@@ -290,12 +322,10 @@ mod SC18IS602 {
 
             // A short delay is needed
             // For improved performance use write if result is not needed
-            cortex_m::asm::delay(1000);
+            cortex_m::asm::delay(1_000);
 
             self.i2c.read(self.addr, words).map_err(|_| panic!()).ok();
 
-            // rprintln!("transfer_read {:02x?}", words);
-
             Ok(words)
         }
     }
@@ -310,12 +340,13 @@ mod SC18IS602 {
             if !self.gpio {
                 Err(Error::NotConfigured)
             } else {
-                rprintln!("set low");
+                // rprintln!("set low");
+                //  cortex_m::asm::delay(10_000);
                 self.i2c
                     .write(self.addr, &[Function::GpioWrite.id(), 0x0])
                     .map_err(|_| panic!())
                     .ok();
-                cortex_m::asm::delay(100_000);
+                // cortex_m::asm::delay(20_000);
                 Ok(())
             }
         }
@@ -324,7 +355,8 @@ mod SC18IS602 {
             if !self.gpio {
                 Err(Error::NotConfigured)
             } else {
-                rprintln!("set_high");
+                // rprintln!("set_high");
+                // cortex_m::asm::delay(10_000);
                 self.i2c
                     .write(self.addr, &[Function::GpioWrite.id(), 0x1])
                     .map_err(|_| panic!())
diff --git a/examples/rtt_rtic_usb_mouse.rs b/examples/rtt_rtic_usb_mouse.rs
index 7bb3347..23bfa4e 100644
--- a/examples/rtt_rtic_usb_mouse.rs
+++ b/examples/rtt_rtic_usb_mouse.rs
@@ -324,6 +324,7 @@ fn usb_poll<B: bus::UsbBus>(
     usb_dev: &mut UsbDevice<'static, B>,
     hid: &mut HIDClass<'static, B>,
 ) {
+    // 
     if !usb_dev.poll(&mut [hid]) {
         return;
     }
diff --git a/examples/usb-mouse.rs b/examples/usb-mouse.rs
index 8ce3148..fef110b 100644
--- a/examples/usb-mouse.rs
+++ b/examples/usb-mouse.rs
@@ -9,6 +9,7 @@ use stm32f4xx_hal::{
     gpio::{gpioc::PC13, Input, PullUp},
     otg_fs::{UsbBus, UsbBusType, USB},
     prelude::*,
+    rcc::Clocks,
 };
 use usb_device::{bus::UsbBusAllocator, prelude::*};
 use usbd_hid::{
@@ -37,7 +38,8 @@ const APP: () = {
 
         // Set up the system clock.
         let rcc = ctx.device.RCC.constrain();
-        let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
+        let clocks: Clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze();
+        let hclk = clocks.hclk();
 
         let gpioc = ctx.device.GPIOC.split();
         let btn = gpioc.pc13.into_pull_up_input();
@@ -49,6 +51,7 @@ const APP: () = {
             usb_pwrclk: ctx.device.OTG_FS_PWRCLK,
             pin_dm: gpioa.pa11.into_alternate_af10(),
             pin_dp: gpioa.pa12.into_alternate_af10(),
+            hclk,
         };
         USB_BUS.replace(UsbBus::new(usb, EP_MEMORY));
 
@@ -66,6 +69,12 @@ const APP: () = {
     #[task(binds=OTG_FS, resources = [btn, hid, usb_dev])]
     fn on_usb(ctx: on_usb::Context) {
         static mut COUNTER: u16 = 0;
+        static mut FIRST: bool = true;
+
+        if *FIRST {
+            rprintln!("on_usb");
+            *FIRST = false;
+        }
 
         // destruct the context
         let (btn, usb_dev, hid) = (ctx.resources.btn, ctx.resources.usb_dev, ctx.resources.hid);
@@ -104,7 +113,7 @@ const APP: () = {
     fn idle(_cx: idle::Context) -> ! {
         rprintln!("idle");
         loop {
-            continue;
+            cortex_m::asm::nop();
         }
     }
 };
diff --git a/openocd.gdb b/openocd.gdb
index 1623a86..01b500c 100644
--- a/openocd.gdb
+++ b/openocd.gdb
@@ -24,7 +24,7 @@ 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 itm.txt uart off 16000000
+monitor tpiu config internal itm.txt uart off 48000000
 
 # # OR: make the microcontroller SWO pin output compatible with UART (8N1)
 # # 8000000 must match the core clock frequency
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index 7922596..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#![no_std]
-#![no_main]
-
-// pick a panicking behavior
-use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
-// use panic_abort as _; // requires nightly
-// use panic_itm as _; // logs messages over ITM; requires ITM support
-// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
-
-use cortex_m::asm;
-use cortex_m_rt::entry;
-
-#[entry]
-fn main() -> ! {
-    asm::nop(); // To not have main optimize to abort in release mode, remove when you add code
-
-    loop {
-        // your code goes here
-    }
-}
diff --git a/src/pmw3389.rs b/src/pmw3389.rs
index a978c32..e2823f6 100644
--- a/src/pmw3389.rs
+++ b/src/pmw3389.rs
@@ -6,7 +6,7 @@ use crate::DwtDelay;
 use embedded_hal::blocking::spi::{Transfer, Write};
 use embedded_hal::digital::v2::OutputPin;
 
-use rtt_target::{rprint, rprintln};
+use rtt_target::rprintln;
 
 #[allow(dead_code)]
 #[derive(Clone, Copy)]
@@ -116,23 +116,6 @@ where
 
         rprintln!("reset");
 
-        // shutdown
-
-        // adns_write_reg(Shutdown, 0xb6); // Shutdown first
-        // delay(300);
-
-        // adns_com_begin(); // drop and raise ncs to reset spi port
-        // delayMicroseconds(40);
-        // adns_com_end();
-        // delayMicroseconds(40);
-
-        // pmw3389.write_register(Register::Shutdown, 0xb6)?;
-        // pmw3389.delay.delay_ms(300);
-        // pmw3389.com_begin();
-        // pmw3389.delay.delay_us(40);
-        // pmw3389.com_end();
-        // pmw3389.delay.delay_us(40);
-
         // force reset
         pmw3389.write_register(Register::PowerUpReset, 0x5a)?;
 
@@ -220,7 +203,7 @@ where
     }
 
     /// Read status
-    pub fn read_status(&mut self) -> Result<((i16, i16)), E> {
+    pub fn read_status(&mut self) -> Result<(i16, i16), E> {
         self.com_begin();
 
         self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
@@ -340,7 +323,7 @@ where
         // // set initial CPI resolution
         // // adns_write_reg(Config1, 0x15);
 
-        let cpi: u16 = 16000;
+        let cpi: u16 = 1600;
         self.write_register(Register::ResolutionL, cpi as u8)?;
         self.write_register(Register::ResolutionH, (cpi >> 8) as u8)?;
 
diff --git a/src/pmw3389e.rs b/src/pmw3389e.rs
index 2455b25..6a77599 100644
--- a/src/pmw3389e.rs
+++ b/src/pmw3389e.rs
@@ -146,16 +146,16 @@ where
 
         pmw3389.upload_firmware()?;
 
-        // pmw3389.delay.delay_ms(1000);
+        pmw3389.delay.delay_ms(1000);
 
-        // rprintln!("Optical Chip Initialized");
+        rprintln!("Optical Chip Initialized");
 
-        // // read product id
-        // let id = pmw3389.product_id()?;
-        // rprintln!("product_id 0x{:x}", id);
+        // read product id
+        let id = pmw3389.product_id()?;
+        rprintln!("product_id 0x{:x}", id);
 
-        // let srom_id = pmw3389.read_register(Register::SROMId)?;
-        // rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id);
+        let srom_id = pmw3389.read_register(Register::SROMId)?;
+        rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id);
 
         // // loop {
         // //     pmw3389.write_register(Register::Motion, 0x01)?;
@@ -384,7 +384,7 @@ where
         // // adns_write_reg(Config1, 0x15);
 
         //            self.write_register(Register::ResolutionL, 0x15)?;
-        self.write_register(Register::ResolutionL, 0x5)?;
+        self.write_register(Register::ResolutionL, 0x15)?;
         // self.write_register(Register::ResolutionH, 0x15)?;
         self.write_register(Register::ResolutionH, 0x00)?;
 
-- 
GitLab