Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions zephcore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -323,12 +323,25 @@ 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.
# Boards with insufficient DRAM (e.g. classic ESP32 PICO-D4) can opt out
# by setting CONFIG_ZEPHCORE_WIFI_OTA=n in their board.conf.
if(ZEPHCORE_PLATFORM_CONF MATCHES "esp32_common" AND EXTRA_CONF_FILE MATCHES "repeater")
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})
zephcore_auto_pair_overlay("${ZEPHCORE_WIFI_OTA_CONF}")
message(STATUS " WiFi OTA: auto-enabled (ESP32 repeater)")
set(_wifi_ota_disabled FALSE)
if(ZEPHCORE_BOARD_CONF AND EXISTS "${ZEPHCORE_BOARD_CONF}")
file(STRINGS "${ZEPHCORE_BOARD_CONF}" _board_conf_lines)
if("CONFIG_ZEPHCORE_WIFI_OTA=n" IN_LIST _board_conf_lines)
set(_wifi_ota_disabled TRUE)
endif()
endif()
if(NOT _wifi_ota_disabled)
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})
zephcore_auto_pair_overlay("${ZEPHCORE_WIFI_OTA_CONF}")
message(STATUS " WiFi OTA: auto-enabled (ESP32 repeater)")
endif()
else()
message(STATUS " WiFi OTA: disabled (board.conf opt-out)")
endif()
endif()

Expand Down
53 changes: 53 additions & 0 deletions zephcore/adapters/board/ZephyrBoard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,48 @@ static const struct device *vbat_enable_dev = NULL;
#define VBAT_MV_MULTIPLIER CONFIG_ZEPHCORE_VBAT_MV_MULTIPLIER
#endif
#define VBAT_ADC_SAMPLES 8
#elif DT_NODE_EXISTS(DT_NODELABEL(axp192_pmic))
/* AXP192 PMIC: battery voltage via I2C registers 0x78/0x79.
* Used on boards without a GPIO-connected battery voltage divider,
* e.g. LilyGo T-Beam v1.x where battery management is internal to the PMIC. */
#include <zephyr/drivers/i2c.h>

/* AXP192 register map (datasheet section 9) */
#define AXP192_REG_ADC_EN1 0x82U /* ADC Enable 1 */
#define AXP192_BATT_V_ADC_EN BIT(7) /* reg 0x82 bit 7: battery voltage ADC */
#define AXP192_REG_BATT_VH 0x78U /* battery voltage ADC high 8 bits [11:4] */
#define AXP192_REG_BATT_VL 0x79U /* battery voltage ADC low 4 bits [7:4] */
#define AXP192_REG_GPIO0_FUNC 0x90U /* GPIO0 function control */
#define AXP192_GPIO0_FUNC_FLOAT 0x06U /* float / high-Z — cuts LED current path */

static const struct i2c_dt_spec axp192_i2c =
I2C_DT_SPEC_GET(DT_NODELABEL(axp192_pmic));

/* One-time AXP192 init at boot.
*
* 1. Enable battery voltage ADC (off at POR).
* 2. Float GPIO0 to turn off the red power-indicator LED.
* GPIO0 is open-drain; at POR its NMOS is conducting, sinking current
* from the VCC→LED→GPIO0 circuit and keeping the LED on. FLOAT mode
* puts GPIO0 in high-impedance, breaking the current path. */
static int axp192_batt_adc_init(void)
{
if (!i2c_is_ready_dt(&axp192_i2c)) {
return -ENODEV;
}

/* Enable battery voltage ADC */
int ret = i2c_reg_update_byte_dt(&axp192_i2c, AXP192_REG_ADC_EN1,
AXP192_BATT_V_ADC_EN, AXP192_BATT_V_ADC_EN);
if (ret < 0) {
return ret;
}

/* Turn off red power-indicator LED (GPIO0 → float) */
return i2c_reg_write_byte_dt(&axp192_i2c, AXP192_REG_GPIO0_FUNC,
AXP192_GPIO0_FUNC_FLOAT);
}
SYS_INIT(axp192_batt_adc_init, APPLICATION, 91);
#endif

/* Initialize TX LED GPIO at boot */
Expand Down Expand Up @@ -142,6 +184,17 @@ uint16_t ZephyrBoard::getBattMilliVolts()
uint16_t mv = (uint16_t)((mult * (int64_t)raw) / 4096);
LOG_DBG("Battery: raw=%d multiplier=%lld mv=%u", (int)raw, (long long)mult, mv);
return mv;
#elif DT_NODE_EXISTS(DT_NODELABEL(axp192_pmic))
/* 12-bit ADC: reg 0x78 = bits[11:4], reg 0x79 bits[7:4] = bits[3:0] */
uint8_t vh = 0, vl = 0;
if (!i2c_is_ready_dt(&axp192_i2c) ||
i2c_reg_read_byte_dt(&axp192_i2c, AXP192_REG_BATT_VH, &vh) < 0 ||
i2c_reg_read_byte_dt(&axp192_i2c, AXP192_REG_BATT_VL, &vl) < 0) {
return 0;
}
uint16_t raw = ((uint16_t)vh << 4) | (vl >> 4);
/* 1.1 mV per LSB — multiply by 11 then divide by 10 to avoid floats */
return (uint16_t)((uint32_t)raw * 11U / 10U);
#else
return 0;
#endif
Expand Down
47 changes: 47 additions & 0 deletions zephcore/boards/esp32/ttgo_tbeam/board.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# LilyGo T-Beam v1.x — ESP32 PICO-D4 + SX1276 + AXP192 PMIC
#
# Hardware:
# ESP32 PICO-D4 (4MB flash)
# SX1276 on SPI3 (NSS=18, SCK=5, MISO=19, MOSI=27, RESET=23, DIO0=26, DIO1=33, DIO2=32)
# AXP192 PMIC on I2C0 — LDO2→LoRa 3.3V, LDO3→GPS 3.3V
# NEO-6M GPS on UART1 (TX=12, RX=34)
# Optional SSD1306 OLED on I2C0 (SDA=21, SCL=22)
#
# Include order: prj.conf → zephcore_common.conf → esp32_common.conf → board.conf
#
# DRAM budget note (ESP32 PICO-D4):
# BT blob reserves ~56 KB DRAM. WiFi stack uses ~80 KB BSS.
# Both together overflow by ~55 KB. Use role-specific conf to select:
# boards/esp32/ttgo_tbeam/repeater.conf — WiFi OTA, no BT
# boards/esp32/ttgo_tbeam/companion.conf — BT, no WiFi OTA

CONFIG_ZEPHCORE_BOARD_NAME="LilyGo T-Beam"
CONFIG_BT_DIS_MODEL_NUMBER_STR="LilyGo T-Beam"

# Radio: SX1276 via loramac-node backend (not the native SX126x driver)
CONFIG_LORA_MODULE_BACKEND_NATIVE=n
CONFIG_LORA_MODULE_BACKEND_LORAMAC_NODE=y
CONFIG_ZEPHCORE_RADIO_SX127X=y

# SX1276 PA_BOOST output: 17 dBm is the safe maximum without an external PA
CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=17

# RX duty cycle not supported by the loramac-node SX127x driver
CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE=n

# ESP32 PICO-D4 rev 1.0: use DIO flash mode, not QIO.
# bootloader_enable_qio_mode() polls WIP indefinitely on PICO-D4 rev 1.0,
# causing a bootloop after the "Proceeding" chip-revision message.
CONFIG_ESPTOOLPY_FLASHMODE_QIO=n
CONFIG_ESPTOOLPY_FLASHMODE_DIO=y

# Default: BT enabled for companion app. WiFi OTA disabled (DRAM constraint).
# Override with repeater.conf for WiFi OTA + no BT.
CONFIG_ZEPHCORE_WIFI_OTA=n

# ESP32 PICO-D4 companion DRAM budget.
# BT blob reserves ~56 KB, leaving 136 KB for data+bss.
# Default 350 contacts × 184 bytes = 65 KB alone — reduce to 32 to fit.
# These are companion-role symbols; silently ignored on repeater builds.
CONFIG_ZEPHCORE_MAX_CONTACTS=32
CONFIG_ZEPHCORE_MAX_CHANNELS=8
143 changes: 143 additions & 0 deletions zephcore/boards/esp32/ttgo_tbeam/board.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* ZephCore overlay — LilyGo T-Beam v1.x (ESP32 PICO-D4 + SX1276 + AXP192)
*
* The upstream Zephyr ttgo_tbeam DTS targets a newer T-Beam revision that
* ships with AXP2101. The v1.0/v1.1 hardware uses AXP192. This overlay:
* 1. Removes the upstream AXP2101 node
* 2. Adds AXP192 with correct T-Beam v1.x LDO assignments:
* LDO2 → SX1276 LoRa 3.3V (always-on)
* LDO3 → GPS (NEO-6M) 3.3V
* 3. Repurposes storage_partition as LittleFS
*
* SX1276 pins (from upstream DTS, verified against T-Beam v1.x schematic):
* NSS=18 SCK=5 MISO=19 MOSI=27 RESET=23 DIO0=26 DIO1=33 DIO2=32
* If your board has RESET on GPIO14 (very early T-Beam v0.7), override
* reset-gpios in a local DTS fragment.
*/

#include <zephyr/dt-bindings/input/input-event-codes.h>

/* Remove the upstream AXP2101 node — wrong PMIC for v1.x hardware */
/delete-node/ &axp2101;

/ {
aliases {
regulator0 = &axp192_pmic;
/* GPIO4 LED is wired active-low (cathode to GPIO, anode to VCC).
* Upstream DTS has GPIO_ACTIVE_HIGH which inverts the logic and
* keeps the LED on permanently. We fix the polarity here and
* register the LED as the LoRa TX indicator so it flashes on
* each transmit in addition to the 4-second heartbeat pulse. */
lora-tx-led = &red_led;
};

/*
* T-Beam v1.x IO38 button (gpio1 pin 6).
* GPIO38 is input-only on ESP32 PICO-D4 (no internal pull-up).
* T-Beam PCB has 100 K pull-up to 3.3 V; button shorts GPIO38 to GND.
*/
buttons: buttons {
compatible = "gpio-keys";
button0: button_0 {
label = "IO38 button";
gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
zephyr,code = <INPUT_KEY_0>;
};
};

user_btn_longpress {
compatible = "zephyr,input-longpress";
input = <&buttons>;
input-codes = <INPUT_KEY_0>;
short-codes = <INPUT_KEY_A>;
long-codes = <INPUT_KEY_ENTER>;
long-delay-ms = <1000>;
};

page_btn_multitap {
compatible = "zephcore,input-multi-tap";
input-codes = <INPUT_KEY_A>;
tap-codes = <INPUT_KEY_1 INPUT_KEY_LEFT>;
tap-delay-ms = <400>;
};
};

/* Fix LED polarity: hardware is active-low, upstream DTS says active-high */
&red_led {
gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
};

/*
* Flash layout — repurpose storage_partition as LittleFS.
* 192 KB at 0x3B0000: same location and size as the deleted storage_partition.
*/
/delete-node/ &storage_partition;

&flash0 {
partitions {
lfs_partition: partition@3b0000 {
label = "lfs";
reg = <0x3B0000 0x30000>;
};
};
};

#include "../../common/filesystem.dtsi"

&i2c0 {
/*
* AXP192 PMIC — replaces AXP2101 from upstream DTS.
* T-Beam v1.x LDO assignments:
* DCDC1: ESP32 core VDD 3.3V
* LDO2: SX1276 LoRa VDD 3.3V
* LDO3: GPS VDD 3.3V
*/
axp192_pmic: axp192@34 {
compatible = "x-powers,axp192";
reg = <0x34>;
status = "okay";

axp192_regulator: axp192_regulator {
compatible = "x-powers,axp192-regulator";
status = "okay";

/* DCDC1 → ESP32 core VDD */
DCDC1 {
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};

/* LDO2 → SX1276 VDD — must be on before radio init */
LDO2 {
regulator-init-microvolt = <3300000>;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-always-on;
};

/* LDO3 → GPS VDD */
LDO3 {
regulator-init-microvolt = <3300000>;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
};
};
};

/* I2C sensors — auto-detected at runtime */
#include "../../common/sensors-i2c.dtsi"
};

/* WiFi — required for observer and wifi_ota roles */
&wifi {
status = "okay";
};

/* Bluetooth HCI — disabled by default in SoC DTSI, enable for repeater/companion */
&esp32_bt_hci {
status = "okay";
};