Tbeam 1W Fan and LNA Sequncing Fix

This commit is contained in:
Robowarrior834 2026-04-20 11:30:42 -04:00
parent dee3e26ac0
commit ad3a3bfb41
11 changed files with 61 additions and 13 deletions

View file

@ -229,4 +229,7 @@ void loop() {
ui_task.loop();
#endif
rtc_clock.tick();
}
#ifdef P_FAN_CTRL
update_fan_control();
#endif
}

View file

@ -887,7 +887,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.flood_advert_interval = 12; // 12 hours
_prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled
#ifdef DEFAULT_AGC_RESET_INTERVAL
_prefs.agc_reset_interval = DEFAULT_AGC_RESET_INTERVAL;
#endif
// bridge defaults
_prefs.bridge_enabled = 1; // enabled
_prefs.bridge_delay = 500; // milliseconds

View file

@ -153,7 +153,9 @@ void loop() {
ui_task.loop();
#endif
rtc_clock.tick();
#ifdef P_FAN_CTRL
update_fan_control();
#endif
if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) {
#if defined(NRF52_PLATFORM)
board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible

View file

@ -644,6 +644,9 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.flood_advert_interval = 12; // 12 hours
_prefs.flood_max = 64;
_prefs.interference_threshold = 0; // disabled
#ifdef DEFAULT_AGC_RESET_INTERVAL
_prefs.agc_reset_interval = DEFAULT_AGC_RESET_INTERVAL;
#endif
#ifdef ROOM_PASSWORD
StrHelper::strncpy(_prefs.guest_password, ROOM_PASSWORD, sizeof(_prefs.guest_password));
#endif

View file

@ -113,4 +113,7 @@ void loop() {
ui_task.loop();
#endif
rtc_clock.tick();
#ifdef P_FAN_CTRL
update_fan_control();
#endif
}

View file

@ -3,30 +3,49 @@
void TBeam1WBoard::begin() {
ESP32Board::begin();
// Power on radio module (must be done before radio init)
// Power on radio module (must be done before radio init).
// Drive LOW first to ensure a clean SX1262 reset — on soft reboot the ESP32
// GPIO glitch may be too brief to drain module capacitors, leaving the SX1262
// in a stuck state. Holding LOW for 50ms guarantees a full power cycle.
pinMode(SX126X_POWER_EN, OUTPUT);
digitalWrite(SX126X_POWER_EN, LOW);
delay(50);
digitalWrite(SX126X_POWER_EN, HIGH);
radio_powered = true;
delay(10); // Allow radio to power up
// RF switch RXEN pin handled by RadioLib via setRfSwitchPins()
// Explicitly drive RXEN HIGH (LNA on) from boot, before RadioLib takes over.
// Without this the pin floats until the first startReceive() call.
pinMode(SX126X_RXEN, OUTPUT);
digitalWrite(SX126X_RXEN, HIGH);
// Initialize LED
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Initialize fan control (on by default - 1W PA can overheat)
// Fan starts off; onAfterTransmit() enables it with a 30s cooldown timer
pinMode(FAN_CTRL_PIN, OUTPUT);
digitalWrite(FAN_CTRL_PIN, HIGH);
digitalWrite(FAN_CTRL_PIN, LOW);
}
void TBeam1WBoard::onBeforeTransmit() {
// RF switching handled by RadioLib via SX126X_DIO2_AS_RF_SWITCH and setRfSwitchPins()
digitalWrite(LED_PIN, HIGH); // TX LED on
digitalWrite(SX126X_RXEN, LOW); // disconnect LNA before PA ramps up
digitalWrite(LED_PIN, HIGH);
}
void TBeam1WBoard::onAfterTransmit() {
digitalWrite(LED_PIN, LOW); // TX LED off
digitalWrite(SX126X_RXEN, HIGH); // re-enable LNA immediately after TX
digitalWrite(LED_PIN, LOW);
// Keep fan running for 5s after TX
setFanEnabled(true);
_fan_off_millis = millis() + 10000;
}
void TBeam1WBoard::updateFan() {
if (_fan_off_millis > 0 && millis() >= _fan_off_millis) {
setFanEnabled(false);
_fan_off_millis = 0;
}
}
uint16_t TBeam1WBoard::getBattMilliVolts() {

View file

@ -30,6 +30,7 @@
class TBeam1WBoard : public ESP32Board {
private:
bool radio_powered = false;
unsigned long _fan_off_millis = 0; // 0 = no pending fan-off
public:
void begin();
@ -39,7 +40,9 @@ public:
const char* getManufacturerName() const override;
void powerOff() override;
// Fan control methods
// Called each main loop iteration to manage fan cooldown after TX
void updateFan();
void setFanEnabled(bool enabled);
bool isFanEnabled() const;
};

View file

@ -1,6 +1,7 @@
[LilyGo_TBeam_1W]
extends = esp32_base
board = t_beam_1w
board_build.partitions = default_16MB.csv
build_flags =
${esp32_base.build_flags}
-I variants/lilygo_tbeam_1w
@ -27,13 +28,20 @@ build_flags =
-D SX126X_DIO3_TCXO_VOLTAGE=3.0
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D SX126X_REGISTER_PATCH=1 ; Patch register 0x8B5 for improved RX with external PA+LNA FEM
; TX power: 22dBm to SX1262, PA module adds ~10dB for 32dBm total
-D LORA_TX_POWER=22
; AGC reset interval default: 60 seconds (value * 4000ms).
; Periodically recalibrates the SX1262 frontend to prevent progressive
; deafness caused by the receiver getting stuck in a high-attenuation state
; after repeated TX/RX transitions with the external PA+LNA module.
-D DEFAULT_AGC_RESET_INTERVAL=15
; Battery - 2S 7.4V LiPo (6.0V min, 8.4V max)
-D BATT_MIN_MILLIVOLTS=6000
-D BATT_MAX_MILLIVOLTS=8400
-D BATT_MAX_MILLIVOLTS=7900
; Display - SH1106 OLED at 0x3C
-D DISPLAY_CLASS=SH1106Display
@ -154,7 +162,6 @@ build_flags =
-I examples/companion_radio/ui-new
-D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40
-D OFFLINE_QUEUE_SIZE=256
-D WIFI_DEBUG_LOGGING=1
-D WIFI_SSID='"myssid"'
-D WIFI_PWD='"mypwd"'

View file

@ -63,3 +63,7 @@ mesh::LocalIdentity radio_new_identity() {
return mesh::LocalIdentity(&rng);
}
void update_fan_control() {
board.updateFan();
}

View file

@ -25,4 +25,5 @@ uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(int8_t dbm);
mesh::LocalIdentity radio_new_identity();
void update_fan_control();

View file

@ -82,6 +82,7 @@
// Fan control
#define FAN_CTRL_PIN 41
#define P_FAN_CTRL FAN_CTRL_PIN // enables update_fan_control() in main loop
// PA Ramp Time - T-Beam 1W requires >800us stabilization (default is 200us)
// Value 0x05 = RADIOLIB_SX126X_PA_RAMP_800U