diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
index 0d10d4fb2c260a217678400333753f7908c90ca0..17dc04f4b2350d0bb2ad673af9e7bb72b294c2c2 100644
--- a/examples/rp/src/bin/usb_serial.rs
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -2,7 +2,7 @@
 #![no_main]
 #![feature(type_alias_impl_trait)]
 
-use defmt::{info, panic};
+use defmt::{info, debug, panic};
 use embassy_executor::Spawner;
 use embassy_time::{Timer, Duration};
 use embassy_rp::pac as pac;
@@ -112,18 +112,47 @@ async fn run<'d, P: Pin>(pin: &mut Flex<'d, P>, syst: &mut SYST) -> Result<(), D
 
     let mut up_x = 1u32;
     let mut down_x = 1u32;
-    let mut up = 0u32;
-    let mut down = 0u32;
+
+    /*
+   |prev    |       |
+   |iter    |       |
+   |        |       |
+            .       |
+          .   .     |                     .
+        .       .   |                   .   .
+      .           . |                 .       .
+    .---------------.---------------.-----------.------ GPIO threshold. Probably isn't really flat.
+                      .           .               .
+                        .       .
+                          .   .
+                            .
+    */
 
     loop {
-        // number of loops per interrupt-free block
+        // number of iterations per interrupt-free block
         const LOOP: usize = 2000;
 
-        // count of cycles to target
-        const T: u32 = 256;
-
-        // BUF iterations from the start (or end?) will be printed
-        const BUF: usize = 16;
+        // Range of cycle counts for overshoot. Upper limit is the pullup/pulldown time
+        // from vcc/gnd to threshold.
+        // A large upper limit will also decrease the number of samples/second (but will
+        // perhaps have more entropy bits/sample?)
+        // Lower limit is necessary because we don't want to hit the threshold immediately
+        // on reading.
+        // Empirical values for a 1uF capacitor.
+        // TODO this could be determined from a calibration step?
+        // const UPRANGE: u32 = 50000;
+        // const LOWRANGE: u32 = 15000;
+        // nice integers
+        const LOW_OVER: u32 = 15000;
+        const HIGH_OVER: u32 = LOW_OVER + 8192;
+
+        // for debug printout
+        // BUF iterations from the start (or end?) will be printed. must be <LOOP
+        const BUF: usize = 64;
+        // for end of buffer
+        // const BUF_START: usize = LOOP - BUF;
+        // for start of buffer
+        const BUF_START: usize = 0;
         let mut ups = [0u32; BUF];
         let mut downs = [0u32; BUF];
         let mut upx = [0u32; BUF];
@@ -135,24 +164,35 @@ async fn run<'d, P: Pin>(pin: &mut Flex<'d, P>, syst: &mut SYST) -> Result<(), D
         // taken for the return to centre value (which is targetting `T`).
         // eg `up_x = step(up_x, down);`
         let step = |prev: u32, meas: u32| {
-            if meas < T {
-                (prev + meas)*2
+            // doubling step.
+            // x[n] = 2*x[n-1] + meas
+            let v = prev*2 + meas;
+
+            // modulo to sensible range
+            if v > UPRANGE {
+                LOWRANGE + (v % (UPRANGE - LOWRANGE))
             } else {
-                prev - prev/4 + meas % T
-            }.max(1)
+                v
+            }
         };
 
         critical_section::with(|_cs| {
 
+            // We alternate between taking the measured down/up values as real output,
+            // and using it to compute the next overshoot.
+            // That prevents leaking "real output" values in the timing of subsequent overshoot
+            // delays.
             for i in 0..LOOP {
                 pin.set_pull(Pull::Up);
                 syst.clear_current();
                 let t1 = SYST::get_current();
                 while pin.is_low() {}
                 let t2 = SYST::get_current();
-                up = t1 - t2;
+                let t_up = t1 - t2;
                 if i % 2 == 0 {
-                    down_x = step(down_x, up);
+                    down_x = step(down_x, t_up);
+                } else {
+                    // TODO: keep `up` as our random output
                 }
                 cortex_m::asm::delay(up_x);
 
@@ -161,21 +201,25 @@ async fn run<'d, P: Pin>(pin: &mut Flex<'d, P>, syst: &mut SYST) -> Result<(), D
                 let t1 = SYST::get_current();
                 while pin.is_high() {}
                 let t2 = SYST::get_current();
-                down = t1 - t2;
+                let t_down = t1 - t2;
                 if i % 2 == 0 {
-                    up_x = step(up_x, down);
+                    up_x = step(up_x, t_down);
+                } else {
+                    // TODO: keep `down` as our random output
                 }
                 cortex_m::asm::delay(down_x);
 
-                if i >= LOOP-BUF {
-                    let n = i - (LOOP-BUF);
-                    ups[n] = up;
+                if (BUF_START..BUF_START+BUF).contains(i) {
+                    let n = i - BUF_START;
+                    ups[n] = t_up;
                     upx[n] = up_x;
-                    downs[n] = down;
+                    downs[n] = t_down;
                     downx[n] = down_x;
                 }
 
             }
+            // put it in idle state so it'll be closer to threshold
+            // on the next critical_section iteration.
             pin.set_pull(Pull::None);
         });