diff --git a/components/flow3r_bsp/flow3r_bsp_ad7147.c b/components/flow3r_bsp/flow3r_bsp_ad7147.c
index a914c27937f4954ebb933e93cc1f227fd5931cff..ae6405f679517e14f8724d15b109af3c218c6c9c 100644
--- a/components/flow3r_bsp/flow3r_bsp_ad7147.c
+++ b/components/flow3r_bsp/flow3r_bsp_ad7147.c
@@ -42,10 +42,16 @@ static esp_err_t _sequence_request(ad7147_chip_t *chip, bool reprogram) {
         int8_t channel = seq[i];
         int8_t offset = chip->channels[channel].afe_offset;
         seq_out.channels[i] = channel;
-        seq_out.pos_afe_offsets[i] = offset;
         // seq_out.idle_to_bias[i] = !(chip->is_bot && (channel < 10)); // jumpy
         // petal 2
         seq_out.idle_to_bias[i] = !chip->is_bot;
+        if (offset < 63) {
+            seq_out.neg_afe_offsets[i] = offset;
+            seq_out.pos_afe_offsets[i] = 0;
+        } else {
+            seq_out.neg_afe_offsets[i] = 63;
+            seq_out.pos_afe_offsets[i] = offset - 63;
+        }
     }
 
     esp_err_t ret;
@@ -119,7 +125,7 @@ static bool _channel_afe_tweak(ad7147_chip_t *chip, size_t cix) {
         // Saturated, can't do anything.
         return false;
     }
-    if (offset >= 63 && diff > 0) {
+    if (offset >= 126 && diff > 0) {
         // Saturated, can't do anything.
         return false;
     }
@@ -128,8 +134,8 @@ static bool _channel_afe_tweak(ad7147_chip_t *chip, size_t cix) {
     if (offset < 0) {
         offset = 0;
     }
-    if (offset > 63) {
-        offset = 63;
+    if (offset > 126) {
+        offset = 126;
     }
 
 #if 0
@@ -151,9 +157,9 @@ static void _on_data(void *user, uint16_t *data, size_t len) {
     if (chip->calibration_cycles > 0) {
         // We're doing a calibration cycle on our channels. Instead of writing
         // the data to channel->cdc, write it to channel->amb_meas.
-        size_t j = chip->calibration_cycles - 1;
-        if (j < _AD7147_CALIB_CYCLES) {
-            for (size_t i = 0; i < len; i++) {
+        int8_t j = chip->calibration_cycles - 1;
+        if (j < _AD7147_CALIB_CYCLES) {  // throw away first few datapoints
+            for (int8_t i = 0; i < len; i++) {
                 chip->channels[_channel_from_readout(chip, i)].amb_meas[j] =
                     data[i];
             }
@@ -186,9 +192,18 @@ static void _on_data(void *user, uint16_t *data, size_t len) {
                 // Calibration measurements done. Calculate average amb data for
                 // each channel.
                 for (size_t i = 0; i < chip->nchannels; i++) {
+#if 1
                     uint16_t avg =
                         _average_calib_measurements(chip->channels[i].amb_meas);
                     chip->channels[i].amb = avg;
+#else
+                    // TODO: compare performance
+                    uint32_t avg = 0;
+                    for (uint8_t j = 0; j < _AD7147_CALIB_CYCLES; j++) {
+                        avg += chip->channels[i].amb_meas[j];
+                    }
+                    chip->channels[i].amb = avg / _AD7147_CALIB_CYCLES;
+#endif
                 }
 
                 char msg[256];
@@ -210,11 +225,11 @@ static void _on_data(void *user, uint16_t *data, size_t len) {
                         rerun |= (1 << i);
                     }
                 }
-
                 if (rerun != 0) {
                     // Rerun calibration again,
                     ESP_LOGI(TAG,
-                             "%s: calibration done, but can do better (%04x). "
+                             "%s: calibration cycle complete, but can do "
+                             "better (%04x). "
                              "Retrying.",
                              chip->name, rerun);
                     chip->calibration_cycles = _AD7147_CALIB_CYCLES + 2;
diff --git a/components/flow3r_bsp/flow3r_bsp_ad7147_hw.c b/components/flow3r_bsp/flow3r_bsp_ad7147_hw.c
index d33be9432067ce6fcadf1921b3aa4491cddafc57..e3ea4fc28b9a540815e99457c653769b83a663ab 100644
--- a/components/flow3r_bsp/flow3r_bsp_ad7147_hw.c
+++ b/components/flow3r_bsp/flow3r_bsp_ad7147_hw.c
@@ -276,6 +276,10 @@ esp_err_t ad7147_hw_init(ad7147_hw_t *device, flow3r_i2c_address addr,
     return _configure_full(device);
 }
 
+static inline uint8_t afe_limit(int8_t offset) {
+    return offset < 0 ? 0 : (offset > 63 ? 63 : offset);
+}
+
 esp_err_t ad7147_hw_configure_stages(ad7147_hw_t *device,
                                      const ad7147_sequence_t *seq,
                                      bool reprogram) {
@@ -291,10 +295,14 @@ esp_err_t ad7147_hw_configure_stages(ad7147_hw_t *device,
     // Configure stages as requested.
     for (size_t i = 0; i < seq->len; i++) {
         int8_t channel = seq->channels[i];
-        int8_t offset = seq->pos_afe_offsets[i];
         device->stage_config[i].cinX_connection_setup[channel] = CIN_CDC_POS;
-        unsigned int pos_offset = offset < 0 ? 0 : (offset > 63 ? 63 : offset);
-        device->stage_config[i].pos_afe_offset = pos_offset;
+
+        device->stage_config[i].pos_afe_offset =
+            afe_limit(seq->pos_afe_offsets[i]);
+        device->stage_config[i].neg_afe_offset =
+            afe_limit(seq->neg_afe_offsets[i]);
+        device->stage_config[i].neg_afe_offset_swap = true;
+        device->stage_config[i].pos_afe_offset_swap = false;
     }
     device->dev_config.sequence_stage_num = seq->len - 1;
     device->dev_config.stageX_complete_int_enable[seq->len - 1] = true;
diff --git a/components/flow3r_bsp/flow3r_bsp_ad7147_hw.h b/components/flow3r_bsp/flow3r_bsp_ad7147_hw.h
index 3eba6417c6c0ea2663d024a743b6119f4d81e00a..224d919f3491dded565e3387885f70d715b39af9 100644
--- a/components/flow3r_bsp/flow3r_bsp_ad7147_hw.h
+++ b/components/flow3r_bsp/flow3r_bsp_ad7147_hw.h
@@ -102,6 +102,7 @@ typedef struct {
     int8_t pos_afe_offsets[12];
     // Whether idle pads are supposed to be connected to bias. Awful hack.
     bool idle_to_bias[12];
+    int8_t neg_afe_offsets[12];
 } ad7147_sequence_t;
 
 // Configure sequencer stages.
diff --git a/components/flow3r_bsp/flow3r_bsp_captouch.c b/components/flow3r_bsp/flow3r_bsp_captouch.c
index 32bcbe16c78ef9bc541183dbcfbd73c9cf86612e..e74379b2320355c963a070e53997106885f75aed 100644
--- a/components/flow3r_bsp/flow3r_bsp_captouch.c
+++ b/components/flow3r_bsp/flow3r_bsp_captouch.c
@@ -401,7 +401,7 @@ static uint16_t amb_limit(int32_t data) {
 }
 
 static uint8_t afe_limit(int32_t data) {
-    return data > 63 ? 63 : (data < 0 ? 0 : data);
+    return data > 126 ? 126 : (data < 0 ? 0 : data);
 }
 
 void flow3r_bsp_captouch_set_calibration_data(int32_t *data) {