From aca76aabffae37fb690d13813eb03284160defd1 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sat, 20 Dec 2025 18:38:11 +0100 Subject: [PATCH 1/2] Fix LNA/PA power control for Heltec v4, wireless tracker v2 --- src/mesh/SX126xInterface.cpp | 9 +++++++-- variants/esp32s3/heltec_v4/variant.h | 12 ++++++++---- .../esp32s3/heltec_wireless_tracker_v2/variant.h | 12 ++++++++---- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index e1f07a32b80..effa6f1f52d 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -53,13 +53,18 @@ template bool SX126xInterface::init() #endif #if defined(USE_GC1109_PA) + // GC1109 FEM chip initialization + // PA_POWER: Power enable for GC1109 (always on) pinMode(LORA_PA_POWER, OUTPUT); digitalWrite(LORA_PA_POWER, HIGH); + // PA_EN: Main enable for GC1109 (must be HIGH for both RX and TX) pinMode(LORA_PA_EN, OUTPUT); - digitalWrite(LORA_PA_EN, LOW); + digitalWrite(LORA_PA_EN, HIGH); // CRITICAL: Must be HIGH, not LOW! + + // PA_TX_EN: RF switch control (LOW=RX/LNA, HIGH=TX/PA) pinMode(LORA_PA_TX_EN, OUTPUT); - digitalWrite(LORA_PA_TX_EN, LOW); + digitalWrite(LORA_PA_TX_EN, LOW); // Default to RX mode #endif #if ARCH_PORTDUINO diff --git a/variants/esp32s3/heltec_v4/variant.h b/variants/esp32s3/heltec_v4/variant.h index 6524bbc723e..736fc41aa1f 100644 --- a/variants/esp32s3/heltec_v4/variant.h +++ b/variants/esp32s3/heltec_v4/variant.h @@ -29,10 +29,14 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator -#define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 2 -#define LORA_PA_TX_EN 46 // enable tx +#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator +#define LORA_PA_POWER 7 // power en +#define LORA_PA_EN 2 // main enable (HIGH for both RX and TX) +#define LORA_PA_TX_EN 46 // enable tx (LOW=RX/LNA, HIGH=TX/PA) + +// Tell RadioLib about external RF switch control +#define SX126X_RXEN RADIOLIB_NC // No separate RX enable pin +#define SX126X_TXEN LORA_PA_TX_EN // TX enable pin controls RF switch #if HAS_TFT #define USE_TFTDISPLAY 1 diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h index 0ce6b3e00e1..cb4969b7ccb 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h +++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h @@ -73,7 +73,11 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator -#define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 4 -#define LORA_PA_TX_EN 46 // enable tx \ No newline at end of file +#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator +#define LORA_PA_POWER 7 // power en +#define LORA_PA_EN 4 // main enable (HIGH for both RX and TX) +#define LORA_PA_TX_EN 46 // enable tx (LOW=RX/LNA, HIGH=TX/PA) + +// Tell RadioLib about external RF switch control +#define SX126X_RXEN RADIOLIB_NC // No separate RX enable pin +#define SX126X_TXEN LORA_PA_TX_EN // TX enable pin controls RF switch \ No newline at end of file From 49f1e912f3f1f20115b705bc0d1da73ca863bd16 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Tue, 23 Dec 2025 22:45:03 +0100 Subject: [PATCH 2/2] Stop using pin 46 as RF switch, just let DIO2 switch handle the RF path --- src/mesh/SX126xInterface.cpp | 21 +++++++----- variants/esp32s3/heltec_v4/variant.h | 34 ++++++++++++++----- .../heltec_wireless_tracker_v2/variant.h | 32 +++++++++++++---- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index effa6f1f52d..cdc06e46931 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -54,17 +54,20 @@ template bool SX126xInterface::init() #if defined(USE_GC1109_PA) // GC1109 FEM chip initialization - // PA_POWER: Power enable for GC1109 (always on) + // See variant.h for full pin mapping and control logic documentation + + // VFEM_Ctrl (LORA_PA_POWER): Power enable for GC1109 LDO (always on) pinMode(LORA_PA_POWER, OUTPUT); digitalWrite(LORA_PA_POWER, HIGH); - // PA_EN: Main enable for GC1109 (must be HIGH for both RX and TX) + // 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); // CRITICAL: Must be HIGH, not LOW! + digitalWrite(LORA_PA_EN, HIGH); - // PA_TX_EN: RF switch control (LOW=RX/LNA, HIGH=TX/PA) + // 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); // Default to RX mode + digitalWrite(LORA_PA_TX_EN, LOW); // Start in RX-ready state #endif #if ARCH_PORTDUINO @@ -370,13 +373,13 @@ template bool SX126xInterface::sleep() return true; } -/** Some boards require GPIO control of tx vs rx paths */ +/** 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); - digitalWrite(LORA_PA_EN, HIGH); - digitalWrite(LORA_PA_TX_EN, txon ? 1 : 0); + 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) #endif } diff --git a/variants/esp32s3/heltec_v4/variant.h b/variants/esp32s3/heltec_v4/variant.h index 736fc41aa1f..1c1168d9459 100644 --- a/variants/esp32s3/heltec_v4/variant.h +++ b/variants/esp32s3/heltec_v4/variant.h @@ -29,14 +29,32 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator -#define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 2 // main enable (HIGH for both RX and TX) -#define LORA_PA_TX_EN 46 // enable tx (LOW=RX/LNA, HIGH=TX/PA) - -// Tell RadioLib about external RF switch control -#define SX126X_RXEN RADIOLIB_NC // No separate RX enable pin -#define SX126X_TXEN LORA_PA_TX_EN // TX enable pin controls RF switch +// ---- 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 +// 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 +// +9dB at 18-19dBm input +// +7dB at 21dBm input (e.g., 21dBm in -> 28dBm out max) +// Control logic (from GC1109 datasheet): +// Shutdown: CSD=0, CTX=X, CPS=X +// Receive LNA: CSD=1, CTX=0, CPS=X (17dB gain, 2dB NF) +// Transmit bypass: CSD=1, CTX=1, CPS=0 (~1dB loss, no PA) +// Transmit PA: CSD=1, CTX=1, CPS=1 (full PA enabled) +// Pin mapping: +// CTX (pin 6) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH) +// 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 #if HAS_TFT #define USE_TFTDISPLAY 1 diff --git a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h index cb4969b7ccb..a5489173d37 100644 --- a/variants/esp32s3/heltec_wireless_tracker_v2/variant.h +++ b/variants/esp32s3/heltec_wireless_tracker_v2/variant.h @@ -73,11 +73,29 @@ #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#define USE_GC1109_PA // We have a GC1109 power amplifier+attenuator -#define LORA_PA_POWER 7 // power en -#define LORA_PA_EN 4 // main enable (HIGH for both RX and TX) -#define LORA_PA_TX_EN 46 // enable tx (LOW=RX/LNA, HIGH=TX/PA) +// ---- GC1109 RF FRONT END CONFIGURATION ---- +// The Heltec Wireless Tracker V2 uses a GC1109 FEM chip with integrated PA and LNA +// RF path: SX1262 -> GC1109 PA -> Pi attenuator -> 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 +// +9dB at 18-19dBm input +// +7dB at 21dBm input (e.g., 21dBm in -> 28dBm out max) +// Control logic (from GC1109 datasheet): +// Shutdown: CSD=0, CTX=X, CPS=X +// Receive LNA: CSD=1, CTX=0, CPS=X (17dB gain, 2dB NF) +// Transmit bypass: CSD=1, CTX=1, CPS=0 (~1dB loss, no PA) +// Transmit PA: CSD=1, CTX=1, CPS=1 (full PA enabled) +// Pin mapping: +// CTX (pin 6) -> SX1262 DIO2: TX/RX path select (automatic via SX126X_DIO2_AS_RF_SWITCH) +// CSD (pin 4) -> GPIO4: 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 4 // CSD - GC1109 chip enable (HIGH=on) +#define LORA_PA_TX_EN 46 // CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass) -// Tell RadioLib about external RF switch control -#define SX126X_RXEN RADIOLIB_NC // No separate RX enable pin -#define SX126X_TXEN LORA_PA_TX_EN // TX enable pin controls RF switch \ No newline at end of file +// 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 \ No newline at end of file