esp gps and BT to 9dBm

This commit is contained in:
liquidraver
2026-09-07 22:29:10 +02:00
parent eef6a488a2
commit 53cf183a5c
3 changed files with 190 additions and 1 deletions
+38 -1
View File
@@ -6,7 +6,44 @@
# ========== BLE: ESP32-specific controller settings ==========
# DLE managed internally by Espressif blob — no CONFIG_BT_CTLR_DATA_LENGTH_MAX
# TX power managed internally by Espressif blob — no CONFIG_BT_CTLR_TX_PWR_*
# BLE TX power — +9 dBm, matching stock Arduino MeshCore.
#
# This was previously left unset, on the belief that the Espressif blob managed
# TX power internally. It does not. Zephyr's HCI driver initialises the
# controller with BT_CONTROLLER_INIT_CONFIG_DEFAULT() (hci_esp32.c), whose
# .txpwr_dft comes from CONFIG_ESP32_BT_CTLR_DFT_TX_POWER_LEVEL_EFF — and that
# macro is a #if chain over Zephyr's CONFIG_BT_CTLR_TX_PWR_* symbols with an
# #else /* use 0dB TX power as default */
# fallback. With none of them set the chain fell through and every ESP32 board
# advertised and connected at 0 dBm, while stock Arduino MeshCore inherits the
# Arduino-ESP32 sdkconfig (CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_P9=y) and runs at
# +9 dBm. That 9 dB deficit is the reported "ZephCore has worse BLE range than
# official firmware" on Heltec V4 — roughly 2.8x the free-space distance.
#
# The symbols ARE settable here: BT_ESP32 selects HAS_BT_CTLR, and upstream
# gates the +9/+12/+15/+18/+21 options on `depends on SOC_FAMILY_ESPRESSIF_ESP32`
# specifically so ESP32 boards can pick one.
#
# Why +9 and not the +20 dBm ceiling the S3/C3/C6 parts can reach: +9 is what
# stock MeshCore runs, it is comfortably inside the EU 2.4 GHz 100 mW (20 dBm)
# EIRP limit, and it is the ONLY level that appears in all three Espressif
# header families — so one line covers every board with no per-board override:
#
# include/esp32c3 (also S3) PLUS_9 -> ESP_PWR_LVL_P9 ceiling +20 dBm
# include/esp32c6 (c5/h2) PLUS_9 -> literal 9 ceiling +20 dBm
# include/esp32 (classic) PLUS_9 -> ESP_PWR_LVL_P9 ceiling +9 dBm
#
# That last row is the trap if anyone raises this later: the classic ESP32
# (ttgo_tbeam, ttgo_lora32) tops out at ESP_PWR_LVL_P9 and its chain has no
# PLUS_12/15/18/21 arm at all, so any higher setting matches nothing there and
# silently drops those two boards back to the 0 dBm `#else` — no warning, no
# build error. Raising this above +9 therefore requires a PLUS_9 override in
# both classic board.conf files.
#
# nRF/nRF54L use CONFIG_BT_CTLR_TX_PWR_PLUS_8 (their own ceiling); +8 is not
# selectable on ESP32 and the ESP32 power enum has no P8 — 3 dB steps only.
CONFIG_BT_CTLR_TX_PWR_PLUS_9=y
# Host privacy: ESP32-only override. Load-bearing for iOS on the Espressif
# controller (Zephyr #84182-class). nRF/MG24 keep privacy OFF.
@@ -14,6 +14,8 @@
* Vext: GPIO36 (active-HIGH, powers OLED)
* Button: GPIO0
* LED: GPIO35
* GPS UART1: TX=GPIO39, RX=GPIO38, 9600 baud (optional external module)
* GPS ctrl: enable GPIO34 (active-LOW), reset GPIO42 (active-LOW)
*/
#include <zephyr/dt-bindings/input/input-event-codes.h>
@@ -47,6 +49,45 @@
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; /* GPIO37 = gpio1 pin 5, HIGH enables (V4/V4.3) */
};
/* GPS enable — GPIO34, active-LOW (Arduino MeshCore heltec_v4:
* PIN_GPS_EN=34, PIN_GPS_EN_ACTIVE=LOW). ZephCore's GPS manager drives
* this via the gps-enable alias.
*
* GPIO33-37 are the octal-PSRAM pads on ESP32-S3 modules that carry one;
* the V4 has 2 MB *quad* PSRAM, so 33/34 are free here — 35/36/37 are
* already spent on LED/Vext/ADC-ctrl above, which is the same evidence. */
gps_en: gps-enable {
compatible = "gpio-leds";
gps_enable_pin: gps_enable {
gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* GPIO34 = gpio1 pin 2 */
label = "GPS Enable";
};
};
/* GPS reset — GPIO42, active-LOW (Arduino PIN_GPS_RESET=42,
* PIN_GPS_RESET_ACTIVE=LOW). Declared so the line is always driven to a
* defined level rather than left floating into the module's reset input.
*
* Declaring gps-reset moves this board onto the manager's
* HAS_T1000_GPS_CONTROL power sequence (EN -> reset -> release). That is
* safe without a VRTC pin — every VRTC/SLEEP step in that path is behind
* its own #if. Note the power-ON pulse uses the raw GPIO_OUTPUT_HIGH flag,
* so on an active-LOW line it de-asserts rather than pulsing; the useful
* half is power-OFF, which asserts reset (logical 1) and holds the module
* down while its supply is gated. */
gps_rst: gps-reset {
compatible = "gpio-leds";
gps_reset_pin: gps_reset {
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* GPIO42 = gpio1 pin 10 */
label = "GPS Reset";
};
};
aliases {
gps-enable = &gps_enable_pin;
gps-reset = &gps_reset_pin;
};
/* Button chain — same mapping as RAK4631 / WisMesh Pocket (rak4631/board.overlay). */
user_btn_longpress {
compatible = "zephyr,input-longpress";
@@ -77,6 +118,41 @@
rx-boosted;
};
/* GPS on UART1 — optional external NMEA module on the pin header, wired to the
* same pins Arduino MeshCore uses for this board (PIN_GPS_RX=38, PIN_GPS_TX=39;
* Arduino names them from the MCU's point of view, so RX=38 is the MCU input).
* Upstream leaves uart1 disabled and gives it no pinctrl, so both are set here.
* GPIO38/39 are otherwise unclaimed on the V4; the console stays on usb_serial
* (or uart0/GPIO43-44 for companion USB builds). 9600 baud matches Arduino's
* default for this variant.
*
* The node is unconditional, like the V3's gnss node for its optional module:
* with nothing fitted the driver simply never sees a fix. */
&pinctrl {
uart1_default: uart1_default {
group1 {
pinmux = <UART1_TX_GPIO39>;
output-high;
};
group2 {
pinmux = <UART1_RX_GPIO38>;
bias-pull-up;
};
};
};
&uart1 {
status = "okay";
current-speed = <9600>;
pinctrl-0 = <&uart1_default>;
pinctrl-names = "default";
gnss: gnss-nmea-generic {
compatible = "gnss-nmea-generic";
};
};
/* I2C sensors — auto-detected at runtime */
&i2c0 {
#include "../../common/sensors-i2c.dtsi"
@@ -14,6 +14,8 @@
* Vext: GPIO36 (active-HIGH, powers OLED)
* Button: GPIO0
* LED: GPIO35
* GPS UART1: TX=GPIO39, RX=GPIO38, 9600 baud (optional external module)
* GPS ctrl: enable GPIO34 (active-LOW), reset GPIO42 (active-LOW)
*/
#include <zephyr/dt-bindings/input/input-event-codes.h>
@@ -47,6 +49,45 @@
enable-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; /* GPIO37 = gpio1 pin 5, HIGH enables (V4/V4.3) */
};
/* GPS enable — GPIO34, active-LOW (Arduino MeshCore heltec_v4:
* PIN_GPS_EN=34, PIN_GPS_EN_ACTIVE=LOW). ZephCore's GPS manager drives
* this via the gps-enable alias.
*
* GPIO33-37 are the octal-PSRAM pads on ESP32-S3 modules that carry one;
* the V4 has 2 MB *quad* PSRAM, so 33/34 are free here — 35/36/37 are
* already spent on LED/Vext/ADC-ctrl above, which is the same evidence. */
gps_en: gps-enable {
compatible = "gpio-leds";
gps_enable_pin: gps_enable {
gpios = <&gpio1 2 GPIO_ACTIVE_LOW>; /* GPIO34 = gpio1 pin 2 */
label = "GPS Enable";
};
};
/* GPS reset — GPIO42, active-LOW (Arduino PIN_GPS_RESET=42,
* PIN_GPS_RESET_ACTIVE=LOW). Declared so the line is always driven to a
* defined level rather than left floating into the module's reset input.
*
* Declaring gps-reset moves this board onto the manager's
* HAS_T1000_GPS_CONTROL power sequence (EN -> reset -> release). That is
* safe without a VRTC pin — every VRTC/SLEEP step in that path is behind
* its own #if. Note the power-ON pulse uses the raw GPIO_OUTPUT_HIGH flag,
* so on an active-LOW line it de-asserts rather than pulsing; the useful
* half is power-OFF, which asserts reset (logical 1) and holds the module
* down while its supply is gated. */
gps_rst: gps-reset {
compatible = "gpio-leds";
gps_reset_pin: gps_reset {
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* GPIO42 = gpio1 pin 10 */
label = "GPS Reset";
};
};
aliases {
gps-enable = &gps_enable_pin;
gps-reset = &gps_reset_pin;
};
/* Button chain — same mapping as RAK4631 / WisMesh Pocket (rak4631/board.overlay). */
user_btn_longpress {
compatible = "zephyr,input-longpress";
@@ -77,6 +118,41 @@
rx-boosted;
};
/* GPS on UART1 — optional external NMEA module on the pin header, wired to the
* same pins Arduino MeshCore uses for this board (PIN_GPS_RX=38, PIN_GPS_TX=39;
* Arduino names them from the MCU's point of view, so RX=38 is the MCU input).
* Upstream leaves uart1 disabled and gives it no pinctrl, so both are set here.
* GPIO38/39 are otherwise unclaimed on the V4; the console stays on usb_serial
* (or uart0/GPIO43-44 for companion USB builds). 9600 baud matches Arduino's
* default for this variant.
*
* The node is unconditional, like the V3's gnss node for its optional module:
* with nothing fitted the driver simply never sees a fix. */
&pinctrl {
uart1_default: uart1_default {
group1 {
pinmux = <UART1_TX_GPIO39>;
output-high;
};
group2 {
pinmux = <UART1_RX_GPIO38>;
bias-pull-up;
};
};
};
&uart1 {
status = "okay";
current-speed = <9600>;
pinctrl-0 = <&uart1_default>;
pinctrl-names = "default";
gnss: gnss-nmea-generic {
compatible = "gnss-nmea-generic";
};
};
/* I2C sensors — auto-detected at runtime */
&i2c0 {
#include "../../common/sensors-i2c.dtsi"