Hold GC1109 FEM power during deep sleep for LNA RX wake (#9572)
* Hold GC1109 PA_POWER and PA_EN during deep sleep for LNA RX wake Use rtc_gpio_hold_en to latch PA_POWER (LDO) and PA_EN (CSD) HIGH during deep sleep so the GC1109 LNA remains powered for wake-on-packet RX. Previously these pins used weak pull-ups which could lose state. On deep sleep wake, skip these pins in the blanket RTC hold release and instead release them in SX126xInterface::init() after GPIO registers are set HIGH first, avoiding a power glitch on the GC1109. Trade-off: ~6.5mA additional deep sleep current for significantly improved wake-on-packet RX sensitivity (~17dB). Reference: https://github.com/meshcore-dev/MeshCore/pull/1600 * Add LDO startup delay before GC1109 chip enable TLV75733P LDO has ~550us startup time (datasheet tSTR). On cold boot, wait 1ms for VBAT to stabilise before driving CSD/CPS, per GC1109 power-on sequence requirement. On deep sleep wake the LDO is held on via RTC latch so no delay is needed.
This commit is contained in:
@@ -6,6 +6,10 @@
|
|||||||
#ifdef ARCH_PORTDUINO
|
#ifdef ARCH_PORTDUINO
|
||||||
#include "PortduinoGlue.h"
|
#include "PortduinoGlue.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(USE_GC1109_PA) && defined(ARCH_ESP32)
|
||||||
|
#include <driver/rtc_io.h>
|
||||||
|
#include <esp_sleep.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Throttle.h"
|
#include "Throttle.h"
|
||||||
|
|
||||||
@@ -55,14 +59,33 @@ template <typename T> bool SX126xInterface<T>::init()
|
|||||||
#if defined(USE_GC1109_PA)
|
#if defined(USE_GC1109_PA)
|
||||||
// GC1109 FEM chip initialization
|
// GC1109 FEM chip initialization
|
||||||
// See variant.h for full pin mapping and control logic documentation
|
// 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)
|
// VFEM_Ctrl (LORA_PA_POWER): Power enable for GC1109 LDO (always on)
|
||||||
pinMode(LORA_PA_POWER, OUTPUT);
|
pinMode(LORA_PA_POWER, OUTPUT);
|
||||||
digitalWrite(LORA_PA_POWER, HIGH);
|
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
|
// CSD (LORA_PA_EN): Chip enable - must be HIGH to enable GC1109 for both RX and TX
|
||||||
pinMode(LORA_PA_EN, OUTPUT);
|
pinMode(LORA_PA_EN, OUTPUT);
|
||||||
digitalWrite(LORA_PA_EN, HIGH);
|
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)
|
// 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
|
// Note: TX/RX path switching (CTX) is handled by DIO2 via SX126X_DIO2_AS_RF_SWITCH
|
||||||
|
|||||||
+14
-2
@@ -162,6 +162,13 @@ void initDeepSleep()
|
|||||||
if (wakeCause != ESP_SLEEP_WAKEUP_UNDEFINED) {
|
if (wakeCause != ESP_SLEEP_WAKEUP_UNDEFINED) {
|
||||||
LOG_DEBUG("Disable any holds on RTC IO pads");
|
LOG_DEBUG("Disable any holds on RTC IO pads");
|
||||||
for (uint8_t i = 0; i <= GPIO_NUM_MAX; i++) {
|
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))
|
if (rtc_gpio_is_valid_gpio((gpio_num_t)i))
|
||||||
rtc_gpio_hold_dis((gpio_num_t)i);
|
rtc_gpio_hold_dis((gpio_num_t)i);
|
||||||
|
|
||||||
@@ -556,8 +563,13 @@ void enableLoraInterrupt()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(USE_GC1109_PA)
|
#if defined(USE_GC1109_PA)
|
||||||
gpio_pullup_en((gpio_num_t)LORA_PA_POWER);
|
// Keep GC1109 FEM powered during deep sleep so LNA remains active for RX wake.
|
||||||
gpio_pullup_en((gpio_num_t)LORA_PA_EN);
|
// 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);
|
gpio_pulldown_en((gpio_num_t)LORA_PA_TX_EN);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user