diff --git a/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp b/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp index 4975d5cde..bd7f680ea 100644 --- a/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp +++ b/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp @@ -6,18 +6,26 @@ void HeltecTrackerV2Board::begin() { pinMode(PIN_ADC_CTRL, OUTPUT); digitalWrite(PIN_ADC_CTRL, LOW); // Initially inactive + // Set up digital GPIO registers before releasing RTC hold. The hold latches + // the pad state including function select, so register writes accumulate + // without affecting the pad. On hold release, all changes apply atomically + // (IO MUX switches to digital GPIO with output already HIGH — no glitch). pinMode(P_LORA_PA_POWER, OUTPUT); digitalWrite(P_LORA_PA_POWER,HIGH); + rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_POWER); - rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_EN); pinMode(P_LORA_PA_EN, OUTPUT); digitalWrite(P_LORA_PA_EN,HIGH); + rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_EN); pinMode(P_LORA_PA_TX_EN, OUTPUT); digitalWrite(P_LORA_PA_TX_EN,LOW); - periph_power.begin(); - esp_reset_reason_t reason = esp_reset_reason(); + if (reason != ESP_RST_DEEPSLEEP) { + delay(1); // GC1109 startup time after cold power-on + } + + periph_power.begin(); if (reason == ESP_RST_DEEPSLEEP) { long wakeup_source = esp_sleep_get_ext1_wakeup_status(); if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) @@ -48,7 +56,9 @@ void HeltecTrackerV2Board::begin() { rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); - rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_EN); //It also needs to be enabled in receive mode + // Hold GC1109 FEM pins during sleep to keep LNA active for RX wake + rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER); + rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_EN); if (pin_wake_btn < 0) { esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet diff --git a/variants/heltec_tracker_v2/platformio.ini b/variants/heltec_tracker_v2/platformio.ini index 25d16f2f6..af41b4f56 100644 --- a/variants/heltec_tracker_v2/platformio.ini +++ b/variants/heltec_tracker_v2/platformio.ini @@ -17,11 +17,11 @@ build_flags = -D P_LORA_SCLK=9 -D P_LORA_MISO=11 -D P_LORA_MOSI=10 - -D P_LORA_PA_POWER=7 ;power en - -D P_LORA_PA_EN=4 - -D P_LORA_PA_TX_EN=46 ;enable tx - -D LORA_TX_POWER=10 ;If it is configured as 10 here, the final output will be 22 dbm. - -D MAX_LORA_TX_POWER=22 ;Max SX1262 output + -D P_LORA_PA_POWER=7 ; VFEM_Ctrl - GC1109 LDO power enable + -D P_LORA_PA_EN=4 ; CSD - GC1109 chip enable (HIGH=on) + -D P_LORA_PA_TX_EN=46 ; CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass) + -D LORA_TX_POWER=10 ; 10dBm + ~11dB GC1109 gain = ~21dBm output + -D MAX_LORA_TX_POWER=22 ; Max SX1262 output -> ~28dBm at antenna -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 diff --git a/variants/heltec_v4/HeltecV4Board.cpp b/variants/heltec_v4/HeltecV4Board.cpp index 92f934376..7e9ecb08e 100644 --- a/variants/heltec_v4/HeltecV4Board.cpp +++ b/variants/heltec_v4/HeltecV4Board.cpp @@ -3,42 +3,71 @@ void HeltecV4Board::begin() { ESP32Board::begin(); - pinMode(PIN_ADC_CTRL, OUTPUT); - digitalWrite(PIN_ADC_CTRL, LOW); // Initially inactive + digitalWrite(PIN_ADC_CTRL, LOW); + // Power on FEM LDO — set registers before releasing RTC hold for + // atomic transition (no glitch on deep sleep wake). pinMode(P_LORA_PA_POWER, OUTPUT); - digitalWrite(P_LORA_PA_POWER,HIGH); + digitalWrite(P_LORA_PA_POWER, HIGH); + rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_POWER); + + esp_reset_reason_t reason = esp_reset_reason(); + if (reason != ESP_RST_DEEPSLEEP) { + delay(1); // FEM startup time after cold power-on + } + // Auto-detect FEM type via GPIO2 default pull level. + // GC1109 CSD: internal pull-down → reads LOW + // KCT8103L CSD: internal pull-up → reads HIGH rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_EN); + pinMode(P_LORA_PA_EN, INPUT); + delay(1); + is_kct8103l_ = (digitalRead(P_LORA_PA_EN) == HIGH); + + // CSD/enable: HIGH for both FEM types pinMode(P_LORA_PA_EN, OUTPUT); - digitalWrite(P_LORA_PA_EN,HIGH); - pinMode(P_LORA_PA_TX_EN, OUTPUT); - digitalWrite(P_LORA_PA_TX_EN,LOW); + digitalWrite(P_LORA_PA_EN, HIGH); + if (is_kct8103l_) { + // V4.3 — KCT8103L: CTX on GPIO5 controls TX/RX path + rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_CTX); + pinMode(P_LORA_PA_CTX, OUTPUT); + digitalWrite(P_LORA_PA_CTX, LOW); // RX mode (LNA enabled) + } else { + // V4.2 — GC1109: CPS on GPIO46 controls PA mode + pinMode(P_LORA_PA_TX_EN, OUTPUT); + digitalWrite(P_LORA_PA_TX_EN, LOW); // RX bypass mode + } periph_power.begin(); - esp_reset_reason_t reason = esp_reset_reason(); if (reason == ESP_RST_DEEPSLEEP) { long wakeup_source = esp_sleep_get_ext1_wakeup_status(); - if (wakeup_source & (1 << P_LORA_DIO_1)) { // received a LoRa packet (while in deep sleep) + if (wakeup_source & (1 << P_LORA_DIO_1)) { startup_reason = BD_STARTUP_RX_PACKET; } - rtc_gpio_hold_dis((gpio_num_t)P_LORA_NSS); rtc_gpio_deinit((gpio_num_t)P_LORA_DIO_1); } } void HeltecV4Board::onBeforeTransmit(void) { - digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on - digitalWrite(P_LORA_PA_TX_EN,HIGH); + digitalWrite(P_LORA_TX_LED, HIGH); + if (is_kct8103l_) { + digitalWrite(P_LORA_PA_CTX, HIGH); // CTX: TX path + } else { + digitalWrite(P_LORA_PA_TX_EN, HIGH); // CPS: full PA + } } void HeltecV4Board::onAfterTransmit(void) { - digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off - digitalWrite(P_LORA_PA_TX_EN,LOW); + digitalWrite(P_LORA_TX_LED, LOW); + if (is_kct8103l_) { + digitalWrite(P_LORA_PA_CTX, LOW); // CTX: RX path (LNA on) + } else { + digitalWrite(P_LORA_PA_TX_EN, LOW); // CPS: bypass + } } void HeltecV4Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { @@ -50,7 +79,15 @@ void HeltecV4Board::begin() { rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); - rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_EN); //It also needs to be enabled in receive mode + // Hold FEM pins during sleep to keep LNA active for RX wake + rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER); + rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_EN); + + if (is_kct8103l_) { + // Hold CTX LOW during deep sleep for RX wake (LNA enabled) + digitalWrite(P_LORA_PA_CTX, LOW); + rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_CTX); + } if (pin_wake_btn < 0) { esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet @@ -87,8 +124,8 @@ void HeltecV4Board::begin() { const char* HeltecV4Board::getManufacturerName() const { #ifdef HELTEC_LORA_V4_TFT - return "Heltec V4 TFT"; + return is_kct8103l_ ? "Heltec V4.3 TFT" : "Heltec V4 TFT"; #else - return "Heltec V4 OLED"; + return is_kct8103l_ ? "Heltec V4.3 OLED" : "Heltec V4 OLED"; #endif } diff --git a/variants/heltec_v4/HeltecV4Board.h b/variants/heltec_v4/HeltecV4Board.h index 745e8d8f3..8a2524a84 100644 --- a/variants/heltec_v4/HeltecV4Board.h +++ b/variants/heltec_v4/HeltecV4Board.h @@ -20,4 +20,6 @@ class HeltecV4Board : public ESP32Board { uint16_t getBattMilliVolts() override; const char* getManufacturerName() const override ; +private: + bool is_kct8103l_ = false; // true = V4.3 (KCT8103L), false = V4.2 (GC1109) }; diff --git a/variants/heltec_v4/platformio.ini b/variants/heltec_v4/platformio.ini index 71ffc2e6a..b8aedb0ba 100644 --- a/variants/heltec_v4/platformio.ini +++ b/variants/heltec_v4/platformio.ini @@ -20,6 +20,7 @@ build_flags = -D P_LORA_PA_POWER=7 ; VFEM_Ctrl - Power on GC1109 -D P_LORA_PA_EN=2 ; PA CSD - Enable GC1109 -D P_LORA_PA_TX_EN=46 ; PA CPS - GC1109 TX PA full(High) / bypass(Low) + -D P_LORA_PA_CTX=5 ; KCT8103L CTX pin (V4.3 only, auto-detected) -D PIN_USER_BTN=0 -D PIN_VEXT_EN=36 -D PIN_VEXT_EN_ACTIVE=HIGH