diff --git a/components/st3m/st3m_captouch.c b/components/st3m/st3m_captouch.c
index 446dd744956416aa5f12396d77947ffa9ed6a2ce..fb90c0a53d226424843471424aa21a3d680d5285 100644
--- a/components/st3m/st3m_captouch.c
+++ b/components/st3m/st3m_captouch.c
@@ -12,6 +12,15 @@
 
 #include <string.h>
 
+// note: at some point there should be a calibration config load/save api
+// that also allows users to set their own threshold. before doing that it
+// would be more useful to start with the existing dynamic calibration data
+// tho :D
+
+#define TOP_PETAL_THRESHOLD 8000
+#define BOTTOM_PETAL_THRESHOLD 12000
+#define PETAL_HYSTERESIS 1000
+
 static const char *TAG = "st3m-captouch";
 
 static SemaphoreHandle_t _mu = NULL;
@@ -20,10 +29,13 @@ static bool _request_calibration = false;
 static bool _calibrating = false;
 
 static inline void _pad_feed(st3m_petal_pad_state_t *pad, uint16_t data,
-                             bool top) {
-    ringbuffer_write(&pad->rb, data);
-    int32_t thres = top ? 8000 : 12000;
-    thres = pad->pressed_prev ? thres - 1000 : thres;  // some hysteresis
+                             uint8_t index) {
+    bool top = (index % 2) == 0;
+    int32_t thres =
+        top ? (TOP_PETAL_THRESHOLD) : (BOTTOM_PETAL_THRESHOLD);
+    thres = pad->pressed_prev ? thres - (PETAL_HYSTERESIS)
+                              : thres;  // some hysteresis
+    pad->raw = data;
     pad->pressed = data > thres;
     pad->pressed_prev = pad->pressed;
 
@@ -39,29 +51,71 @@ static inline void _pad_feed(st3m_petal_pad_state_t *pad, uint16_t data,
     }
 }
 
-static inline void _petal_process(st3m_petal_state_t *petal, bool top) {
+// roughly matches the behavior of the legacy api. someday we should have more
+// meaningful output units.
+#define POS_AMPLITUDE 40000
+#define POS_AMPLITUDE_SHIFT 2
+#define POS_DIV_MIN 1000
+static inline void _petal_process(st3m_petal_state_t *petal, uint8_t index) {
+    bool top = (index % 2) == 0;
+    int32_t thres = top ? (TOP_PETAL_THRESHOLD) : (BOTTOM_PETAL_THRESHOLD);
+    thres =
+        petal->pressed ? thres - (PETAL_HYSTERESIS) : thres;  // some hysteresis
+    int32_t distance;
+    int32_t angle;
     if (top) {
-        petal->pressed =
-            petal->base.pressed || petal->ccw.pressed || petal->cw.pressed;
         petal->pressure =
             (petal->base.pressure + petal->ccw.pressure + petal->cw.pressure) /
             3;
-        int32_t left = ringbuffer_avg(&petal->ccw.rb);
-        int32_t right = ringbuffer_avg(&petal->cw.rb);
-        int32_t base = ringbuffer_avg(&petal->base.rb);
-        petal->pos_distance = (left + right) / 2 - base;
-        petal->pos_angle = right - left;
+        int32_t raw = petal->base.raw + petal->ccw.raw + petal->cw.raw;
+        petal->pressed = raw > thres;
+        int32_t left = petal->ccw.raw;
+        int32_t right = petal->cw.raw;
+        int32_t base = petal->base.raw;
+        int32_t tip = (left + right) >> 1;
+        distance = tip - base;
+        distance *= (POS_AMPLITUDE) >> (POS_AMPLITUDE_SHIFT);
+        distance /= ((tip + base) >> (POS_AMPLITUDE_SHIFT)) + (POS_DIV_MIN);
+        angle = right - left;
+        angle *= (POS_AMPLITUDE) >> (POS_AMPLITUDE_SHIFT);
+        angle /= ((right + left) >> (POS_AMPLITUDE_SHIFT)) + (POS_DIV_MIN);
 #if defined(CONFIG_FLOW3R_HW_GEN_P3)
-        petal->pos_distance = -petal->pos_distance;
+        distance = -pos_distance;
 #endif
     } else {
-        petal->pressed = petal->base.pressed || petal->tip.pressed;
         petal->pressure = (petal->base.pressure + petal->tip.pressure) / 2;
-        int32_t base = ringbuffer_avg(&petal->base.rb);
-        int32_t tip = ringbuffer_avg(&petal->tip.rb);
-        petal->pos_distance = tip - base;
-        petal->pos_angle = 0;
+        int32_t raw = petal->base.raw + petal->tip.raw;
+        if(index == 5) raw *= 2;
+        petal->pressed = raw > thres;
+        int32_t base = petal->base.raw;
+        int32_t tip = petal->tip.raw;
+        if (index == 5) {
+            distance =
+                petal->pressed ? (tip * 5) / 4 - 40000 : 0;  // bad hack pt2
+        } else {
+            distance = tip - base;
+            distance *= (POS_AMPLITUDE) >> (POS_AMPLITUDE_SHIFT);
+            distance /= ((tip + base) >> (POS_AMPLITUDE_SHIFT)) + (POS_DIV_MIN);
+        }
+        angle = 0;
+    }
+    if ((!petal->press_event_new) || petal->fresh) {
+        petal->press_event_new = petal->pressed;
+        petal->fresh = false;
     }
+    // moved filter behind the nonlinearity to get more consistent response
+    // times, also replaced comb with pole for slightly lower lag with similar
+    // noise. maybe switch to higher order in the future for even lower lag but
+    // not sure if that's a good idea. graphical display looks good for now, so
+    // we're leaving fine tuning for when the mapping is a bit more polished.
+    int8_t f_div_pow = 4;
+    // widescreen ratio for better graphics
+    int8_t f_mult_old = 9;
+    int8_t f_mult_new = (1 << f_div_pow) - f_mult_old;
+    petal->pos_distance =
+        (f_mult_old * petal->pos_distance + f_mult_new * distance) >> f_div_pow;
+    petal->pos_angle =
+        (f_mult_old * petal->pos_angle + f_mult_new * angle) >> f_div_pow;
 }
 
 static void _on_data(const flow3r_bsp_captouch_state_t *st) {
@@ -73,17 +127,17 @@ static void _on_data(const flow3r_bsp_captouch_state_t *st) {
         if (top) {
 #if defined(CONFIG_FLOW3R_HW_GEN_P3)
             // Hack for P3 badges, pretend tip is base.
-            _pad_feed(&_state.petals[ix].base, st->petals[ix].tip.raw, true);
+            _pad_feed(&_state.petals[ix].base, st->petals[ix].tip.raw, ix);
 #else
-            _pad_feed(&_state.petals[ix].base, st->petals[ix].base.raw, true);
+            _pad_feed(&_state.petals[ix].base, st->petals[ix].base.raw, ix);
 #endif
-            _pad_feed(&_state.petals[ix].cw, st->petals[ix].cw.raw, true);
-            _pad_feed(&_state.petals[ix].ccw, st->petals[ix].ccw.raw, true);
-            _petal_process(&_state.petals[ix], true);
+            _pad_feed(&_state.petals[ix].cw, st->petals[ix].cw.raw, ix);
+            _pad_feed(&_state.petals[ix].ccw, st->petals[ix].ccw.raw, ix);
+            _petal_process(&_state.petals[ix], ix);
         } else {
-            _pad_feed(&_state.petals[ix].base, st->petals[ix].base.raw, false);
-            _pad_feed(&_state.petals[ix].tip, st->petals[ix].tip.raw, false);
-            _petal_process(&_state.petals[ix], false);
+            _pad_feed(&_state.petals[ix].base, st->petals[ix].base.raw, ix);
+            _pad_feed(&_state.petals[ix].tip, st->petals[ix].tip.raw, ix);
+            _petal_process(&_state.petals[ix], ix);
         }
     }
 
@@ -126,17 +180,18 @@ static void _refresh_petal_events(uint8_t petal_ix) {
         pt->cw.press_event = pt->cw.press_event_new;
         pt->ccw.press_event = pt->ccw.press_event_new;
         pt->base.press_event = pt->base.press_event_new;
-        pt->press_event =
-            pt->base.press_event || pt->ccw.press_event || pt->cw.press_event;
+        pt->press_event = pt->press_event_new;
         pt->cw.fresh = true;
         pt->ccw.fresh = true;
         pt->base.fresh = true;
+        pt->fresh = true;
     } else {
         pt->tip.press_event = pt->tip.press_event_new;
         pt->base.press_event = pt->base.press_event_new;
-        pt->press_event = pt->tip.press_event || pt->base.press_event;
+        pt->press_event = pt->press_event_new;
         pt->tip.fresh = true;
         pt->base.fresh = true;
+        pt->fresh = true;
     }
 }
 
diff --git a/components/st3m/st3m_captouch.h b/components/st3m/st3m_captouch.h
index 170b9c6da1df9a96d6ec98fef89ba5128a1ff332..c2dd1e67cb63479c4b3656b77532119a15a2183c 100644
--- a/components/st3m/st3m_captouch.h
+++ b/components/st3m/st3m_captouch.h
@@ -37,11 +37,12 @@
 //     touch. Top petals have two degrees of freedom, bottom petals have a
 //     single degree of freedom (distance from center).
 
-#include "st3m_ringbuffer.h"
-
 // NOTE: keep the enum definitions below in-sync with flow3r_bsp_captouch.h, as
 // they are converted by numerical value internally.
 
+#include <stdbool.h>
+#include <stdint.h>
+
 // One of the four possible touch points (pads) on a petal. Top petals have
 // base/cw/ccw. Bottom petals have base/tip.
 typedef enum {
@@ -66,8 +67,8 @@ typedef enum {
 
 // State of capacitive touch for a petal's pad.
 typedef struct {
-    // Raw data ringbuffer.
-    st3m_ringbuffer_t rb;
+    // Raw data.
+    uint16_t raw;
     // Whether the pad is currently being touched. Calculated from ringbuffer
     // data.
     bool pressed;
@@ -82,6 +83,8 @@ typedef struct {
 
 // State of capacitive touch for a petal.
 typedef struct {
+    bool press_event_new;
+    bool fresh;
     // Is this a top or bottom petal?
     st3m_petal_kind_t kind;
 
@@ -108,8 +111,11 @@ typedef struct {
     //
     // Arbitrary units around (0, 0).
     // TODO(q3k): normalize and document.
-    float pos_distance;
-    float pos_angle;
+
+    // note moon2: changed these back to int16, no idea what was the motivation
+    // here, there wasn't even a division to warrant it.
+    int32_t pos_distance;
+    int32_t pos_angle;
 } st3m_petal_state_t;
 
 typedef struct {
diff --git a/docs/badge/usage.rst b/docs/badge/usage.rst
index 2225953f88471b45b4bfbf4c7973d0013f3dd5c7..60c3ae7ebdb0fe766272f7fc5c77b78cdf1a4f87 100644
--- a/docs/badge/usage.rst
+++ b/docs/badge/usage.rst
@@ -249,3 +249,18 @@ Reboot
 ^^^^^^
 
 Reboot flow3r.
+
+.. _usage_troubleshooting:
+
+Troubleshooting
+---------------
+
+Captouch doesn't register inputs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+At this point in time the captouch driver is silently calibrated once during every boot. This calibration expects no petals to be pressed, so if you hold flow3r in such a way that a press should be registered during calibration the petal will function poorly during this boot cycle. From experimental data we have found that similar effects are present when flow3r is face-up on a couch or similar surface. This is all in all not ideal, we're planning to add explicit calibration and persistent data storage in a future firmware release. For now we personally find it easiest to boot the badge while holding it from the back with one hand or while it is lying on a non-couchy surface. Apologies for the inconvenience. PS: Fingertips just so curling around the edge of the badge to get a proper grip is usually not an issue.
+
+Captouch of petal 5 seems to be only working in the lower half
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This not a defect but a driver peculiarity and will be fixed in the future.