diff --git a/Cargo.lock b/Cargo.lock
index 51d5acb9001c80f18706e90c8eabe911ac557a42..3d13b31af886ac8bcf7362dd91a3483930447c51 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9,7 +9,6 @@ dependencies = [
  "byte-slice-cast 1.2.2",
  "embedded-hal 0.2.7",
  "embedded-hal 1.0.0-alpha.10",
- "esp-println",
  "heapless",
 ]
 
diff --git a/README.md b/README.md
index 95f90293e998cb4173f07ebf1e47542acc8d5805..eaddd0f8ba4bd20f6e7c1971d8f2ce67b6fa5c83 100644
--- a/README.md
+++ b/README.md
@@ -17,11 +17,11 @@ This repo provides a pure-rust board support crate / runtime + drivers for the h
 - [x] LEDs
 - [x] Port expanders
 - [x] Input rockers
-- [ ] IMU: possibly working, could not fully test due to broken IMU on my prototype
-- [ ] Captouch: driver partially implemented, however currently broken
+- [ ] IMU: most probably working, could not fully test due to broken IMU on my prototype -> HELP WANTED FOR TESTING!
+- [x] Captouch: driver ~~partially~~ mostly implemented, ~~however currently broken~~, working again, API needs some love though
 - [ ] BadgeLink/BadgeNet: partially implemented, UART/SLIP driver for embassy-net implemented, interop with C/MicroPython Firmware not tested yet, currently no switching implemented
-- [ ] SD-Card: in progress
-- [ ] Barometer: not implemented yet
+- [ ] SD-Card: not implemented yet
+- [ ] Barometer: should come mostly for free with IMU, but could not test that yet
 - [ ] Audio: not implemented yet
 
 If you are interested in implementing or testing one of the missing features, I am always happy for any help. Just open an issue or reach out via matrix (@zdmx:xatellite.space) or e-mail.
diff --git a/ad7147/Cargo.lock b/ad7147/Cargo.lock
index cabe226a2c62aefcd420598e1d2bc7f968440beb..203259657913be61992fb15738f8046486955c81 100644
--- a/ad7147/Cargo.lock
+++ b/ad7147/Cargo.lock
@@ -9,7 +9,6 @@ dependencies = [
  "byte-slice-cast",
  "embedded-hal 0.2.7",
  "embedded-hal 1.0.0-alpha.10",
- "esp-println",
  "heapless",
 ]
 
@@ -62,15 +61,6 @@ version = "1.0.0-alpha.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f65c4d073f5d91c66e629b216818a4c9747eeda0debedf2deda9a0a947e4e93b"
 
-[[package]]
-name = "esp-println"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af6a511d37dba5fb8f01bf5485bc619a1a1959e1aaf666a7597df8fe615a0816"
-dependencies = [
- "critical-section",
-]
-
 [[package]]
 name = "hash32"
 version = "0.2.1"
diff --git a/ad7147/Cargo.toml b/ad7147/Cargo.toml
index 2c2580aab1b184582cea2eb129bef9b68a907daf..29bbf6e2e5cb676b5ce9dc78d82d990a25e60455 100644
--- a/ad7147/Cargo.toml
+++ b/ad7147/Cargo.toml
@@ -2,11 +2,12 @@
 name = "ad7147"
 version = "0.1.0"
 edition = "2021"
+description = "embedded-hal driver for AD7147"
+license = "MIT OR Apache-2.0"
 authors = ["zdmx <hi@zdmx.me>"]
 
 [dependencies]
 byte-slice-cast = { version = "1.2.2", default-features = false }
 embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10" }
 embedded-hal = "0.2.7"
-esp-println = { version = "0.5.0", features = ["esp32s3"] }
 heapless = "0.7.16"
diff --git a/ad7147/src/device.rs b/ad7147/src/device.rs
index e73a612fda5b01e493cf5d613d65cce20e31148f..04a55a32c82d271611a1bb3911356ed5de7a4731 100644
--- a/ad7147/src/device.rs
+++ b/ad7147/src/device.rs
@@ -241,7 +241,7 @@ impl<STATE, const S: usize> ConfigurationBuilder<STATE, S> {
                 stage_low_int_enable: self.configuration.stage_low_int_enable,
                 stage_high_int_enable: self.configuration.stage_high_int_enable,
                 stage_complete_int_enable: self.configuration.stage_complete_int_enable,
-                stages: stages,
+                stages,
             },
             _state: WithStages,
         };
@@ -338,10 +338,10 @@ pub(crate) struct CalibrationEnable {
 impl CalibrationEnable {
     pub(crate) const REGISTER: u16 = 0x001;
 
-    pub(crate) fn to_reg_value(&self) -> u16 {
+    pub(crate) fn to_reg_value(self) -> u16 {
         let mut res = 0u16;
         for (i, val) in self.stages_enable.iter().enumerate() {
-            res |= (val.clone() as u16) << i;
+            res |= (*val as u16) << i;
         }
         res |= (self.avg_fp_skip as u16) << 12;
         res |= (self.avg_lp_skip as u16) << 14;
@@ -385,7 +385,7 @@ pub(crate) struct AmbientCompensationControl {
 impl AmbientCompensationControl {
     pub(crate) const REGISTER: u16 = 0x002;
 
-    pub(crate) fn to_reg_value(&self) -> [u16; 3] {
+    pub(crate) fn to_reg_value(self) -> [u16; 3] {
         let mut res = [0u16; 3];
         res[0] |= self.fast_filter_skip as u16;
         res[0] |= (self.full_power_proximity_disable as u16) << 4;
@@ -439,10 +439,10 @@ pub(crate) struct StageLowIntEnable {
 impl StageLowIntEnable {
     pub(crate) const _REGISTER: u16 = 0x005;
 
-    pub(crate) fn to_reg_value(&self) -> u16 {
+    pub(crate) fn to_reg_value(self) -> u16 {
         let mut res = 0u16;
         for (i, val) in self.stages_enable.iter().enumerate() {
-            res |= (val.clone() as u16) << i;
+            res |= (*val as u16) << i;
         }
         res |= (self.gpio_setup as u16) << 12;
         res |= (self.gpio_input_config as u16) << 14;
@@ -480,10 +480,10 @@ pub(crate) struct StageHighIntEnable {
 impl StageHighIntEnable {
     pub(crate) const _REGISTER: u16 = 0x006;
 
-    pub(crate) fn to_reg_value(&self) -> u16 {
+    pub(crate) fn to_reg_value(self) -> u16 {
         let mut res = 0u16;
         for (i, val) in self.stages_enable.iter().enumerate() {
-            res |= (val.clone() as u16) << i;
+            res |= (*val as u16) << i;
         }
         res
     }
@@ -501,10 +501,10 @@ pub(crate) struct StageCompleteIntEnable {
 impl StageCompleteIntEnable {
     pub(crate) const _REGISTER: u16 = 0x007;
 
-    pub(crate) fn to_reg_value(&self) -> u16 {
+    pub(crate) fn to_reg_value(self) -> u16 {
         let mut res = 0u16;
         for (i, val) in self.stages_enable.iter().enumerate() {
-            res |= (val.clone() as u16) << i;
+            res |= (*val as u16) << i;
         }
         res
     }
diff --git a/ad7147/src/driver.rs b/ad7147/src/driver.rs
index 164d5adf587b053f329d0703d13e6f05d627ebe4..6e55a5b2cea34adc1d1929b735540ececb9f96fc 100644
--- a/ad7147/src/driver.rs
+++ b/ad7147/src/driver.rs
@@ -1,14 +1,9 @@
 use byte_slice_cast::AsByteSlice;
-use embedded_hal_1::delay::DelayUs;
 use embedded_hal::blocking::i2c::{Write, WriteRead};
-use esp_println::println;
-
-use crate::{
-    device::{
-        AmbientCompensationControl, CalibrationEnable, DeviceConfiguration,
-        InternalDeviceConfiguration,
-    },
-    interrupt::InterruptStatus,
+use embedded_hal_1::delay::DelayUs;
+
+use crate::device::{
+    AmbientCompensationControl, CalibrationEnable, DeviceConfiguration, InternalDeviceConfiguration,
 };
 
 const STAGE_CONVERSION_RESULT_REGISTER: u16 = 0x0B;
@@ -54,13 +49,15 @@ where
             data[data_idx..data_idx + 8].copy_from_slice(&stage.to_reg_value());
         }
         //println!("writing to device: addr: {:016b} stage0: {:016b}, stage0: {:016b}", data[0], data[1], data[2]);
-        self.i2c.write(self.address, to_be_array(data).as_byte_slice())?;
+        self.i2c
+            .write(self.address, to_be_array(data).as_byte_slice())?;
 
         let mut data = [0u16; 9];
         data[0] = 0x000;
         data[1..9].copy_from_slice(&configuration.0.to_reg_value_for_init());
         //println!("writing to device: addr: {:016b} pwr_cfg: {:016b}, stage_cal: {:016b}, amb_comp_1: {:016b}, amb_comp_2: {:016b}, amb_comp_3: {:016b}, stage_low_int: {:016b}, stage_high_int: {:016b}, stage_complete_int: {:016b}", data[0], data[1], data[2], data[3], data[4], data[5],  data[6], data[7], data[8]);
-        self.i2c.write(self.address, to_be_array(data).as_byte_slice())?;
+        self.i2c
+            .write(self.address, to_be_array(data).as_byte_slice())?;
 
         delay.delay_ms(100);
 
@@ -68,7 +65,8 @@ where
         data[0] = CalibrationEnable::REGISTER;
         data[1] = configuration.0.calibration_enable.to_reg_value();
         //println!("writing to device: addr: {:016b} stage_cal: {:016b}", data[0], data[1]);
-        self.i2c.write(self.address, to_be_array(data).as_byte_slice())?;
+        self.i2c
+            .write(self.address, to_be_array(data).as_byte_slice())?;
 
         Ok(Ad7147 {
             i2c: self.i2c,
@@ -84,52 +82,61 @@ where
     I2C: WriteRead<Error = E> + Write<Error = E>,
 {
     pub fn read_all_stages(&mut self) -> Result<[u16; S], E> {
-        let mut result = [0u8; 12*2];
-        self.i2c
-            .write_read(self.address, to_be_array([STAGE_CONVERSION_RESULT_REGISTER]).as_byte_slice(), &mut result)?;
+        let mut result = [0u8; 12 * 2];
+        self.i2c.write_read(
+            self.address,
+            to_be_array([STAGE_CONVERSION_RESULT_REGISTER]).as_byte_slice(),
+            &mut result,
+        )?;
         //println!("read from device {:x?}", result);
         Ok(to_le_u16_array(&result))
     }
 
-    pub fn read_interrupt_registers(&mut self) -> Result<InterruptStatus, E> {
+    pub fn read_interrupt_registers(&mut self) -> Result<[u16; 3], E> {
         let mut data = [0u8; 6];
-        self.i2c
-            .write_read(self.address, to_be_array([STAGE_COMPLETED_INTERRUPT_RESULT_REGISTER]).as_byte_slice(), &mut data)?;
+        self.i2c.write_read(
+            self.address,
+            to_be_array([STAGE_COMPLETED_INTERRUPT_RESULT_REGISTER]).as_byte_slice(),
+            &mut data,
+        )?;
         //println!("read from device {:x?}", data);
-        Ok(InterruptStatus::from_registers(to_le_u16_array(&data)))
+        Ok(to_le_u16_array(&data))
     }
 
     pub fn read_device_id(&mut self) -> Result<u16, E> {
         let mut data = [0u8; 2];
-        self.i2c
-            .write_read(self.address, to_be_array([DEVICE_ID_REGISTER]).as_byte_slice(), &mut data)?;
+        self.i2c.write_read(
+            self.address,
+            to_be_array([DEVICE_ID_REGISTER]).as_byte_slice(),
+            &mut data,
+        )?;
         Ok(u16::from_be_bytes(data))
     }
 
     pub fn reset(&mut self) -> Result<(), E> {
-        let mut acc_reg = self.config.ambient_comp_control.clone();
+        let mut acc_reg = self.config.ambient_comp_control;
         acc_reg.conversion_reset = true;
         let mut data = [0u16; 4];
         data[0] = AmbientCompensationControl::REGISTER;
-        data[1..8].copy_from_slice(&acc_reg.to_reg_value());
-        self.i2c.write(self.address, to_be_array(data).as_byte_slice())
+        data[1..4].copy_from_slice(&acc_reg.to_reg_value());
+        self.i2c
+            .write(self.address, to_be_array(data).as_byte_slice())
     }
 }
 
-
-fn to_be_array<const N: usize>(data: [u16;N]) -> [u16;N] {
-    let mut result = [0u16;N];
+fn to_be_array<const N: usize>(data: [u16; N]) -> [u16; N] {
+    let mut result = [0u16; N];
     for (i, word) in data.into_iter().enumerate() {
         result[i] = word.to_be();
     }
     result
 }
 
-fn to_le_u16_array<const N: usize>(data: &[u8]) -> [u16;N] {
-    let mut result = [0u16;N];
+fn to_le_u16_array<const N: usize>(data: &[u8]) -> [u16; N] {
+    let mut result = [0u16; N];
     for i in 0..N {
-        let (int_bytes, _) = data[i*2..].split_at(core::mem::size_of::<u16>());
+        let (int_bytes, _) = data[i * 2..].split_at(core::mem::size_of::<u16>());
         result[i] = u16::from_be_bytes(int_bytes.try_into().unwrap());
     }
     result
-}
\ No newline at end of file
+}
diff --git a/ad7147/src/lib.rs b/ad7147/src/lib.rs
index 1475c9120e08ccb4cf361b9d55b96d8ee46f6cc9..bd8734f1562bbd32a3bad9f07946640a62058076 100644
--- a/ad7147/src/lib.rs
+++ b/ad7147/src/lib.rs
@@ -2,7 +2,6 @@
 
 pub mod device;
 mod driver;
-mod interrupt;
 pub mod stage;
 
 pub use device::DeviceConfiguration;
diff --git a/ad7147/src/stage.rs b/ad7147/src/stage.rs
index e39376037ad0edc332d3f5b50ccaf87a23434204..2dfb74053144f25b7c20c4e739822f00b2906243 100644
--- a/ad7147/src/stage.rs
+++ b/ad7147/src/stage.rs
@@ -109,7 +109,7 @@ pub(crate) struct InternalStageConfiguration {
 }
 
 impl InternalStageConfiguration {
-    pub(crate) fn to_reg_value(&self) -> [u16; 8] {
+    pub(crate) fn to_reg_value(self) -> [u16; 8] {
         let mut res = [0u16; 8];
         res[0..2].copy_from_slice(&self.input_configuration.to_reg_value());
         res[1] |= (self.neg_afe_offset_disable as u16) << 14;
@@ -141,7 +141,7 @@ enum InputMode {
 }
 
 impl InputMode {
-    pub(crate) fn to_reg_value(&self) -> [u16; 2] {
+    pub(crate) fn to_reg_value(self) -> [u16; 2] {
         let mut res = 0u32;
         match self {
             Self::NotConfigured => {
@@ -206,7 +206,7 @@ struct AfeOffsetConfiguration {
 }
 
 impl AfeOffsetConfiguration {
-    pub(crate) fn to_reg_value(&self) -> u16 {
+    pub(crate) fn to_reg_value(self) -> u16 {
         let mut res = 0u16;
         res |= (self.neg_afe_offset & 0b00011111) as u16;
         res |= (self.neg_afe_offset_swap as u16) << 7;
@@ -225,7 +225,7 @@ pub struct StageSensitivity {
 }
 
 impl StageSensitivity {
-    pub(crate) fn to_reg_value(&self) -> u16 {
+    pub(crate) fn to_reg_value(self) -> u16 {
         let mut res = 0u16;
         res |= self.neg_threshold_sensitivity as u16;
         res |= (self.neg_peak_detect as u16) << 4;
diff --git a/src/demo_tasks.rs b/src/demo_tasks.rs
index b0feda9d18230d726644422f6394e408df5749a9..1559a64011bb017c85b0119756e89c67127673bc 100644
--- a/src/demo_tasks.rs
+++ b/src/demo_tasks.rs
@@ -1,6 +1,6 @@
-use crate::flow3r::{display::Display, imu::ImuHandler};
+use crate::flow3r::{captouch::CaptouchHandler, display::Display, imu::ImuHandler};
 use bmi270::AxisData;
-use embassy_futures::select::{select, Either, select3, Either3};
+use embassy_futures::select::{select, select3, select_array, Either, Either3};
 use embassy_time::{Duration, Timer};
 use embedded_graphics::{
     image::Image,
@@ -65,7 +65,7 @@ pub async fn display_demo(display: &mut crate::flow3r::display::Display) {
         {
             Either3::First(_) => move_rectangle(&mut rect, &text, display, &rect_style, -5).await,
             Either3::Second(_) => move_rectangle(&mut rect, &text, display, &rect_style, 5).await,
-            Either3::Third(_) => break
+            Either3::Third(_) => break,
         }
     }
 }
@@ -149,3 +149,126 @@ pub async fn imu_demo(display: &mut Display /*imu: &mut ImuHandler*/) {
         }
     }
 }
+
+pub async fn captouch_demo(display: &mut Display) {
+    let input = InputHandler;
+    let mut inputs = input.split();
+
+    let captouch = CaptouchHandler;
+    let top = captouch.top_petals();
+    let bot = captouch.bottom_petals();
+
+    let circle_top_style = PrimitiveStyle::with_fill(Rgb565::YELLOW);
+    let circle_bot_style = PrimitiveStyle::with_fill(Rgb565::GREEN);
+
+    display
+        .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+        .unwrap();
+    display.flush().await.unwrap();
+
+    loop {
+        match select(inputs.sw2_center.wait_for_press(), async {
+            display
+                .fill_solid(&display.bounding_box(), Rgb565::BLACK)
+                .unwrap();
+            if top.petal0.pressed().await {
+                Circle::with_center(Point::new(120, 20), 20)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(120, 20), 10)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            }
+            if top.petal2.pressed().await {
+                Circle::with_center(Point::new(215, 90), 20)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(215, 90), 10)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            }
+            if top.petal4.pressed().await {
+                Circle::with_center(Point::new(178, 200), 20)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(178, 200), 10)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            }
+            if top.petal6.pressed().await {
+                Circle::with_center(Point::new(61, 200), 20)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(61, 200), 10)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            }
+            if top.petal8.pressed().await {
+                Circle::with_center(Point::new(25, 90), 20)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(25, 90), 10)
+                    .draw_styled(&circle_top_style, display)
+                    .unwrap();
+            }
+
+            if bot.petal1.pressed().await {
+                Circle::with_center(Point::new(178, 39), 20)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(178, 39), 10)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            }
+            if bot.petal3.pressed().await {
+                Circle::with_center(Point::new(215, 150), 20)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(215, 150), 10)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            }
+            if bot.petal5.pressed().await {
+                Circle::with_center(Point::new(120, 220), 20)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(120, 220), 10)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            }
+            if bot.petal7.pressed().await {
+                Circle::with_center(Point::new(24, 150), 20)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(24, 150), 10)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            }
+            if bot.petal9.pressed().await {
+                Circle::with_center(Point::new(61, 29), 20)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            } else {
+                Circle::with_center(Point::new(61, 29), 10)
+                    .draw_styled(&circle_bot_style, display)
+                    .unwrap();
+            }
+            display.flush().await.unwrap();
+            Timer::after(Duration::from_millis(50)).await;
+        })
+        .await
+        {
+            Either::First(_) => break,
+            Either::Second(_) => (),
+        }
+    }
+}
diff --git a/src/flow3r/badgelink/badgelink.rs b/src/flow3r/badgelink/badgelink.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ecf93f782ef7f84f8f09e7e948a819b7618dc07e
--- /dev/null
+++ b/src/flow3r/badgelink/badgelink.rs
@@ -0,0 +1,11 @@
+
+pub fn init_badgelink_io(i2c: I2cProxy<'static, XtensaMutex<I2C<'static, I2C0>>>) {
+    let mut pe1 = port_expander::Max7321::new(shared_i2c.acquire_i2c(), true, true, true, false);
+
+    let mut pe1_io = pe1.split();
+    pe1_io.p1.set_high().unwrap();
+    let _in_r_sw = pe1_io.p3;
+    let _in_t_sw = pe1_io.p4;
+    let _out_r_sw = pe1_io.p5;
+    let _out_t_sw = pe1_io.p6;
+}
\ No newline at end of file
diff --git a/src/flow3r/captouch.rs b/src/flow3r/captouch.rs
index 08d97ef238853a466d6c60ca3e2520aed1cd535a..9a7c977cd4e56698bb010f50547925c33fcc5b3c 100644
--- a/src/flow3r/captouch.rs
+++ b/src/flow3r/captouch.rs
@@ -1,10 +1,15 @@
 use ad7147::{
     device::DecimationFactor,
-    stage::{CapInput, CdcInput, InputConnection},
+    stage::{CapInput, CdcInput, InputConnection, StageSensitivity, ThresholdSensitivity, PeakDetect},
     Ad7147, DeviceConfiguration, Initialized, StageConfiguration,
 };
-use embassy_futures::select::select;
-use embassy_time::{Delay, Duration, Timer};
+use embassy_futures::select::{select, Either};
+use embassy_sync::{
+    blocking_mutex::raw::CriticalSectionRawMutex,
+    mutex::Mutex,
+    pubsub::{PubSubChannel, Subscriber},
+};
+use embassy_time::Delay;
 use embedded_hal_async::digital::Wait;
 use esp_println::println;
 use hal::{
@@ -14,7 +19,197 @@ use hal::{
 };
 use shared_bus::{I2cProxy, XtensaMutex};
 
-pub struct CapTouchHandler;
+static CAPTOUCH_CHANNEL: PubSubChannel<CriticalSectionRawMutex, Flow3rCaptouchEvent, 32, 32, 32> =
+    PubSubChannel::<CriticalSectionRawMutex, Flow3rCaptouchEvent, 32, 32, 32>::new();
+
+pub type CaptouchEventListener =
+    Subscriber<'static, CriticalSectionRawMutex, Flow3rCaptouchEvent, 32, 32, 32>;
+
+static PETALS: Mutex<CriticalSectionRawMutex, [Flow3rPetal; 10]> = Mutex::new([
+    Flow3rPetal::new(0, Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(1, Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(2, Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(3, Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(4, Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(5, Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(6, Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(7, Flow3rCaptouchController::BOTTOM),
+    Flow3rPetal::new(8, Flow3rCaptouchController::TOP),
+    Flow3rPetal::new(9, Flow3rCaptouchController::BOTTOM),
+]);
+
+#[derive(Debug, Clone, Copy)]
+struct Flow3rCaptouchEvent {
+    petals: [Flow3rPetal; 5],
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Flow3rPetal {
+    TOP {
+        number: u8,
+        ccw: Flow3rPetalPart,
+        base: Flow3rPetalPart,
+        cw: Flow3rPetalPart,
+    },
+    BOTTOM {
+        number: u8,
+        base: Flow3rPetalPart,
+        tip: Flow3rPetalPart,
+    },
+}
+
+impl Flow3rPetal {
+    const fn new(num: u8, pos: Flow3rCaptouchController) -> Flow3rPetal {
+        match pos {
+            Flow3rCaptouchController::TOP => Self::TOP {
+                number: num,
+                ccw: Flow3rPetalPart {
+                    pressed: false,
+                    raw: 0,
+                },
+                base: Flow3rPetalPart {
+                    pressed: false,
+                    raw: 0,
+                },
+                cw: Flow3rPetalPart {
+                    pressed: false,
+                    raw: 0,
+                },
+            },
+            Flow3rCaptouchController::BOTTOM => Self::BOTTOM {
+                number: num,
+                base: Flow3rPetalPart {
+                    pressed: false,
+                    raw: 0,
+                },
+                tip: Flow3rPetalPart {
+                    pressed: false,
+                    raw: 0,
+                },
+            },
+        }
+    }
+
+    pub fn pressed(&self) -> bool {
+        match self {
+            Flow3rPetal::TOP {
+                number,
+                ccw,
+                base,
+                cw,
+            } => ccw.pressed | base.pressed | cw.pressed,
+            Flow3rPetal::BOTTOM { number, base, tip } => base.pressed | tip.pressed,
+        }
+    }
+
+    pub fn position(&self) -> i32 {
+        match self {
+            Flow3rPetal::TOP {
+                number,
+                ccw,
+                base,
+                cw,
+            } => (ccw.raw as i32 + cw.raw as i32) / 2 - base.raw as i32,
+            Flow3rPetal::BOTTOM { number, base, tip } => base.raw as i32 + tip.raw as i32 / 2,
+        }
+    }
+
+    pub fn number(&self) -> u8 {
+        match self {
+            Flow3rPetal::TOP {
+                number,
+                ccw,
+                base,
+                cw,
+            } => *number,
+            Flow3rPetal::BOTTOM { number, base, tip } => *number,
+        }
+    }
+
+    fn update(&mut self, pressed: &[bool], values: &[u16]) {
+        match self {
+            Flow3rPetal::TOP {
+                number,
+                ccw,
+                base,
+                cw,
+            } => ccw.pressed = pressed[0],
+            Flow3rPetal::BOTTOM { number, base, tip } => todo!(),
+        }
+    }
+}
+
+#[derive(Debug, Default, Clone, Copy)]
+struct Flow3rPetalPart {
+    pressed: bool,
+    raw: u16,
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Flow3rCaptouchController {
+    BOTTOM,
+    TOP,
+}
+
+pub struct CaptouchHandler;
+
+impl CaptouchHandler {
+    pub fn top_petals(&self) -> TopPetals {
+        TopPetals {
+            petal0: Petal::new(0),
+            petal2: Petal::new(2),
+            petal4: Petal::new(4),
+            petal6: Petal::new(6),
+            petal8: Petal::new(8),
+        }
+    }
+
+    pub fn bottom_petals(&self) -> BottomPetals {
+        BottomPetals {
+            petal1: Petal::new(1),
+            petal3: Petal::new(3),
+            petal5: Petal::new(5),
+            petal7: Petal::new(7),
+            petal9: Petal::new(9),
+        }
+    }
+}
+
+pub struct Petal {
+    number: usize,
+}
+
+impl Petal {
+    fn new(number: usize) -> Self {
+        Self { number }
+    }
+
+    pub async fn pressed(&self) -> bool {
+        let fp = PETALS.lock().await[self.number];
+        fp.pressed()
+    }
+
+    pub async fn position(&self) -> i32 {
+        let fp = PETALS.lock().await[self.number];
+        fp.position()
+    }
+}
+
+pub struct TopPetals {
+    pub petal0: Petal,
+    pub petal2: Petal,
+    pub petal4: Petal,
+    pub petal6: Petal,
+    pub petal8: Petal,
+}
+
+pub struct BottomPetals {
+    pub petal1: Petal,
+    pub petal3: Petal,
+    pub petal5: Petal,
+    pub petal7: Petal,
+    pub petal9: Petal,
+}
 
 fn init_captouch(
     i2c_bot: I2cProxy<'static, XtensaMutex<I2C<'static, I2C0>>>,
@@ -32,102 +227,114 @@ fn init_captouch(
         .stages([
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN0,
                     cdc: CdcInput::Positive,
                 })
+                .sensitivity(StageSensitivity {
+                    neg_threshold_sensitivity: ThresholdSensitivity::Percent90,
+                    neg_peak_detect: PeakDetect::Percent90,
+                    pos_threshold_sensitivity: ThresholdSensitivity::Percent90,
+                    pos_peak_detect:  PeakDetect::Percent90,
+                })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN1,
                     cdc: CdcInput::Positive,
                 })
+                .sensitivity(StageSensitivity {
+                    neg_threshold_sensitivity: ThresholdSensitivity::Percent90,
+                    neg_peak_detect: PeakDetect::Percent90,
+                    pos_threshold_sensitivity: ThresholdSensitivity::Percent90,
+                    pos_peak_detect:  PeakDetect::Percent90,
+                })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN2,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN3,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN4,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN5,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN6,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN7,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN8,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(2)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN9,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(30)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN10,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
@@ -137,6 +344,7 @@ fn init_captouch(
                     cin: CapInput::CIN11,
                     cdc: CdcInput::Positive,
                 })
+                .initial_offset_high(55000)
                 .build(),
         ])
         .build();
@@ -155,7 +363,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(30)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN1,
@@ -164,7 +371,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(28)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN2,
@@ -173,7 +379,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(28)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN3,
@@ -182,7 +387,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(28)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN4,
@@ -191,7 +395,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(28)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN5,
@@ -200,7 +403,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(28)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN6,
@@ -209,7 +411,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(10)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN7,
@@ -218,7 +419,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(20)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN8,
@@ -227,7 +427,6 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
                 .pos_afe_offset(20)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN9,
@@ -236,7 +435,7 @@ fn init_captouch(
                 .build(),
             StageConfiguration::builder()
                 .calibration_enabled(true)
-                .conversion_complete_interrupt_enabled(true)
+                .conversion_complete_interrupt_enabled(false)
                 .pos_afe_offset(8)
                 .add_input_connection(InputConnection {
                     cin: CapInput::CIN10,
@@ -277,43 +476,146 @@ pub async fn captouch_controller(
     println!("captouch top device id: {:016b}", device_id);
     println!("initialized captouch");
     loop {
-        //println!("int pin: {}", cap_b_int.is_input_high());
-        select(cap_bot_int.wait_for_low(), cap_top_int.wait_for_low());
-        let _ = ad7147_bot.read_interrupt_registers().unwrap();
-        let _ = ad7147_top.read_interrupt_registers().unwrap();
-        //println!("ints: {:?}", ints);
-        let measurement = ad7147_bot.read_all_stages().unwrap();
-        /*println!(
-            "{} {} {} {} {} {} {} {} {} {} {} {}",
-            measurement[0],
-            measurement[1],
-            measurement[2],
-            measurement[3],
-            measurement[4],
-            measurement[5],
-            measurement[6],
-            measurement[7],
-            measurement[8],
-            measurement[9],
-            measurement[10],
-            measurement[11]
-        );*/
-        let measurement = ad7147_top.read_all_stages().unwrap();
-        /*println!(
-            "{} {} {} {} {} {} {} {} {} {} {} {}",
-            measurement[0],
-            measurement[1],
-            measurement[2],
-            measurement[3],
-            measurement[4],
-            measurement[5],
-            measurement[6],
-            measurement[7],
-            measurement[8],
-            measurement[9],
-            measurement[10],
-            measurement[11]
-        );*/
-        Timer::after(Duration::from_millis(1000)).await;
+        match select(cap_bot_int.wait_for_low(), cap_top_int.wait_for_low()).await {
+            Either::First(_) => {
+                let interrupts = ad7147_bot.read_interrupt_registers().unwrap();
+                let measurements_bot = ad7147_bot.read_all_stages().unwrap();
+                // println!("pad 0: {}, {}, {}, {}", measurements_bot[0], measurements_bot[1], interrupts[1] & (1 << 0) != 0, interrupts[1] & (1 << 1) != 0);
+                update_petals_bot(interrupts[1], measurements_bot).await;
+            }
+            Either::Second(_) => {
+                let interrupts = ad7147_top.read_interrupt_registers().unwrap();
+                let measurements_top = ad7147_top.read_all_stages().unwrap();
+                update_petals_top(interrupts[1], measurements_top).await;
+            }
+        }
+    }
+}
+
+#[derive(Debug, Copy, Clone)]
+enum PetalPosition {
+    CCW,
+    BASE,
+    CW,
+    TIP,
+}
+
+static PETAL_MAPPING_TOP: [(usize, PetalPosition); 12] = [
+    (0, PetalPosition::BASE),
+    (0, PetalPosition::CCW),
+    (0, PetalPosition::CW),
+    (8, PetalPosition::CW),
+    (8, PetalPosition::CCW),
+    (8, PetalPosition::BASE),
+    (4, PetalPosition::BASE),
+    (4, PetalPosition::CCW),
+    (4, PetalPosition::CW),
+    (6, PetalPosition::CW),
+    (6, PetalPosition::CCW),
+    (6, PetalPosition::BASE),
+];
+
+async fn update_petals_top(interrupts: u16, measurements: [u16; 12]) {
+    let mut petals = PETALS.lock().await;
+    for (i, m) in PETAL_MAPPING_TOP.iter().enumerate() {
+        let pressed = measurements[i] > 50000;
+        match petals[m.0] {
+            Flow3rPetal::TOP {
+                ref mut ccw,
+                ref mut base,
+                ref mut cw,
+                ..
+            } => match m.1 {
+                PetalPosition::CCW => {
+                    ccw.pressed = pressed;
+                    ccw.raw = measurements[i]
+                }
+                PetalPosition::BASE => {
+                    base.pressed = pressed;
+                    base.raw = measurements[i]
+                }
+                PetalPosition::CW => {
+                    cw.pressed = pressed;
+                    cw.raw = measurements[i]
+                }
+                PetalPosition::TIP => panic!("top petal does not have tip"),
+            },
+            Flow3rPetal::BOTTOM {
+                ref mut base,
+                ref mut tip,
+                ..
+            } => match m.1 {
+                PetalPosition::CCW => panic!("bottom petal does not have ccw"),
+                PetalPosition::BASE => {
+                    base.pressed = pressed;
+                    base.raw = measurements[i]
+                }
+                PetalPosition::CW => panic!("bottom petal does not have cw"),
+                PetalPosition::TIP => {
+                    tip.pressed = pressed;
+                    tip.raw = measurements[i]
+                }
+            },
+        }
+    }
+}
+
+static PETAL_MAPPPING_BOT: [(usize, PetalPosition); 12] = [
+    (9, PetalPosition::BASE),
+    (9, PetalPosition::TIP),
+    (7, PetalPosition::BASE),
+    (7, PetalPosition::TIP),
+    (5, PetalPosition::BASE),
+    (5, PetalPosition::TIP),
+    (3, PetalPosition::BASE),
+    (3, PetalPosition::TIP),
+    (1, PetalPosition::BASE),
+    (1, PetalPosition::TIP),
+    (2, PetalPosition::BASE),
+    (2, PetalPosition::CW),
+];
+
+async fn update_petals_bot(interrupts: u16, measurements: [u16; 12]) {
+    let mut petals = PETALS.lock().await;
+    for (i, m) in PETAL_MAPPPING_BOT.iter().enumerate() {
+        let pressed = measurements[i] > 40000;
+        match petals[m.0] {
+            Flow3rPetal::TOP {
+                ref mut ccw,
+                ref mut base,
+                ref mut cw,
+                ..
+            } => match m.1 {
+                PetalPosition::CCW => {
+                    ccw.pressed = pressed;
+                    ccw.raw = measurements[i]
+                }
+                PetalPosition::BASE => {
+                    base.pressed = pressed;
+                    base.raw = measurements[i]
+                }
+                PetalPosition::CW => {
+                    cw.pressed = pressed;
+                    cw.raw = measurements[i]
+                }
+                PetalPosition::TIP => panic!("top petal does not have tip"),
+            },
+            Flow3rPetal::BOTTOM {
+                ref mut base,
+                ref mut tip,
+                ..
+            } => match m.1 {
+                PetalPosition::CCW => panic!("bottom petal does not have ccw"),
+                PetalPosition::BASE => {
+                    base.pressed = pressed;
+                    base.raw = measurements[i]
+                }
+                PetalPosition::CW => panic!("bottom petal does not have cw"),
+                PetalPosition::TIP => {
+                    tip.pressed = pressed;
+                    tip.raw = measurements[i]
+                }
+            },
+        }
     }
 }
diff --git a/src/flow3r/imu.rs b/src/flow3r/imu.rs
index b1ed43a13b6fca9e47462516896c4cd5490c2c08..2b06347ec9c4d2e5cfdd8b64b17aa7d443e541dc 100644
--- a/src/flow3r/imu.rs
+++ b/src/flow3r/imu.rs
@@ -1,5 +1,4 @@
 use bmi270::{interface::I2cInterface, AuxData, AxisData, Bmi270, Error, PwrCtrl};
-use embassy_time::{Duration, Timer};
 use esp_println::println;
 use hal::{i2c::I2C, peripherals::I2C0};
 use shared_bus::{I2cProxy, XtensaMutex};
diff --git a/src/flow3r/input.rs b/src/flow3r/input.rs
index ae557b14860b5eafa4d02ba83975efd217faadff..88553c48fc916ef804857cf4d2dbfd61ccfe7c2c 100644
--- a/src/flow3r/input.rs
+++ b/src/flow3r/input.rs
@@ -3,7 +3,6 @@ use embassy_sync::{
     blocking_mutex::raw::CriticalSectionRawMutex,
     pubsub::{PubSubChannel, Subscriber, WaitResult},
 };
-use embedded_hal_1::digital::ErrorKind;
 use embedded_hal_async::digital::Wait;
 use esp_println::println;
 use hal::{
diff --git a/src/flow3r/mod.rs b/src/flow3r/mod.rs
index 185d2bcb0b1d0b334daffe863e3df0c01d2ec324..691711fefb361ec1f01fe29079f2f20cf1caab4b 100644
--- a/src/flow3r/mod.rs
+++ b/src/flow3r/mod.rs
@@ -1,7 +1,7 @@
 use self::badgelink::BadgeLink;
-use self::captouch::CapTouchHandler;
+use self::captouch::CaptouchHandler;
 use self::display::Display;
-use self::imu::ImuHandler;
+//use self::imu::ImuHandler;
 use self::input::InputHandler;
 use self::leds::Leds;
 
@@ -16,7 +16,7 @@ pub mod ui;
 
 pub struct Flow3r {
     pub badgelink: BadgeLink,
-    pub captouch: CapTouchHandler,
+    pub captouch: CaptouchHandler,
     pub display: Display,
     //pub imu: ImuHandler,
     pub inputs: InputHandler,
@@ -26,7 +26,7 @@ pub struct Flow3r {
 impl Flow3r {
     pub fn new(
         badgelink: BadgeLink,
-        captouch: CapTouchHandler,
+        captouch: CaptouchHandler,
         display: Display,
         //imu: ImuHandler,
         inputs: InputHandler,
diff --git a/src/flow3r/ui/main_menu.rs b/src/flow3r/ui/main_menu.rs
index 9d68791cbf3b64aef3207841c51b455403d5fb50..aefd1b3f479ba4f60749163e1d99071b489ada7d 100644
--- a/src/flow3r/ui/main_menu.rs
+++ b/src/flow3r/ui/main_menu.rs
@@ -6,10 +6,9 @@ use embedded_graphics::{
     prelude::*,
     text::Text,
 };
-use esp_println::println;
 
 use crate::{
-    demo_tasks::{display_demo, imu_demo},
+    demo_tasks::{display_demo, imu_demo, captouch_demo},
     flow3r::{display::Display, input::InputHandler},
 };
 
@@ -108,7 +107,7 @@ async fn start_current_app(app: &str, display: &mut Display) {
     match app {
         "input_test" => display_demo(display).await,
         "imu_test" => imu_demo(display).await,
-        "captouch_test" => {}
+        "captouch_test" => captouch_demo(display).await,
         _ => (),
     }
 }
diff --git a/src/runtime.rs b/src/runtime.rs
index 2794f2126796099b19b1f9b5d4a398c6a927f5b4..456dd2dbfb2390d3fdc56bd8a6ab1708ecfa8f75 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -18,9 +18,9 @@ use static_cell::StaticCell;
 
 use crate::flow3r::{
     badgelink::BadgeLink,
-    captouch::{captouch_controller, CapTouchHandler},
+    captouch::{captouch_controller, CaptouchHandler},
     display::{display_refresh, Display},
-    imu::ImuHandler,
+    //imu::ImuHandler,
     input::{input_controller, InputHandler},
     leds::init_leds,
     Flow3r,
@@ -178,7 +178,7 @@ async fn init_runtime() {
     let badgelink = BadgeLink::new(i2c_busmanager.acquire_i2c());
     //let imu = ImuHandler::new(i2c_busmanager.acquire_i2c());
     let inputs = InputHandler;
-    let captouch = CapTouchHandler;
+    let captouch = CaptouchHandler;
     let leds = init_leds(pulse.channel0, io.pins.gpio14);
 
     let flow3r = Flow3r::new(badgelink, captouch, display, inputs, leds);