diff --git a/firmware/application/apps/ui_mictx.cpp b/firmware/application/apps/ui_mictx.cpp
index fe1502255ca8bb6234618f45515e12dd292304b9..54dca6b01b6618fd92738739abd1c28dba666ef7 100644
--- a/firmware/application/apps/ui_mictx.cpp
+++ b/firmware/application/apps/ui_mictx.cpp
@@ -23,20 +23,16 @@
 #include "ui_mictx.hpp"
 
 #include "baseband_api.hpp"
-#include "hackrf_gpio.hpp"
 #include "audio.hpp"
 #include "tonesets.hpp"
-#include "portapack.hpp"
-#include "pins.hpp"
+#include "portapack_hal.hpp"
 #include "string_format.hpp"
 #include "irq_controls.hpp"
-#include "portapack_shared_memory.hpp"
 
 #include <cstring>
 
 using namespace tonekey;
 using namespace portapack;
-using namespace hackrf::one;
 
 namespace ui {
 
@@ -58,7 +54,7 @@ void MicTXView::configure_baseband() {
 	baseband::set_audiotx_data(
 		sampling_rate / 20,		// Update vu-meter at 20Hz
 		transmitting ? transmitter_model.channel_bandwidth() : 0,
-		mic_gain_x10,
+		mic_gain,
 		TONES_F2D(tone_key_frequency(tone_key_index)),
 		0.2		// 20% mix
 	);
@@ -68,8 +64,11 @@ void MicTXView::set_tx(bool enable) {
 	if (enable) {
 		transmitting = true;
 		configure_baseband();
-		gpio_tx.write(1);
-		led_tx.on();
+		transmitter_model.set_rf_amp(true);
+		transmitter_model.enable();
+		portapack::pin_i2s0_rx_sda.mode(3);		// This is already done in audio::init but gets changed by the CPLD overlay reprogramming
+		//gpio_tx.write(1);
+		//led_tx.on();
 	} else {
 		if (transmitting && rogerbeep_enabled) {
 			baseband::request_beep();
@@ -77,8 +76,10 @@ void MicTXView::set_tx(bool enable) {
 		} else {
 			transmitting = false;
 			configure_baseband();
-			gpio_tx.write(0);
-			led_tx.off();
+			transmitter_model.set_rf_amp(false);
+			transmitter_model.disable();
+			//gpio_tx.write(0);
+			//led_tx.off();
 		}
 	}
 }
@@ -128,8 +129,8 @@ MicTXView::MicTXView(
 	NavigationView& nav
 )
 {
-	pins[P6_2].mode(3);		// Set P6_2 pin function to I2S0_RX_SDA
-		
+	portapack::pin_i2s0_rx_sda.mode(3);		// This is already done in audio::init but gets changed by the CPLD overlay reprogramming
+	
 	baseband::run_image(portapack::spi_flash::image_tag_mic_tx);
 	
 	add_children({
@@ -154,7 +155,7 @@ MicTXView::MicTXView(
 	options_tone_key.set_selected_index(0);
 	
 	options_gain.on_change = [this](size_t, int32_t v) {
-		mic_gain_x10 = v;
+		mic_gain = v / 10.0;
 		configure_baseband();
 	};
 	options_gain.set_selected_index(1);		// x1.0
@@ -206,11 +207,9 @@ MicTXView::MicTXView(
 	};
 	field_va_decay.set_value(1000);
 	
-	// Run baseband as soon as the app starts to get audio levels without transmitting (rf amp off)
 	transmitter_model.set_sampling_rate(sampling_rate);
-	transmitter_model.set_rf_amp(true);
+	transmitter_model.set_rf_amp(false);
 	transmitter_model.set_baseband_bandwidth(1750000);
-	transmitter_model.enable();
 	
 	set_tx(false);
 	
@@ -219,6 +218,7 @@ MicTXView::MicTXView(
 }
 
 MicTXView::~MicTXView() {
+	audio::input::stop();
 	transmitter_model.disable();
 	baseband::shutdown();
 }
diff --git a/firmware/application/apps/ui_mictx.hpp b/firmware/application/apps/ui_mictx.hpp
index 7663d5dc581e820c125f099b63d3684fecd47345..4cebe343c7ca62f7cac5ce476d903f3f7fa83935 100644
--- a/firmware/application/apps/ui_mictx.hpp
+++ b/firmware/application/apps/ui_mictx.hpp
@@ -24,10 +24,8 @@
 #define __UI_MICTX_H__
 
 #include "ui.hpp"
-#include "hal.h"
 #include "ui_widget.hpp"
 #include "ui_navigation.hpp"
-#include "ui_font_fixed_8x16.hpp"
 #include "ui_receiver.hpp"
 #include "transmitter_model.hpp"
 #include "tone_key.hpp"
@@ -73,7 +71,7 @@ private:
 	bool va_enabled { };
 	bool rogerbeep_enabled { };
 	uint32_t tone_key_index { };
-	uint32_t mic_gain_x10 { 10 };
+	float mic_gain { 1.0 };
 	uint32_t audio_level { 0 };
 	uint32_t va_level { };
 	uint32_t attack_ms { };
diff --git a/firmware/application/apps/ui_sd_wipe.cpp b/firmware/application/apps/ui_sd_wipe.cpp
index c8cabd310fd06eff1c4c8bfbd30121c132a2c3fb..295789bd3bd3d47e63e69166b0e34eb425b0d0b5 100644
--- a/firmware/application/apps/ui_sd_wipe.cpp
+++ b/firmware/application/apps/ui_sd_wipe.cpp
@@ -24,6 +24,8 @@
 
 namespace ui {
 
+Thread* WipeSDView::thread { nullptr };
+
 WipeSDView::WipeSDView(NavigationView& nav) : nav_ (nav) {
 	add_children({
 		&text_info,
@@ -33,28 +35,24 @@ WipeSDView::WipeSDView(NavigationView& nav) : nav_ (nav) {
 }
 
 WipeSDView::~WipeSDView() {
-	if (thread) chThdTerminate(thread);
+	if (thread)
+		chThdTerminate(thread);
 }
 
-Thread* WipeSDView::thread { nullptr };
-
 void WipeSDView::focus() {
 	BlockDeviceInfo block_device_info;
 	
 	dummy.focus();
 	
 	if (!confirmed) {
-		nav_.push<ModalMessageView>("Warning !", "Wipe first 32MB of SD card\n(filesystem included) ?", YESCANCEL, [this](bool choice) {
+		nav_.push<ModalMessageView>("Warning !", "Wipe FAT of SD card ?", YESCANCEL, [this](bool choice) {
 				if (choice)
 					confirmed = true;
 			}
 		);
 	} else {
 		if (sdcGetInfo(&SDCD1, &block_device_info) == CH_SUCCESS) {
-			blocks = 32;	// Only erase first 32MB (block_device_info.blk_size * uint64_t(block_device_info.blk_num)) / (1024 * 1024);
-			progress.set_max(blocks);
-			
-			thread = chThdCreateFromHeap(NULL, 2048, NORMALPRIO + 10, WipeSDView::static_fn, this);
+			thread = chThdCreateFromHeap(NULL, 2048, NORMALPRIO, WipeSDView::static_fn, this);
 		} else {
 			nav_.pop();		// Just silently abort for now
 		}
diff --git a/firmware/application/apps/ui_sd_wipe.hpp b/firmware/application/apps/ui_sd_wipe.hpp
index 0564fa79e402f9b095dbcf11fd918b74dbc3559b..6d49b6f4ff2824169de1fe4df3c347e26c93e99c 100644
--- a/firmware/application/apps/ui_sd_wipe.hpp
+++ b/firmware/application/apps/ui_sd_wipe.hpp
@@ -25,6 +25,7 @@
 
 #include "ui_widget.hpp"
 #include "ui_navigation.hpp"
+#include "string_format.hpp"
 #include "ff.h"
 
 #include <cstdint>
@@ -37,13 +38,12 @@ public:
 	~WipeSDView();
 	void focus() override;
 	
-	std::string title() const override { return "SD card wipe"; };	
+	std::string title() const override { return "Wipe FAT"; };	
 
 private:
 	NavigationView& nav_;
 	
 	bool confirmed = false;
-	uint32_t blocks { 0 };
 	static Thread* thread;
 	
 	static msg_t static_fn(void* arg) {
@@ -53,21 +53,24 @@ private:
 	}
 	
 	void run() {
-		uint32_t n, b;
 		lfsr_word_t v = 1;
-		const auto buffer = std::make_unique<std::array<uint8_t, 16384>>();
+		//DIR d;
+		const auto buffer = std::make_unique<std::array<uint8_t, 512>>();
 
-		for (b = 0; b < blocks; b++) {
-			progress.set_value(b);
+		//f_opendir(&d, (TCHAR*)u"");
+
+		uint32_t count = 512;	//sd_card::fs.n_fats * sd_card::fs.fsize;
+		progress.set_max(count);
+
+		for (uint32_t c = 0; c < count; c++) {
+			progress.set_value(c);
 			
 			lfsr_fill(v,
 				reinterpret_cast<lfsr_word_t*>(buffer->data()),
 				sizeof(*buffer.get()) / sizeof(lfsr_word_t));
-			
-			// 1MB
-			for (n = 0; n < 64; n++) {
-				if (disk_write(sd_card::fs.drv, buffer->data(), n + (b * 64), 16384 / 512) != RES_OK) nav_.pop();
-			}
+				
+			if (disk_write(sd_card::fs.drv, buffer->data(), sd_card::fs.fatbase + c, 1) != RES_OK)
+				break;
 		}
 		nav_.pop();
 	}
diff --git a/firmware/application/audio.cpp b/firmware/application/audio.cpp
index 54c9b15425865ad692499e7599e631dc37c8d6c6..cec0979e86c4746c56cbaff907a48dfb601078a9 100644
--- a/firmware/application/audio.cpp
+++ b/firmware/application/audio.cpp
@@ -220,6 +220,7 @@ void init(audio::Codec* const codec) {
 
 void shutdown() {
 	audio_codec->reset();
+	input::stop();
 	output::stop();
 }
 
diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp
index 790948347197180ad7645d002e99e9b2a71c9413..499c98871f30d95c6a0c20ffd52d30372432eb3e 100644
--- a/firmware/application/baseband_api.cpp
+++ b/firmware/application/baseband_api.cpp
@@ -152,12 +152,12 @@ void kill_afsk() {
 	send_message(&message);
 }
 
-void set_audiotx_data(const uint32_t divider, const uint32_t bw, const uint32_t gain_x10,
+void set_audiotx_data(const uint32_t divider, const float deviation_hz, const float audio_gain,
 					const uint32_t tone_key_delta, const float tone_key_mix_weight) {
 	const AudioTXConfigMessage message {
 		divider,
-		bw,
-		gain_x10,
+		deviation_hz,
+		audio_gain,
 		tone_key_delta,
 		tone_key_mix_weight
 	};
diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp
index 01c38a9cc35fd0a361ed0bd685bb0fe44da6b6fb..3f06b4d65ea58bd32b156a8fd1b44e77e5db6959 100644
--- a/firmware/application/baseband_api.hpp
+++ b/firmware/application/baseband_api.hpp
@@ -60,7 +60,7 @@ void set_tones_config(const uint32_t bw, const uint32_t pre_silence, const uint1
 					const bool dual_tone, const bool audio_out);
 void kill_tone();
 void set_sstv_data(const uint8_t vis_code, const uint32_t pixel_duration);
-void set_audiotx_data(const uint32_t divider, const uint32_t bw, const uint32_t gain_x10,
+void set_audiotx_data(const uint32_t divider, const float deviation_hz, const float audio_gain,
 					const uint32_t tone_key_delta, const float tone_key_mix_weight);
 void set_fifo_data(const int8_t * data);
 void set_pitch_rssi(int32_t avg, bool enabled);
diff --git a/firmware/baseband/audio_output.cpp b/firmware/baseband/audio_output.cpp
index e2bc851e510633dd14eeda87b1c00dce09b667a3..42854b7d70115ab0692b0ca9e8697e6de5295059 100644
--- a/firmware/baseband/audio_output.cpp
+++ b/firmware/baseband/audio_output.cpp
@@ -97,7 +97,7 @@ void AudioOutput::on_block(
 }
 
 bool AudioOutput::is_squelched() {
-	return ~audio_present;
+	return !audio_present;
 }
 
 void AudioOutput::fill_audio_buffer(const buffer_f32_t& audio, const bool send_to_fifo) {
diff --git a/firmware/baseband/proc_adsbrx.cpp b/firmware/baseband/proc_adsbrx.cpp
index 9eb2f210e6022f69475ed7d5b356dc1c7617c893..f81ce960d20ba783f280f19b332143ceaa6044e3 100644
--- a/firmware/baseband/proc_adsbrx.cpp
+++ b/firmware/baseband/proc_adsbrx.cpp
@@ -34,8 +34,9 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
 	int8_t re, im;
 	float mag;
 	uint32_t c;
-	uint8_t level, bit, byte;
-	bool confidence, first_in_window, last_in_window;
+	uint8_t level, bit, byte { };
+	//bool confidence;
+	bool first_in_window, last_in_window;
 	
 	// This is called at 2M/2048 = 977Hz
 	// One pulse = 500ns = 2 samples
@@ -62,10 +63,6 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
 				if ((prev_mag < threshold_low) && (mag < threshold_low)) {
 					// Both under window, silence.
 					if (null_count > 3) {
-						//text_debug_b.set("Bits:" + bits.substr(0, 25));
-						//text_debug_c.set("Hex:" + hex_str.substr(0, 26));
-						//text_debug_d.set("DF=" + to_string_dec_uint(frame.get_DF()) + " ICAO=" + to_string_hex(frame.get_ICAO_address(), 6));
-						
 						const ADSBFrameMessage message(frame);
 						shared_memory.application_queue.push(message);
 							
@@ -73,7 +70,7 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
 					} else
 						null_count++;
 						
-					confidence = false;
+					//confidence = false;
 					if (prev_mag > mag)
 						bit = 1;
 					else
@@ -87,13 +84,13 @@ void ADSBRXProcessor::execute(const buffer_c8_t& buffer) {
 					last_in_window = ((mag >= threshold_low) && (mag <= threshold_high));
 					
 					if ((first_in_window && !last_in_window) || (!first_in_window && last_in_window)) {
-						confidence = true;
+						//confidence = true;
 						if (prev_mag > mag)
 							bit = 1;
 						else
 							bit = 0;
 					} else {
-						confidence = false;
+						//confidence = false;
 						if (prev_mag > mag)
 							bit = 1;
 						else
diff --git a/firmware/baseband/proc_adsbrx.hpp b/firmware/baseband/proc_adsbrx.hpp
index e41d0599be57cc042c383f7eeacfbe47d59d9273..afa8508c41480986423fd6d6681eea434a32decc 100644
--- a/firmware/baseband/proc_adsbrx.hpp
+++ b/firmware/baseband/proc_adsbrx.hpp
@@ -50,8 +50,8 @@ private:
 	ADSBFrame frame { };
 	bool configured { false };
 	float prev_mag { 0 };
-	float threshold, threshold_low, threshold_high;
-	size_t null_count, bit_count, sample_count;
+	float threshold { }, threshold_low { }, threshold_high { };
+	size_t null_count { 0 }, bit_count { 0 }, sample_count { 0 };
 	std::pair<float, uint8_t> shifter[ADSB_PREAMBLE_LENGTH];
 	bool decoding { };
 	bool preamble { }, active { };
diff --git a/firmware/baseband/proc_audiotx.cpp b/firmware/baseband/proc_audiotx.cpp
index cf39cfe8696e4ab74b4be0f95105ec737fe3190e..de78d836e5865f1bbbd9eac9ead0c69d33f3ec9a 100644
--- a/firmware/baseband/proc_audiotx.cpp
+++ b/firmware/baseband/proc_audiotx.cpp
@@ -74,7 +74,7 @@ void AudioTXProcessor::on_message(const Message* const msg) {
 	
 	switch(msg->id) {
 		case Message::ID::AudioTXConfig:
-			fm_delta = message.fm_delta * (0xFFFFFFULL / 1536000);
+			fm_delta = message.deviation_hz * (0xFFFFFFULL / baseband_fs);
 			divider = message.divider;
 			as = 0;
 			
diff --git a/firmware/baseband/proc_audiotx.hpp b/firmware/baseband/proc_audiotx.hpp
index d5a6d56e725f25dedd9f47dab52d43d62caeed30..711b63782abf96b6517221420bd24c2153311b66 100644
--- a/firmware/baseband/proc_audiotx.hpp
+++ b/firmware/baseband/proc_audiotx.hpp
@@ -35,9 +35,11 @@ public:
 	void on_message(const Message* const msg) override;
 
 private:
+	static constexpr size_t baseband_fs = 1536000U;
+	
 	bool configured = false;
 	
-	BasebandThread baseband_thread { 1536000, this, NORMALPRIO + 20, baseband::Direction::Transmit };
+	BasebandThread baseband_thread { baseband_fs, this, NORMALPRIO + 20, baseband::Direction::Transmit };
 	
 	int8_t audio_fifo_data[2048] { };
 	FIFO<int8_t> audio_fifo = { audio_fifo_data, 11 };	// 43ms @ 48000Hz
diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp
index 3d7c0610e7c8a02b9abb0434457164edf511b155..0a45df781a36f0c34b7daa0c719c5aa2cb1c0ca3 100644
--- a/firmware/baseband/proc_mictx.cpp
+++ b/firmware/baseband/proc_mictx.cpp
@@ -21,9 +21,9 @@
  */
 
 #include "proc_mictx.hpp"
-#include "tonesets.hpp"
 #include "portapack_shared_memory.hpp"
 #include "sine_table_int8.hpp"
+#include "tonesets.hpp"
 #include "event_m4.hpp"
 
 #include <cstdint>
@@ -40,7 +40,7 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
 		
 		if (!play_beep) {
 			sample = audio_buffer.p[i >> 6] >> 8;			// 1536000 / 64 = 24000
-			sample = (sample * (int32_t)gain_x10) / 10;
+			sample *= audio_gain;
 			
 			power_acc += (sample < 0) ? -sample : sample;	// Power average for UI vu-meter
 			
@@ -60,7 +60,6 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
 				
 				if (beep_index == BEEP_TONES_NB) {
 					configured = false;
-					fm_delta = 0;		// Zero-out the IQ output for the rest of the buffer
 					shared_memory.application_queue.push(txprogress_message);
 				} else {
 					beep_gen.configure(beep_deltas[beep_index], 1.0);
@@ -74,20 +73,20 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){
 		sample = tone_gen.process(sample);
 		
 		// FM
-		if (fm_delta) {
+		if (configured) {
 			delta = sample * fm_delta;
 			
 			phase += delta;
-			sphase = phase + (64 << 24);
+			sphase = phase >> 24;
 
-			re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
-			im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
+			re = (sine_table_i8[(sphase + 64) & 255]);
+			im = (sine_table_i8[sphase]);
 		} else {
 			re = 0;
 			im = 0;
 		}
 		
-		buffer.p[i] = {re, im};
+		buffer.p[i] = { re, im };
 	}
 }
 
@@ -97,8 +96,9 @@ void MicTXProcessor::on_message(const Message* const msg) {
 	
 	switch(msg->id) {
 		case Message::ID::AudioTXConfig:
-			fm_delta = config_message.fm_delta * (0xFFFFFFULL / baseband_fs);
-			gain_x10 = config_message.gain_x10;
+			fm_delta = config_message.deviation_hz * (0xFFFFFFUL / baseband_fs);
+			
+			audio_gain = config_message.audio_gain;
 			divider = config_message.divider;
 			power_acc_count = 0;
 			
diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp
index bb9ac11fcefa5a5906358e1956d79165192ee5a7..588442a65b89e900ea03ed7da2e481e98197ea51 100644
--- a/firmware/baseband/proc_mictx.hpp
+++ b/firmware/baseband/proc_mictx.hpp
@@ -51,7 +51,7 @@ private:
 	ToneGen tone_gen { };
 	ToneGen beep_gen { };
 	
-	uint32_t divider { }, gain_x10 { };
+	uint32_t divider { }, audio_gain { };
 	uint64_t power_acc { 0 };
 	uint32_t power_acc_count { 0 };
 	bool play_beep { false };
diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp
index 575922c39cea04014cf0125a8912e0639ed0bf2c..cf84823483b5072d17943ceaa434403a3f830641 100644
--- a/firmware/common/message.hpp
+++ b/firmware/common/message.hpp
@@ -765,22 +765,22 @@ class AudioTXConfigMessage : public Message {
 public:
 	constexpr AudioTXConfigMessage(
 		const uint32_t divider,
-		const uint32_t fm_delta,
-		const uint32_t gain_x10,
+		const float deviation_hz,
+		const float audio_gain,
 		const uint32_t tone_key_delta,
 		const float tone_key_mix_weight
 	) : Message { ID::AudioTXConfig },
 		divider(divider),
-		fm_delta(fm_delta),
-		gain_x10(gain_x10),
+		deviation_hz(deviation_hz),
+		audio_gain(audio_gain),
 		tone_key_delta(tone_key_delta),
 		tone_key_mix_weight(tone_key_mix_weight)
 	{
 	}
 
 	const uint32_t divider;
-	const uint32_t fm_delta;
-	const uint32_t gain_x10;
+	const float deviation_hz;
+	const float audio_gain;
 	const uint32_t tone_key_delta;
 	const float tone_key_mix_weight;
 };
diff --git a/firmware/common/ui.hpp b/firmware/common/ui.hpp
index bc2031e018d89dafb1d93098ca2733fab636aa5c..7020e7b4c580f4915e56101a740ef57125f990fb 100644
--- a/firmware/common/ui.hpp
+++ b/firmware/common/ui.hpp
@@ -70,14 +70,14 @@ struct Color {
 		return { 255,   0,   0 };
 	}
 	static constexpr Color dark_red() {
-		return { 191,   0,   0 };
+		return { 159,   0,   0 };
 	}
 	
 	static constexpr Color orange() {
 		return { 255, 175,   0 };
 	}
 	static constexpr Color dark_orange() {
-		return { 191,  88,   0 };
+		return { 191,  95,   0 };
 	}
 
 	static constexpr Color yellow() {
@@ -91,7 +91,7 @@ struct Color {
 		return {   0, 255,   0 };
 	}
 	static constexpr Color dark_green() {
-		return {   0, 191,   0 };
+		return {   0, 159,   0 };
 	}
 
 	static constexpr Color blue() {
diff --git a/firmware/portapack-h1-havoc.bin b/firmware/portapack-h1-havoc.bin
index 0e92d7f8eb961417deb9a2bc3774f9621e48a8ec..927e2613b1234b7e402f31dacb52c796cd382f4a 100644
Binary files a/firmware/portapack-h1-havoc.bin and b/firmware/portapack-h1-havoc.bin differ