diff --git a/src/configuration.h b/src/configuration.h
index 53ae30d51d2..ee754f3227b 100644
--- a/src/configuration.h
+++ b/src/configuration.h
@@ -163,6 +163,10 @@ along with this program. If not, see .
#define TX_GAIN_LORA 0
#endif
+#ifndef HAS_LORA_FEM
+#define HAS_LORA_FEM 0
+#endif
+
// -----------------------------------------------------------------------------
// Feature toggles
// -----------------------------------------------------------------------------
diff --git a/src/mesh/LoRaFEMInterface.cpp b/src/mesh/LoRaFEMInterface.cpp
new file mode 100644
index 00000000000..a1b56320e20
--- /dev/null
+++ b/src/mesh/LoRaFEMInterface.cpp
@@ -0,0 +1,193 @@
+#if HAS_LORA_FEM
+#include "LoRaFEMInterface.h"
+
+#if defined(ARCH_ESP32)
+#include
+#include
+#endif
+
+LoRaFEMInterface loraFEMInterface;
+void LoRaFEMInterface::init(void)
+{
+ setLnaCanControl(false); // Default is uncontrollable
+#ifdef HELTEC_V4
+ pinMode(LORA_PA_POWER, OUTPUT);
+ digitalWrite(LORA_PA_POWER, HIGH);
+ rtc_gpio_hold_dis((gpio_num_t)LORA_PA_POWER);
+ delay(1);
+ rtc_gpio_hold_dis((gpio_num_t)LORA_KCT8103L_PA_CSD);
+ pinMode(LORA_KCT8103L_PA_CSD, INPUT); // detect which FEM is used
+ delay(1);
+ if (digitalRead(LORA_KCT8103L_PA_CSD) == HIGH) {
+ // FEM is KCT8103L
+ fem_type = KCT8103L_PA;
+ rtc_gpio_hold_dis((gpio_num_t)LORA_KCT8103L_PA_CTX);
+ pinMode(LORA_KCT8103L_PA_CSD, OUTPUT);
+ digitalWrite(LORA_KCT8103L_PA_CSD, HIGH);
+ pinMode(LORA_KCT8103L_PA_CTX, OUTPUT);
+ digitalWrite(LORA_KCT8103L_PA_CTX, HIGH);
+ setLnaCanControl(true);
+ } else if (digitalRead(LORA_KCT8103L_PA_CSD) == LOW) {
+ // FEM is GC1109
+ fem_type = GC1109_PA;
+ // LORA_GC1109_PA_EN and LORA_KCT8103L_PA_CSD are the same pin and do not need to be repeatedly turned off and held.
+ // rtc_gpio_hold_dis((gpio_num_t)LORA_GC1109_PA_EN);
+ pinMode(LORA_GC1109_PA_EN, OUTPUT);
+ digitalWrite(LORA_GC1109_PA_EN, HIGH);
+ pinMode(LORA_GC1109_PA_TX_EN, OUTPUT);
+ digitalWrite(LORA_GC1109_PA_TX_EN, LOW);
+ } else {
+ fem_type = OTHER_FEM_TYPES;
+ }
+#elif defined(USE_GC1109_PA)
+ fem_type = GC1109_PA;
+#if defined(ARCH_ESP32)
+ rtc_gpio_hold_dis((gpio_num_t)LORA_PA_POWER);
+ rtc_gpio_hold_dis((gpio_num_t)LORA_GC1109_PA_EN);
+ rtc_gpio_hold_dis((gpio_num_t)LORA_GC1109_PA_TX_EN);
+#endif
+ pinMode(LORA_PA_POWER, OUTPUT);
+ digitalWrite(LORA_PA_POWER, HIGH);
+ delay(1);
+ pinMode(LORA_GC1109_PA_EN, OUTPUT);
+ digitalWrite(LORA_GC1109_PA_EN, HIGH);
+ pinMode(LORA_GC1109_PA_TX_EN, OUTPUT);
+ digitalWrite(LORA_GC1109_PA_TX_EN, LOW);
+#endif
+}
+
+void LoRaFEMInterface::setSleepModeEnable(void)
+{
+#ifdef HELTEC_V4
+ if (fem_type == GC1109_PA) {
+ /*
+ * Do not switch the power on and off frequently.
+ * After turning off LORA_GC1109_PA_EN, the power consumption has dropped to the uA level.
+ */
+ digitalWrite(LORA_GC1109_PA_EN, LOW);
+ digitalWrite(LORA_GC1109_PA_TX_EN, LOW);
+ } else if (fem_type == KCT8103L_PA) {
+ // shutdown the PA
+ digitalWrite(LORA_KCT8103L_PA_CSD, LOW);
+ }
+#elif defined(USE_GC1109_PA)
+ digitalWrite(LORA_GC1109_PA_EN, LOW);
+ digitalWrite(LORA_GC1109_PA_TX_EN, LOW);
+#endif
+}
+
+void LoRaFEMInterface::setTxModeEnable(void)
+{
+#ifdef HELTEC_V4
+ if (fem_type == GC1109_PA) {
+ digitalWrite(LORA_GC1109_PA_EN, HIGH); // CSD=1: Chip enabled
+ digitalWrite(LORA_GC1109_PA_TX_EN, HIGH); // CPS: 1=full PA, 0=bypass (for RX, CPS is don't care)
+ } else if (fem_type == KCT8103L_PA) {
+ digitalWrite(LORA_KCT8103L_PA_CSD, HIGH);
+ digitalWrite(LORA_KCT8103L_PA_CTX, HIGH);
+ }
+#elif defined(USE_GC1109_PA)
+ digitalWrite(LORA_GC1109_PA_EN, HIGH); // CSD=1: Chip enabled
+ digitalWrite(LORA_GC1109_PA_TX_EN, HIGH); // CPS: 1=full PA, 0=bypass (for RX, CPS is don't care)
+#endif
+}
+
+void LoRaFEMInterface::setRxModeEnable(void)
+{
+#ifdef HELTEC_V4
+ if (fem_type == GC1109_PA) {
+ digitalWrite(LORA_GC1109_PA_EN, HIGH); // CSD=1: Chip enabled
+ digitalWrite(LORA_GC1109_PA_TX_EN, LOW);
+ } else if (fem_type == KCT8103L_PA) {
+ digitalWrite(LORA_KCT8103L_PA_CSD, HIGH);
+ if (lna_enabled) {
+ digitalWrite(LORA_KCT8103L_PA_CTX, LOW);
+ } else {
+ digitalWrite(LORA_KCT8103L_PA_CTX, HIGH);
+ }
+ }
+#elif defined(USE_GC1109_PA)
+ digitalWrite(LORA_GC1109_PA_EN, HIGH); // CSD=1: Chip enabled
+ digitalWrite(LORA_GC1109_PA_TX_EN, LOW);
+#endif
+}
+
+void LoRaFEMInterface::setRxModeEnableWhenMCUSleep(void)
+{
+
+#ifdef HELTEC_V4
+ // Keep GC1109 FEM powered during deep sleep so LNA remains active for RX wake.
+ // Set PA_POWER and PA_EN HIGH (overrides SX126xInterface::sleep() shutdown),
+ // then latch with RTC hold so the state survives deep sleep.
+ digitalWrite(LORA_PA_POWER, HIGH);
+ rtc_gpio_hold_en((gpio_num_t)LORA_PA_POWER);
+ if (fem_type == GC1109_PA) {
+ digitalWrite(LORA_GC1109_PA_EN, HIGH);
+ rtc_gpio_hold_en((gpio_num_t)LORA_GC1109_PA_EN);
+ gpio_pulldown_en((gpio_num_t)LORA_GC1109_PA_TX_EN);
+ } else if (fem_type == KCT8103L_PA) {
+ digitalWrite(LORA_KCT8103L_PA_CSD, HIGH);
+ rtc_gpio_hold_en((gpio_num_t)LORA_KCT8103L_PA_CSD);
+ if (lna_enabled) {
+ digitalWrite(LORA_KCT8103L_PA_CTX, LOW);
+ } else {
+ digitalWrite(LORA_KCT8103L_PA_CTX, HIGH);
+ }
+ rtc_gpio_hold_en((gpio_num_t)LORA_KCT8103L_PA_CTX);
+ }
+#elif defined(USE_GC1109_PA)
+ digitalWrite(LORA_PA_POWER, HIGH);
+ digitalWrite(LORA_GC1109_PA_EN, HIGH);
+#if defined(ARCH_ESP32)
+ rtc_gpio_hold_en((gpio_num_t)LORA_PA_POWER);
+ rtc_gpio_hold_en((gpio_num_t)LORA_GC1109_PA_EN);
+ gpio_pulldown_en((gpio_num_t)LORA_GC1109_PA_TX_EN);
+#endif
+#endif
+}
+
+void LoRaFEMInterface::setLNAEnable(bool enabled)
+{
+ lna_enabled = enabled;
+}
+
+int8_t LoRaFEMInterface::powerConversion(int8_t loraOutputPower)
+{
+#ifdef HELTEC_V4
+ const uint16_t gc1109_tx_gain[] = {11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7};
+ const uint16_t kct8103l_tx_gain[] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7};
+ const uint16_t *tx_gain;
+ uint16_t tx_gain_num;
+ if (fem_type == GC1109_PA) {
+ tx_gain = gc1109_tx_gain;
+ tx_gain_num = sizeof(gc1109_tx_gain) / sizeof(gc1109_tx_gain[0]);
+ } else if (fem_type == KCT8103L_PA) {
+ tx_gain = kct8103l_tx_gain;
+ tx_gain_num = sizeof(kct8103l_tx_gain) / sizeof(kct8103l_tx_gain[0]);
+ } else {
+ return loraOutputPower;
+ }
+#else
+#ifdef ARCH_PORTDUINO
+ size_t num_pa_points = portduino_config.num_pa_points;
+ const uint16_t *tx_gain = portduino_config.tx_gain_lora;
+ uint16_t tx_gain_num = num_pa_points;
+#else
+ size_t num_pa_points = NUM_PA_POINTS;
+ const uint16_t tx_gain[NUM_PA_POINTS] = {TX_GAIN_LORA};
+ uint16_t tx_gain_num = NUM_PA_POINTS;
+#endif
+#endif
+ for (int radio_dbm = 0; radio_dbm < tx_gain_num; radio_dbm++) {
+ if (((radio_dbm + tx_gain[radio_dbm]) > loraOutputPower) ||
+ ((radio_dbm == (tx_gain_num - 1)) && ((radio_dbm + tx_gain[radio_dbm]) <= loraOutputPower))) {
+ // we've exceeded the power limit, or hit the max we can do
+ LOG_INFO("Requested Tx power: %d dBm; Device LoRa Tx gain: %d dB", loraOutputPower, tx_gain[radio_dbm]);
+ loraOutputPower -= tx_gain[radio_dbm];
+ break;
+ }
+ }
+ return loraOutputPower;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/LoRaFEMInterface.h b/src/mesh/LoRaFEMInterface.h
new file mode 100644
index 00000000000..0a7c810ef8b
--- /dev/null
+++ b/src/mesh/LoRaFEMInterface.h
@@ -0,0 +1,30 @@
+#pragma once
+#if HAS_LORA_FEM
+#include "configuration.h"
+#include
+
+typedef enum { GC1109_PA, KCT8103L_PA, OTHER_FEM_TYPES } LoRaFEMType;
+
+class LoRaFEMInterface
+{
+ public:
+ LoRaFEMInterface() {}
+ virtual ~LoRaFEMInterface() {}
+ void init(void);
+ void setSleepModeEnable(void);
+ void setTxModeEnable(void);
+ void setRxModeEnable(void);
+ void setRxModeEnableWhenMCUSleep(void);
+ void setLNAEnable(bool enabled);
+ int8_t powerConversion(int8_t loraOutputPower);
+ bool isLnaCanControl(void) { return lna_can_control; }
+ void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
+
+ private:
+ LoRaFEMType fem_type;
+ bool lna_enabled = false;
+ bool lna_can_control = false;
+};
+extern LoRaFEMInterface loraFEMInterface;
+
+#endif
\ No newline at end of file
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index 2a481ac2537..4defd00ed4c 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -915,6 +915,12 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
power = maxPower;
}
+#if HAS_LORA_FEM
+ if (!devicestate.owner.is_licensed) {
+ power = loraFEMInterface.powerConversion(power);
+ }
+#else
+// todo:All entries containing "lora fem" are grouped together above.
#ifdef ARCH_PORTDUINO
size_t num_pa_points = portduino_config.num_pa_points;
const uint16_t *tx_gain = portduino_config.tx_gain_lora;
@@ -940,7 +946,7 @@ void RadioInterface::limitPower(int8_t loraMaxPower)
}
}
}
-
+#endif
if (power > loraMaxPower) // Clamp power to maximum defined level
power = loraMaxPower;
diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h
index 1fe3dd7b0f5..05825dce1c9 100644
--- a/src/mesh/RadioInterface.h
+++ b/src/mesh/RadioInterface.h
@@ -8,6 +8,10 @@
#include "error.h"
#include
+#if HAS_LORA_FEM
+#include "LoRaFEMInterface.h"
+#endif
+
// Forward decl to avoid a direct include of generated config headers / full LoRaConfig definition in this widely-included file.
typedef struct _meshtastic_Config_LoRaConfig meshtastic_Config_LoRaConfig;
diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp
index 553cd4ee5bf..5c9ab35979c 100644
--- a/src/mesh/SX126xInterface.cpp
+++ b/src/mesh/SX126xInterface.cpp
@@ -6,7 +6,7 @@
#ifdef ARCH_PORTDUINO
#include "PortduinoGlue.h"
#endif
-#if defined(USE_GC1109_PA) && defined(ARCH_ESP32)
+#if defined(ARCH_ESP32)
#include
#include
#endif
@@ -56,41 +56,8 @@ template bool SX126xInterface::init()
pinMode(SX126X_POWER_EN, OUTPUT);
#endif
-#if defined(USE_GC1109_PA)
- // GC1109 FEM chip initialization
- // See variant.h for full pin mapping and control logic documentation
- //
- // On deep sleep wake, PA_POWER and PA_EN are held HIGH by RTC latch (set in
- // enableLoraInterrupt). We configure GPIO registers before releasing the hold
- // so the pad transitions atomically from held-HIGH to register-HIGH with no
- // power glitch. On cold boot the hold_dis is a harmless no-op.
-
- // VFEM_Ctrl (LORA_PA_POWER): Power enable for GC1109 LDO (always on)
- pinMode(LORA_PA_POWER, OUTPUT);
- digitalWrite(LORA_PA_POWER, HIGH);
- rtc_gpio_hold_dis((gpio_num_t)LORA_PA_POWER);
-
- // TLV75733P LDO has ~550us startup time (datasheet tSTR). On cold boot, wait
- // for VBAT to stabilise before driving CSD/CPS, per GC1109 requirement:
- // "VBAT must be prior to CSD/CPS/CTX for the power on sequence"
- // On deep sleep wake the LDO was held on via RTC latch, so no delay needed.
-#if defined(ARCH_ESP32)
- if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_UNDEFINED) {
- delayMicroseconds(1000);
- }
-#else
- delayMicroseconds(1000);
-#endif
-
- // CSD (LORA_PA_EN): Chip enable - must be HIGH to enable GC1109 for both RX and TX
- pinMode(LORA_PA_EN, OUTPUT);
- digitalWrite(LORA_PA_EN, HIGH);
- rtc_gpio_hold_dis((gpio_num_t)LORA_PA_EN);
-
- // CPS (LORA_PA_TX_EN): PA mode select - HIGH enables full PA during TX, LOW for RX (don't care)
- // Note: TX/RX path switching (CTX) is handled by DIO2 via SX126X_DIO2_AS_RF_SWITCH
- pinMode(LORA_PA_TX_EN, OUTPUT);
- digitalWrite(LORA_PA_TX_EN, LOW); // Start in RX-ready state
+#if HAS_LORA_FEM
+ loraFEMInterface.init();
#endif
#ifdef RF95_FAN_EN
@@ -419,15 +386,10 @@ template bool SX126xInterface::sleep()
digitalWrite(SX126X_POWER_EN, LOW);
#endif
-#if defined(USE_GC1109_PA)
- /*
- * Do not switch the power on and off frequently.
- * After turning off LORA_PA_EN, the power consumption has dropped to the uA level.
- * // digitalWrite(LORA_PA_POWER, LOW);
- */
- digitalWrite(LORA_PA_EN, LOW);
- digitalWrite(LORA_PA_TX_EN, LOW);
+#if HAS_LORA_FEM
+ loraFEMInterface.setSleepModeEnable();
#endif
+
return true;
}
@@ -489,10 +451,12 @@ template void SX126xInterface::resetAGC()
/** Control PA mode for GC1109 FEM - CPS pin selects full PA (txon=true) or bypass mode (txon=false) */
template void SX126xInterface::setTransmitEnable(bool txon)
{
-#if defined(USE_GC1109_PA)
- digitalWrite(LORA_PA_POWER, HIGH); // Ensure LDO is on
- digitalWrite(LORA_PA_EN, HIGH); // CSD=1: Chip enabled
- digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0); // CPS: 1=full PA, 0=bypass (for RX, CPS is don't care)
+#if HAS_LORA_FEM
+ if (txon) {
+ loraFEMInterface.setTxModeEnable();
+ } else {
+ loraFEMInterface.setRxModeEnable();
+ }
#endif
}
diff --git a/src/sleep.cpp b/src/sleep.cpp
index 8470e9273c7..8603603eaf5 100644
--- a/src/sleep.cpp
+++ b/src/sleep.cpp
@@ -163,13 +163,6 @@ void initDeepSleep()
if (wakeCause != ESP_SLEEP_WAKEUP_UNDEFINED) {
LOG_DEBUG("Disable any holds on RTC IO pads");
for (uint8_t i = 0; i <= GPIO_NUM_MAX; i++) {
-#if defined(USE_GC1109_PA)
- // Skip GC1109 FEM power pins - they are held HIGH during deep sleep to keep
- // the LNA active for RX wake. Released later in SX126xInterface::init() after
- // GPIO registers are set HIGH first, avoiding a power glitch.
- if (i == LORA_PA_POWER || i == LORA_PA_EN)
- continue;
-#endif
if (rtc_gpio_is_valid_gpio((gpio_num_t)i))
rtc_gpio_hold_dis((gpio_num_t)i);
@@ -567,15 +560,8 @@ void enableLoraInterrupt()
gpio_pullup_en((gpio_num_t)LORA_CS);
#endif
-#if defined(USE_GC1109_PA)
- // Keep GC1109 FEM powered during deep sleep so LNA remains active for RX wake.
- // Set PA_POWER and PA_EN HIGH (overrides SX126xInterface::sleep() shutdown),
- // then latch with RTC hold so the state survives deep sleep.
- digitalWrite(LORA_PA_POWER, HIGH);
- rtc_gpio_hold_en((gpio_num_t)LORA_PA_POWER);
- digitalWrite(LORA_PA_EN, HIGH);
- rtc_gpio_hold_en((gpio_num_t)LORA_PA_EN);
- gpio_pulldown_en((gpio_num_t)LORA_PA_TX_EN);
+#if HAS_LORA_FEM
+ loraFEMInterface.setRxModeEnableWhenMCUSleep();
#endif
LOG_INFO("setup LORA_DIO1 (GPIO%02d) with wakeup by gpio interrupt", LORA_DIO1);
diff --git a/variants/esp32s3/heltec_v4/platformio.ini b/variants/esp32s3/heltec_v4/platformio.ini
index 72c53ded095..9591f2dc1bc 100644
--- a/variants/esp32s3/heltec_v4/platformio.ini
+++ b/variants/esp32s3/heltec_v4/platformio.ini
@@ -6,6 +6,7 @@ board_build.partitions = default_16MB.csv
build_flags =
${esp32s3_base.build_flags}
-D HELTEC_V4
+ -D HAS_LORA_FEM=1
-I variants/esp32s3/heltec_v4
diff --git a/variants/esp32s3/heltec_v4/variant.h b/variants/esp32s3/heltec_v4/variant.h
index 1c1168d9459..8843f75c9fb 100644
--- a/variants/esp32s3/heltec_v4/variant.h
+++ b/variants/esp32s3/heltec_v4/variant.h
@@ -30,8 +30,8 @@
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
// ---- GC1109 RF FRONT END CONFIGURATION ----
-// The Heltec V4 uses a GC1109 FEM chip with integrated PA and LNA
-// RF path: SX1262 -> GC1109 PA -> Pi attenuator -> Antenna
+// The Heltec V4.2 uses a GC1109 FEM chip with integrated PA and LNA
+// RF path: SX1262 -> Pi attenuator -> GC1109 PA -> Antenna
// Measured net TX gain (non-linear due to PA compression):
// +11dB at 0-15dBm input (e.g., 10dBm in -> 21dBm out)
// +10dB at 16-17dBm input
@@ -47,15 +47,31 @@
// CSD (pin 4) -> GPIO2: Chip enable (HIGH=on, LOW=shutdown)
// CPS (pin 5) -> GPIO46: PA mode select (HIGH=full PA, LOW=bypass)
// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7
-#define USE_GC1109_PA
-#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable
-#define LORA_PA_EN 2 // CSD - GC1109 chip enable (HIGH=on)
-#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass)
-
// GC1109 FEM: TX/RX path switching is handled by DIO2 -> CTX pin (via SX126X_DIO2_AS_RF_SWITCH)
-// GPIO46 is CPS (PA mode), not TX control - setTransmitEnable() handles it in SX126xInterface.cpp
// Do NOT use SX126X_TXEN/RXEN as that would cause double-control of GPIO46
+#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 and KCT8103L LDO power enable
+#define LORA_GC1109_PA_EN 2 // CSD - GC1109 chip enable (HIGH=on)
+#define LORA_GC1109_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass)
+
+// ---- KCT8103L RF FRONT END CONFIGURATION ----
+// The Heltec V4.3 uses a KCT8103L FEM chip with integrated PA and LNA
+// RF path: SX1262 -> Pi attenuator -> KCT8103L PA -> Antenna
+// Control logic (from KCT8103L datasheet):
+// Transmit PA: CSD=1, CTX=1, CPS=1
+// Receive LNA: CSD=1, CTX=0, CPS=X (21dB gain, 1.9dB NF)
+// Receive bypass: CSD=1, CTX=1, CPS=0
+// Shutdown: CSD=0, CTX=X, CPS=X
+// Pin mapping:
+// CPS (pin 5) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH)
+// CSD (pin 4) -> GPIO2: Chip enable (HIGH=on, LOW=shutdown)
+// CTX (pin 6) -> GPIO5: Switch between Receive LNA Mode and Receive Bypass Mode. (HIGH=bypass PA, LOW=LNA)
+// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7
+// KCT8103L FEM: TX/RX path switching is handled by DIO2 -> CPS pin (via SX126X_DIO2_AS_RF_SWITCH)
+
+#define LORA_KCT8103L_PA_CSD 2 // CSD - KCT8103L chip enable (HIGH=on)
+#define LORA_KCT8103L_PA_CTX 5 // CTX - Switch between Receive LNA Mode and Receive Bypass Mode. (HIGH=bypass PA, LOW=LNA)
+
#if HAS_TFT
#define USE_TFTDISPLAY 1
#endif
diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini
index a5277ba196d..ebf0118bbed 100644
--- a/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini
+++ b/variants/esp32s3/heltec_wireless_tracker_v2/platformio.ini
@@ -17,6 +17,7 @@ build_flags =
${esp32s3_base.build_flags}
-I variants/esp32s3/heltec_wireless_tracker_v2
-D HELTEC_WIRELESS_TRACKER_V2
+ -D HAS_LORA_FEM=1
lib_deps =
${esp32s3_base.lib_deps}
# renovate: datasource=custom.pio depName=LovyanGFX packageName=lovyan03/library/LovyanGFX
diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h
index 0ca2dfc033f..7937039ba69 100644
--- a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h
+++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h
@@ -92,9 +92,9 @@
// CPS (pin 5) -> GPIO46: PA mode select (HIGH=full PA, LOW=bypass)
// VCC0/VCC1 -> Vfem via U3 LDO, controlled by GPIO7
#define USE_GC1109_PA
-#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable
-#define LORA_PA_EN 4 // CSD - GC1109 chip enable (HIGH=on)
-#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass)
+#define LORA_PA_POWER 7 // VFEM_Ctrl - GC1109 LDO power enable
+#define LORA_GC1109_PA_EN 4 // CSD - GC1109 chip enable (HIGH=on)
+#define LORA_GC1109_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass)
// GC1109 FEM: TX/RX path switching is handled by DIO2 -> CTX pin (via SX126X_DIO2_AS_RF_SWITCH)
// GPIO46 is CPS (PA mode), not TX control - setTransmitEnable() handles it in SX126xInterface.cpp