8.3 KiB
Ratdeck — Troubleshooting
Collected hardware and software gotchas for the LilyGo T-Deck Plus with SX1262 LoRa.
Radio Issues
TCXO voltage must be 1.8V
The T-Deck Plus SX1262 uses a TCXO that requires 1.8V. This is configured as MODE_TCXO_1_8V_6X (0x02) in BoardConfig.h.
Symptom: Radio reports online but can't synthesize frequencies. PLL lock fails, no TX or RX.
Diagnosis: Ctrl+D diagnostics — if DevErrors shows 0x0040, that's PLL lock failure.
Fix: Verify LORA_TCXO_VOLTAGE is 0x02 in BoardConfig.h.
SetModulationParams must be called from STDBY mode
The SX1262 silently rejects SetModulationParams (0x8B) when issued from RX or TX mode. The command appears to succeed but the hardware ignores the new SF/BW/CR values.
Symptom: Software logs show correct SF/BW/CR but actual TX airtime is wrong. Two devices see each other's RF (RSSI visible) but every packet fails CRC.
Fix: setModulationParams() now calls standby() internally before issuing the SPI command.
Calibration must run after TCXO is enabled
Per SX1262 datasheet Section 13.1.12, if a TCXO is used, it must be enabled before calling calibrate(). Calibration locks to whichever oscillator is active.
Symptom: TX completes successfully on both devices, RSSI shows real signals, but neither device ever decodes the other's packets.
Fix: Init order must be: enableTCXO() -> delay(5ms) -> setRegulatorMode(DC-DC) -> loraMode() -> standby(XOSC) -> calibrate() -> calibrate_image()
IRQ stale latch
The SX1262's IRQ flags can become latched from previous operations. If stale flags persist, DCD gets stuck in "channel busy" and TX never fires.
Symptom: First packet sends fine, then all subsequent TX attempts hang.
Fix: Clear all IRQ flags at the top of receive() before entering RX mode. In dcd(), clear stale header error flags when preamble is not detected.
Build Issues
PlatformIO not on PATH
Fix: Use python3 -m platformio instead of pio:
python3 -m platformio run
python3 -m platformio run --target upload
python3 -m platformio device monitor -b 115200
Flash fails or disconnects mid-upload
The T-Deck Plus USB-Serial/JTAG can be sensitive to baud rates.
Fix: Enter download mode (hold trackball/BOOT button while pressing reset), then flash:
python3 -m esptool --chip esp32s3 --port /dev/cu.usbmodem* --baud 460800 \
write-flash -z 0x10000 .pio/build/ratdeck_915/firmware.bin
USBMode must be default
The build flag ARDUINO_USB_MODE=1 selects USB-Serial/JTAG mode (not native CDC).
Symptom: With hwcdc (USB_MODE=0), the port never appears on macOS.
Fix: Keep ARDUINO_USB_MODE=1 in platformio.ini.
Boot Issues
Boot loop detection and recovery
Ratdeck tracks consecutive boot failures in NVS. If 3 consecutive boots fail to reach the end of setup(), WiFi is forced OFF on the next boot.
How it works:
- On each boot, NVS counter
bootcincrements - If
bootc >= 3, WiFi forced to OFF - At end of successful
setup(), counter resets to 0
Manual recovery: Connect serial at 115200 baud and watch for [BOOT] Boot loop detected. The device should stabilize with WiFi off, then change WiFi settings in Setup.
Transport reference crash
RNS::Transport::_interfaces stores Interface& (references, not copies). If a RNS::Interface goes out of scope, it creates a dangling reference — LoadProhibited crash.
Fix: Store TCP Interface wrappers in std::list<RNS::Interface> at global scope. Must use std::list, not std::vector — vector reallocation invalidates references.
GPIO 10 must be HIGH
The T-Deck Plus requires GPIO 10 to be set HIGH at boot to enable all peripherals (display, radio, keyboard, etc.).
Symptom: Blank screen, no serial output, device appears dead.
Fix: setup() sets pinMode(10, OUTPUT); digitalWrite(10, HIGH); as the very first step.
Storage Issues
LittleFS not mounting
Symptom: [E][vfs_api.cpp:24] open(): File system is not mounted
Causes: First boot after flash erase, or partition table mismatch.
Fix: FlashStore calls LittleFS.begin(true) which auto-formats on first use. If it persists, erase flash and reflash:
python3 -m esptool --chip esp32s3 --port /dev/cu.usbmodem* erase-flash
SD card not detected
Check: SD card must be FAT32. The SD card shares the SPI bus with the radio and display (CS=GPIO 39).
Fix: Ensure SD card is inserted before power-on. Check serial output for [SD] messages. The device works without an SD card — flash is used as fallback.
Messages not persisting
Check: Verify SD card directories exist. Boot should auto-create /ratputer/messages/, /ratputer/contacts/, etc.
Fix: If directories are missing, reboot with SD card inserted. SDStore::formatForRatputer() creates the full directory tree on boot.
WiFi Issues
AP and STA are separate modes
Ratdeck uses three WiFi modes: OFF, AP, STA. These are NOT concurrent — WIFI_AP_STA was removed because it consumed too much heap and caused instability.
- AP mode: Creates
ratdeck-XXXXhotspot, TCP server on port 4242 - STA mode: Connects to an existing network, TCP client connections
- OFF: No WiFi
Switch modes in Setup -> Network. WiFi mode changes require reboot.
TCP client won't connect
Check: WiFi must be in STA mode and connected to a network first. TCP clients are created after WiFi connection succeeds.
Fix: Verify the TCP endpoint address and port. Check serial for [TCP] messages. Auto-reconnect runs every 15 seconds.
WiFi causes crashes
WiFi initialization is the most common crash source. The boot loop recovery system (3 consecutive failures -> WiFi OFF) handles this automatically.
Manual fix: If stuck, erase flash to reset NVS, reflash, and reconfigure WiFi settings.
RF Debugging
RSSI Monitor
Press Ctrl+R to sample RSSI continuously for 5 seconds. Transmit from another device during sampling. If RSSI stays at the noise floor (~-110 to -120 dBm), the RX front-end isn't hearing RF.
Test Packet
Press Ctrl+T to send a test packet with FIFO readback verification. Confirms the TX path without involving Reticulum.
Full Diagnostics
Press Ctrl+D for a complete diagnostic dump to serial:
| Field | Meaning |
|---|---|
| Identity hash | 16-byte Reticulum identity hash |
| Destination hash | LXMF destination address |
| Transport | ACTIVE or OFFLINE, endpoint or transport node |
| Paths / Links | Known Reticulum paths and active links |
| Freq / SF / BW / CR / TXP | Current radio parameters |
| SyncWord regs | Raw 0x0740/0x0741 values (should be 0x14/0x24) |
| DevErrors | SX1262 error register (0x0040 = PLL lock failure) |
| Current RSSI | Instantaneous RSSI in dBm |
| Free heap / PSRAM | Available memory |
| Flash | LittleFS used/total |
| Uptime | Seconds since boot |
Factory Reset
Settings-only reset
In Setup -> System -> Factory Reset: clears user config from flash and SD, then reboots. Radio, WiFi, display, and audio revert to defaults. Identity and messages are preserved.
SD card wipe
Connect serial at 115200 baud. Power cycle the device and send WIPE within 500ms of boot. Deletes /ratputer/* on the SD card and recreates clean directories.
Full flash erase
Erases everything — LittleFS, NVS, firmware:
python3 -m esptool --chip esp32s3 --port /dev/cu.usbmodem* erase-flash
Reflash firmware after erasing. A new identity will be generated. SD card data is preserved.
Serial Log Tags
| Tag | Subsystem |
|---|---|
[BOOT] |
Setup sequence |
[RADIO] |
SX1262 driver |
[LORA_IF] |
LoRa <-> Reticulum interface |
[WIFI] |
WiFi AP/STA |
[TCP] |
TCP client connections |
[LXMF] |
LXMF message protocol |
[SD] |
SD card storage |
[BLE] |
BLE Sideband transport |
[HOTKEY] |
Keyboard hotkey dispatch |
[ID] |
Identity management |
Known Limitations
| Feature | Status | Notes |
|---|---|---|
| Touchscreen | Disabled | GT911 needs calibration |
| GPS | Pins defined | Not yet implemented |
| Split packets | Header flag defined | Single-frame LoRa only (max ~254 bytes) |
| TCP client leak | Minor | Stopped clients not freed (Transport holds refs) |