Add Heltec tower v2 board. (#10693)

* Add heltec_mesh_tower_v2 board.

* Added automatic detection for high and low power versions.

* Fix low power consumption issues
This commit is contained in:
Quency-D
2026-06-18 07:07:50 -05:00
committed by GitHub
co-authored by GitHub
parent 79a7dcc46c
commit 68af6b277c
8 changed files with 338 additions and 1 deletions
+54
View File
@@ -0,0 +1,54 @@
{
"build": {
"arduino": {
"ldscript": "nrf52840_s140_v6.ld"
},
"core": "nRF5",
"cpu": "cortex-m4",
"extra_flags": "-DNRF52840_XXAA",
"f_cpu": "64000000L",
"hwids": [
["0x239A", "0x4405"],
["0x239A", "0x0029"],
["0x239A", "0x002A"],
["0x239A", "0x0071"]
],
"usb_product": "HT-n5262",
"mcu": "nrf52840",
"variant": "heltec_mesh_tower_v2",
"variants_dir": "variants",
"bsp": {
"name": "adafruit"
},
"softdevice": {
"sd_flags": "-DS140",
"sd_name": "s140",
"sd_version": "6.1.1",
"sd_fwid": "0x00B6"
},
"bootloader": {
"settings_addr": "0xFF000"
}
},
"connectivity": ["bluetooth"],
"debug": {
"jlink_device": "nRF52840_xxAA",
"onboard_tools": ["jlink"],
"svd_path": "nrf52840.svd",
"openocd_target": "nrf52840-mdk-rs"
},
"frameworks": ["arduino"],
"name": "Heltec MeshTower V2 (Adafruit BSP)",
"upload": {
"maximum_ram_size": 248832,
"maximum_size": 815104,
"speed": 115200,
"protocol": "nrfutil",
"protocols": ["jlink", "nrfjprog", "nrfutil", "stlink"],
"use_1200bps_touch": true,
"require_upload_port": true,
"wait_for_upload_port": true
},
"url": "https://heltec.org",
"vendor": "Heltec"
}
+7
View File
@@ -179,6 +179,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif
#endif
#ifdef USE_KCT8103L_PA_ONLY
#if defined(HELTEC_MESH_TOWER_V2)
#define NUM_PA_POINTS 22
#define TX_GAIN_LORA 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 8, 7
#endif
#endif
#ifdef RAK13302
#define NUM_PA_POINTS 22
#define TX_GAIN_LORA 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8
+29
View File
@@ -57,6 +57,11 @@ static void releaseSleepHolds()
void LoRaFEMInterface::init(void)
{
setLnaCanControl(false); // Default is uncontrollable
#if defined(RF_PA_DETECT_PIN)
pinMode(RF_PA_DETECT_PIN, INPUT);
high_power_pa = (digitalRead(RF_PA_DETECT_PIN) == RF_PA_HIGH_POWER_VALUE);
LOG_INFO("Detected %s LoRa PA profile", high_power_pa ? "high-power" : "low-power");
#endif
#ifdef HELTEC_V4
pinMode(LORA_PA_POWER, OUTPUT);
digitalWrite(LORA_PA_POWER, HIGH);
@@ -119,6 +124,13 @@ void LoRaFEMInterface::init(void)
pinMode(LORA_KCT8103L_PA_CTX, OUTPUT);
digitalWrite(LORA_KCT8103L_PA_CTX, LOW); // LNA enabled by default
setLnaCanControl(true);
#elif defined(USE_KCT8103L_PA_ONLY)
fem_type = KCT8103L_PA;
pinMode(LORA_KCT8103L_EN, OUTPUT);
digitalWrite(LORA_KCT8103L_EN, HIGH);
delay(1);
pinMode(LORA_KCT8103L_TX_RX, OUTPUT);
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
#endif
}
@@ -148,6 +160,9 @@ void LoRaFEMInterface::setSleepModeEnable(void)
// shutdown the PA
digitalWrite(LORA_KCT8103L_PA_CSD, LOW);
digitalWrite(LORA_PA_POWER, LOW);
#elif defined(USE_KCT8103L_PA_ONLY)
// shutdown the PA
digitalWrite(LORA_KCT8103L_EN, LOW);
#endif
}
@@ -173,6 +188,9 @@ void LoRaFEMInterface::setTxModeEnable(void)
enableFEMPower();
digitalWrite(LORA_KCT8103L_PA_CSD, HIGH);
digitalWrite(LORA_KCT8103L_PA_CTX, HIGH);
#elif defined(USE_KCT8103L_PA_ONLY)
enableFEMPower();
digitalWrite(LORA_KCT8103L_TX_RX, HIGH);
#endif
}
@@ -206,6 +224,9 @@ void LoRaFEMInterface::setRxModeEnable(void)
} else {
digitalWrite(LORA_KCT8103L_PA_CTX, HIGH);
}
#elif defined(USE_KCT8103L_PA_ONLY)
enableFEMPower();
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
#endif
}
@@ -247,6 +268,9 @@ void LoRaFEMInterface::setRxModeEnableWhenMCUSleep(void)
rtc_gpio_hold_en((gpio_num_t)LORA_KCT8103L_PA_CSD);
rtc_gpio_hold_en((gpio_num_t)LORA_KCT8103L_PA_CTX);
#endif
#elif defined(USE_KCT8103L_PA_ONLY)
enableFEMPower();
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
#endif
}
@@ -257,6 +281,11 @@ void LoRaFEMInterface::setLNAEnable(bool enabled)
int8_t LoRaFEMInterface::powerConversion(int8_t loraOutputPower)
{
#if defined(RF_PA_DETECT_PIN)
if (!high_power_pa) {
return loraOutputPower;
}
#endif
#ifdef HELTEC_V4
const uint16_t gc1109_tx_gain[] = {11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7};
const uint16_t kct8103l_tx_gain[] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7};
+2 -1
View File
@@ -24,7 +24,8 @@ class LoRaFEMInterface
LoRaFEMType fem_type;
bool lna_enabled = true;
bool lna_can_control = false;
bool high_power_pa = true;
};
extern LoRaFEMInterface loraFEMInterface;
#endif
#endif
+2
View File
@@ -137,6 +137,8 @@
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_SOLAR
#elif defined(MUZI_BASE)
#define HW_VENDOR meshtastic_HardwareModel_MUZI_BASE
#elif defined(HELTEC_MESH_TOWER_V2)
#define HW_VENDOR meshtastic_HardwareModel_HELTEC_MESH_TOWER_V2
#else
#define HW_VENDOR meshtastic_HardwareModel_NRF52_UNKNOWN
#endif
@@ -0,0 +1,27 @@
; Heltec MeshTower V2 nrf52840/sx1262 device
[env:heltec-mesh-tower-v2]
custom_meshtastic_hw_model = 139
custom_meshtastic_hw_model_slug = HELTEC_MESH_TOWER_V2
custom_meshtastic_architecture = nrf52840
custom_meshtastic_actively_supported = false
custom_meshtastic_support_level = 1
custom_meshtastic_display_name = Heltec MeshTower V2
custom_meshtastic_images = heltec-mesh-tower-v2.svg
custom_meshtastic_tags = Heltec
extends = nrf52840_base
board = heltec_mesh_tower_v2
board_level = pr
debug_tool = jlink
# add -DCFG_SYSVIEW if you want to use the Segger systemview tool for OS profiling.
build_flags = ${nrf52840_base.build_flags}
-Ivariants/nrf52840/heltec_mesh_tower_v2
-DHELTEC_MESH_TOWER_V2
-D HAS_LORA_FEM=1
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/nrf52840/heltec_mesh_tower_v2>
lib_deps =
${nrf52840_base.lib_deps}
# renovate: datasource=custom.pio depName=ArduinoJson packageName=bblanchon/library/ArduinoJson
bblanchon/ArduinoJson@6.21.6
@@ -0,0 +1,61 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "variant.h"
#include "Arduino.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// P0 - pins 0 and 1 are hardwired for xtal and should never be enabled
0xff, 0xff, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
// P1
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47};
void initVariant()
{
}
void variant_shutdown()
{
nrf_gpio_cfg_default(PIN_GPS_EN);
nrf_gpio_cfg_default(PIN_GPS_PPS);
nrf_gpio_cfg_default(PIN_GPS_RESET);
nrf_gpio_cfg_default(PIN_GPS_STANDBY);
nrf_gpio_cfg_default(GPS_RX_PIN);
nrf_gpio_cfg_default(GPS_TX_PIN);
nrf_gpio_cfg_default(ADC_CTRL);
pinMode(LORA_KCT8103L_EN, OUTPUT);
digitalWrite(LORA_KCT8103L_EN, LOW);
nrf_gpio_cfg_default(LORA_KCT8103L_TX_RX);
nrf_gpio_cfg_default(RF_PA_DETECT_PIN);
nrf_gpio_cfg_default(SX126X_CS);
nrf_gpio_cfg_default(SX126X_DIO1);
nrf_gpio_cfg_default(SX126X_BUSY);
nrf_gpio_cfg_default(SX126X_RESET);
nrf_gpio_cfg_default(PIN_SPI_MISO);
nrf_gpio_cfg_default(PIN_SPI_MOSI);
nrf_gpio_cfg_default(PIN_SPI_SCK);
detachInterrupt(PIN_GPS_PPS);
detachInterrupt(PIN_BUTTON1);
}
@@ -0,0 +1,156 @@
/*
Copyright (c) 2014-2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2018, Adafruit Industries (adafruit.com)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _VARIANT_HELTEC_NRF_
#define _VARIANT_HELTEC_NRF_
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// Number of pins defined in PinDescription array
#define PINS_COUNT (48)
#define NUM_DIGITAL_PINS (48)
#define NUM_ANALOG_INPUTS (1)
#define NUM_ANALOG_OUTPUTS (0)
#define PIN_LED1 (32 + 15) // green
#define LED_BLUE PIN_LED1 // fake for bluefruit library
#define LED_GREEN PIN_LED1
#define LED_STATE_ON 0 // State when LED is lit
/*
* Buttons
*/
#define PIN_BUTTON1 (32 + 10) // P1.10, MCU_USER
/*
No longer populated on PCB
*/
#define PIN_SERIAL2_RX (-1)
#define PIN_SERIAL2_TX (-1)
/*
* I2C
*/
#define WIRE_INTERFACES_COUNT 1
// I2C bus 0, routed to HUSB238 USB PD sink controller.
#define PIN_WIRE_SDA (0 + 30) // P0.30, PD_SINK_SDA
#define PIN_WIRE_SCL (0 + 5) // P0.05, PD_SINK_SCL
/*
* Lora radio
*/
#define USE_SX1262
#define SX126X_CS (0 + 24)
#define LORA_CS SX126X_CS
#define SX126X_DIO1 (0 + 20)
#define SX126X_BUSY (0 + 17)
#define SX126X_RESET (0 + 25)
#define SX126X_DIO2_AS_RF_SWITCH
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
#define USE_KCT8103L_PA_ONLY
#define LORA_KCT8103L_EN (0 + 15) // CSD - KCT8103L chip enable (HIGH=on)
#define LORA_KCT8103L_TX_RX (0 + 16) // TX or bypass control (HIGH=TX, LOW=RX)
#define LORA_PA_POWER LORA_KCT8103L_EN
#define RF_PA_DETECT_PIN (0 + 13) // HIGH=high-power PA, LOW=low-power
#define RF_PA_HIGH_POWER_VALUE HIGH
/*
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 1
// For LORA, spi 0
#define PIN_SPI_MISO (0 + 23)
#define PIN_SPI_MOSI (0 + 22)
#define PIN_SPI_SCK (0 + 19)
/*
* GPS pins
*/
#define GPS_L76K
#define PIN_GPS_RESET (32 + 6)
#define GPS_RESET_MODE LOW
#define PIN_GPS_EN (0 + 7) // P0.07, VGNSS_Ctrl
#define GPS_EN_ACTIVE LOW
#define PERIPHERAL_WARMUP_MS 1000 // Make sure GNSS power is stable before continuing
#define PIN_GPS_STANDBY (32 + 2) // P1.02, WAKE_UP. Low allows sleep, high forces wake.
#define PIN_GPS_PPS (32 + 4) // P1.04, 1PPS
#define GPS_RX_PIN (32 + 5) // P1.05, MCU RX connected to GPS TXD.
#define GPS_TX_PIN (32 + 7) // P1.07, MCU TX connected to GPS RXD.
#define GPS_THREAD_INTERVAL 50
#define PIN_SERIAL1_RX GPS_RX_PIN
#define PIN_SERIAL1_TX GPS_TX_PIN
// Hardware watchdog
#define HAS_HARDWARE_WATCHDOG
#define HARDWARE_WATCHDOG_DONE (0 + 9)
#define HARDWARE_WATCHDOG_WAKE (0 + 10)
#define HARDWARE_WATCHDOG_TIMEOUT_MS (6 * 60 * 1000) // 6 minute watchdog
#define SERIAL_PRINT_PORT 0
#define ADC_CTRL (0 + 21) // P0.21, ADC_Ctrl
#define ADC_CTRL_ENABLED HIGH
#define BATTERY_PIN (0 + 4) // P0.04, ADC_IN
#define ADC_RESOLUTION 14
#define BATTERY_SENSE_RESOLUTION_BITS 12
#define BATTERY_SENSE_RESOLUTION 4096.0
#undef AREF_VOLTAGE
#define AREF_VOLTAGE 3.0
#define VBAT_AR_INTERNAL AR_INTERNAL_3_0
#define ADC_MULTIPLIER (4.916F)
// nRF52840 AIN2 is P0.04 on the MeshTower V2 battery divider.
#define BATTERY_LPCOMP_INPUT NRF_LPCOMP_INPUT_2
// We have AIN2 with a VBAT divider so AIN2 = VBAT * (100/490)
// We have the device going deep sleep under 3.1V, which is AIN2 = 0.63V
// So we can wake up when VBAT>=VDD is restored to 3.3V, where AIN2 = 0.67V
// Ratio 0.67/3.3 = 0.20, so we can pick a bit higher, 2/8 VDD, which means
// VBAT=4.04V
#define BATTERY_LPCOMP_THRESHOLD NRF_LPCOMP_REF_SUPPLY_2_8
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif