Add Lilygo T-beam 1.2 (SX1262)

This commit is contained in:
liquidraver
2026-06-14 14:00:51 +02:00
parent 16238a129e
commit 18b63bd6f5
6 changed files with 237 additions and 4 deletions
+30 -2
View File
@@ -40,6 +40,7 @@ ESP32_boards=(
heltec_wifi_lora32_v3/esp32s3/procpu
heltec_wifi_lora32_v4/esp32s3/procpu
heltec_wifi_lora32_v43/esp32s3/procpu
ttgo_tbeam/esp32/procpu
)
if [[ $1 == "nrf" ]]; then
@@ -127,13 +128,40 @@ if [[ $1 == "esp32" ]]; then
for board in "${ESP32_boards[@]}"; do
board_clean_for_path=$(echo "$board" | sed -e 's/\//-/g')
if [[ $board =~ (esp32[^/]+) ]]; then
if [[ $board =~ (esp32[^/]*) ]]; then
chip="${BASH_REMATCH[1]}"
else
echo "Unknown chip for: $board"
exit 1;
fi
# Classic ESP32 (e.g. T-Beam, PICO-D4) cannot fit the mesh stack
# alongside MCUboot in DRAM, so it uses Zephyr's simple-boot path: a
# self-contained zephyr.bin flashed at the 0x1000 ROM bootloader offset.
# The S3/C-series have the DRAM headroom and use sysbuild + MCUboot
# (handled in the blocks below).
if [[ $chip == "esp32" ]]; then
if [[ $2 == "companions" ]]; then
role="companion"
echo "Now building $board companion (simple boot)"
west build -b "$board" zephcore --pristine
elif [[ $2 == "repeaters" ]]; then
role="repeater"
echo "Now building $board repeater (simple boot)"
west build -b "$board" zephcore --pristine -- -DEXTRA_CONF_FILE="boards/common/repeater.conf"
else
continue
fi
# Simple-boot zephyr.bin is already the complete bootable image;
# wrap it in a full-flash merged image at the 0x1000 offset.
python -m esptool --chip "$chip" merge-bin \
--output firmware/"$board_clean_for_path"-"$role"-"$COMMIT_HASH"-merged.bin \
--flash-mode dio --flash-freq 40m --flash-size 4MB \
0x1000 build/zephyr/zephyr.bin
cp build/zephyr/zephyr.bin firmware/"$board_clean_for_path"-"$role"-"$COMMIT_HASH".bin
continue
fi
if [[ $2 == "companions" ]]; then
# build ESP32 companions (production is the default)
echo "Now building $board companion"
+7 -1
View File
@@ -323,7 +323,13 @@ endif()
# Enables WiFi AP + HTTP server + MCUboot image management.
# Requires --sysbuild to build MCUboot alongside the app.
# Non-ESP32 builds and companion builds are unaffected.
if(ZEPHCORE_PLATFORM_CONF MATCHES "esp32_common" AND EXTRA_CONF_FILE MATCHES "repeater")
#
# Excluded on the classic ESP32 (e.g. T-Beam, board qualifier ".../esp32/..."):
# its DRAM cannot fit the mesh stack alongside WiFi + MCUboot, so it uses the
# simple-boot path and a CLI-only repeater (no WiFi OTA). The ESP32-S3/C-series
# (esp32s3/esp32c*) keep WiFi OTA.
if(ZEPHCORE_PLATFORM_CONF MATCHES "esp32_common" AND EXTRA_CONF_FILE MATCHES "repeater"
AND NOT BOARD MATCHES "/esp32/")
set(ZEPHCORE_WIFI_OTA_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/wifi_ota.conf")
if(EXISTS ${ZEPHCORE_WIFI_OTA_CONF})
list(APPEND ZEPHCORE_CONF_FILES ${ZEPHCORE_WIFI_OTA_CONF})
+35 -1
View File
@@ -66,6 +66,18 @@ static const struct device *vbat_enable_dev = NULL;
#define VBAT_ADC_SAMPLES 8
#endif
/* Battery fuel gauge (AXP2101 PMU etc.) — preferred over the ADC divider when
* present. Reports battery voltage and state-of-charge over I2C, so boards with
* a PMU and no battery ADC (e.g. LilyGo T-Beam) still get battery telemetry. */
#if DT_HAS_COMPAT_STATUS_OKAY(x_powers_axp2101_fuel_gauge)
#include <zephyr/drivers/fuel_gauge.h>
#define HAS_FUEL_GAUGE 1
static const struct device *const fuel_gauge_dev =
DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(x_powers_axp2101_fuel_gauge));
#else
#define HAS_FUEL_GAUGE 0
#endif
/* Initialize TX LED GPIO at boot */
#if HAS_TX_LED
static int tx_led_init(void)
@@ -82,7 +94,17 @@ namespace mesh {
uint16_t ZephyrBoard::getBattMilliVolts()
{
#if DT_NODE_EXISTS(DT_PATH(zephyr_user)) && \
#if HAS_FUEL_GAUGE
if (device_is_ready(fuel_gauge_dev)) {
union fuel_gauge_prop_val val;
int ret = fuel_gauge_get_prop(fuel_gauge_dev, FUEL_GAUGE_VOLTAGE, &val);
if (ret == 0) {
return (uint16_t)(val.voltage / 1000); /* µV -> mV */
}
LOG_WRN("Fuel gauge voltage read failed: %d", ret);
}
return 0;
#elif DT_NODE_EXISTS(DT_PATH(zephyr_user)) && \
DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
if (!adc_is_ready_dt(&vbat_adc)) {
LOG_ERR("ADC not ready");
@@ -149,6 +171,18 @@ uint16_t ZephyrBoard::getBattMilliVolts()
uint8_t ZephyrBoard::getBattPercent()
{
#if HAS_FUEL_GAUGE
if (device_is_ready(fuel_gauge_dev)) {
union fuel_gauge_prop_val val;
int ret = fuel_gauge_get_prop(fuel_gauge_dev,
FUEL_GAUGE_RELATIVE_STATE_OF_CHARGE, &val);
if (ret == 0) {
return val.relative_state_of_charge;
}
LOG_WRN("Fuel gauge SoC read failed: %d", ret);
}
/* Fall through to the voltage-curve estimate if the gauge read fails. */
#endif
return battery_curve_lookup(&battery_curve_default, getBattMilliVolts());
}
@@ -0,0 +1,40 @@
# LilyGo T-Beam v1.2 — ESP32 (PICO-D4) + SX1262
#
# Hardware:
# ESP32-PICO-D4 (4MB flash)
# SX1262 on SPI3 (DIO2 RF switch, 1.8V TCXO via DIO3)
# SSD1306 128x64 OLED on I2C0
# AXP2101 PMU — powers LoRa (ALDO2) and GPS (ALDO3) rails, battery fuel gauge
# NEO-6M / NEO-M8N GNSS on UART1
#
# Upstream Zephyr board: lilygo/ttgo_tbeam — that DTS models the SX1276 radio
# variant; board.overlay overrides the radio to a native SX1262 on the same
# SPI3 wiring. The AXP2101 MFD + regulator + fuel-gauge drivers are stock
# Zephyr and auto-enable from the upstream DTS PMU nodes.
#
# Include order: prj.conf -> zephcore_common.conf -> esp32_common.conf -> board.conf
# Board identification
CONFIG_ZEPHCORE_BOARD_NAME="LilyGo T-Beam"
CONFIG_BT_DIS_MODEL_NUMBER_STR="LilyGo T-Beam v1.2"
# SX1262 — 22 dBm default TX power (matches Arduino LORA_TX_POWER)
CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=22
# Battery via the AXP2101 fuel-gauge subsystem (voltage + state-of-charge over
# I2C). CONFIG_REGULATOR (zephcore_common.conf) plus the AXP2101 MFD/regulator
# drivers default-enable from the devicetree PMU nodes and bring the LoRa/GPS
# rails up at boot from their regulator-boot-on/always-on properties.
CONFIG_FUEL_GAUGE=y
# Flash mode: ESP32-PICO-D4 — use DIO, not QIO. PICO-D4 rev 1.0 hangs in the
# QIO-enable SPI sequence (RTCWDT bootloop), same as handled for ttgo_lora32.
CONFIG_ESPTOOLPY_FLASHMODE_QIO=n
CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
# Companion RAM budget — the classic ESP32 has a much smaller contiguous DRAM
# segment than the ESP32-S3 boards, and the default contact/queue arrays
# (350/256) overflow it. Use the Arduino MeshCore T-Beam companion sizes.
CONFIG_ZEPHCORE_MAX_CONTACTS=160
CONFIG_ZEPHCORE_MAX_CHANNELS=8
CONFIG_ZEPHCORE_OFFLINE_QUEUE_SIZE=128
@@ -0,0 +1,119 @@
/*
* SPDX-License-Identifier: MIT
* LilyGo T-Beam v1.2 (SX1262) — ZephCore overlay
*
* The upstream Zephyr DTS (lilygo/ttgo_tbeam) targets the SX1276 radio
* variant. The v1.2 board carries an SX1262 instead, on the same SPI3
* wiring, so this overlay swaps the radio over to the native SX126x driver
* and adds the SX1262-specific control pins.
*
* Pin mapping (Arduino MeshCore variants/lilygo_tbeam_SX1262):
* LoRa SPI3: SCLK=5, MOSI=27, MISO=19, NSS=18
* LoRa ctrl: RESET=23, BUSY=32 (gpio1 0), DIO1=33 (gpio1 1)
* DIO2 = antenna RF switch, DIO3 = 1.8V TCXO
* Display I2C0: SDA=21, SCL=22, SSD1306 @ 0x3C [base DTS]
* PMU I2C0: AXP2101 @ 0x34 [base DTS]
* GPS UART1: TX=12, RX=34, NEO-6M/M8N [base DTS]
*
* Power (AXP2101, brought up by the stock Zephyr regulator driver from the
* base DTS regulator-boot-on/always-on properties):
* DCDC1 = ESP32 + OLED (always-on)
* ALDO2 = LoRa -> raised to 3.3V below (upstream 2.9-3.0V)
* ALDO3 = GPS -> raised to 3.3V below (upstream 2.7-2.8V)
* 3.3V matches the Arduino/Meshtastic reference firmware for this board.
*/
#include <zephyr/dt-bindings/lora/sx126x.h>
/*
* BT HCI controller. The upstream ttgo_tbeam DTS does not select the ESP32 BT
* HCI controller, so forcing CONFIG_BT=y would otherwise leave the Espressif
* controller/PHY Kconfig half-configured (BT_ESP32 stays off). Enabling the HCI
* node selects BT_ESP32, which in turn pulls in the shared PHY.
*
* WiFi is intentionally left disabled: the classic ESP32 cannot fit the mesh
* stack alongside both the WiFi and BLE controllers in DRAM, and the companion
* transport is BLE. (A WiFi-observer build would need its own RAM-trimmed conf.)
*/
/ {
chosen {
zephyr,bt-hci = &esp32_bt_hci;
};
aliases {
/* GPIO4 LED blinks on LoRa TX, matching Arduino P_LORA_TX_LED=4
* and Meshtastic LED_POWER=4. */
lora-tx-led = &red_led;
};
};
&esp32_bt_hci {
status = "okay";
};
/*
* GPIO4 LED is active-LOW on the T-Beam (Meshtastic LED_STATE_ON=0; Arduino
* drives the pin LOW to light it). The upstream DTS marks it active-high, so
* correct the polarity here — otherwise the TX LED logic is inverted.
*/
&red_led {
gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
};
/* Swap the upstream SX1276 node to a native SX1262. */
&lora0 {
compatible = "semtech,sx1262";
spi-max-frequency = <8000000>;
/delete-property/ dio-gpios;
/delete-property/ power-amplifier-output;
/* RESET=GPIO23 inherited from base DTS; NSS=GPIO18 via spi3 cs-gpios. */
busy-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>; /* BUSY = GPIO32 */
dio1-gpios = <&gpio1 1 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; /* DIO1 = GPIO33 */
/* DIO2 drives the antenna TX/RX switch. */
dio2-tx-enable;
/* 1.8V TCXO via DIO3 (matches Arduino SX126X_DIO3_TCXO_VOLTAGE=1.8). */
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
tcxo-power-startup-delay-ms = <5>;
rx-boosted;
};
/* LoRa rail (ALDO2): upstream 2.9-3.0V; reference firmware runs it at 3.3V. */
&vdd_lora {
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
/* GPS rail (ALDO3): upstream 2.7-2.8V; reference firmware runs it at 3.3V. */
&vdd_gnss {
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
/* I2C sensors — auto-detected at runtime (OLED + AXP2101 already in base DTS). */
&i2c0 {
#include "../../common/sensors-i2c.dtsi"
};
/*
* Flash partitions — repurpose the 192KB storage_partition (0x3B0000) as
* LittleFS, same as ttgo_lora32. The 4MB AMP layout keeps its MCUboot slots.
*/
/delete-node/ &storage_partition;
&flash0 {
partitions {
/* LittleFS 192KB for DataStore (identity, prefs, creds) */
lfs_partition: partition@3b0000 {
label = "lfs";
reg = <0x3B0000 0x30000>;
};
};
};
/* LittleFS auto-mount — standard /lfs mount point */
#include "../../common/filesystem.dtsi"
+6
View File
@@ -37,11 +37,17 @@ station_g2/esp32s3/procpu
heltec_wifi_lora32_v3/esp32s3/procpu
heltec_wifi_lora32_v4/esp32s3/procpu
heltec_wifi_lora32_v43/esp32s3/procpu
ttgo_tbeam/esp32/procpu
```
> ESP32 boards require `west blobs fetch hal_espressif` before first build.
>
> Heltec V3 console/shell use `uart0` (UART serial) in ZephCore.
>
> **LilyGo T-Beam** (`ttgo_tbeam/esp32/procpu`): classic ESP32 (PICO-D4) with
> SX1262, AXP2101 PMU, and GNSS. Use this for the **v1.2 SX1262** variant — the
> upstream Zephyr DTS models the SX1276 radio, which ZephCore overrides to
> SX1262 in `board.overlay`. Console/CLI are on `uart0` (onboard USB-UART).
## MG24 (Silicon Labs)