Skip to content

Commit 3192684

Browse files
authored
Merge pull request #2752 from Quency-D/heltec-tower-v2
Add Heltec tower v2
2 parents aa1cb1f + 1c4c995 commit 3192684

10 files changed

Lines changed: 554 additions & 0 deletions

File tree

boards/heltec_tower_v2.json

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
{
2+
"build": {
3+
"arduino": {
4+
"ldscript": "nrf52840_s140_v6.ld"
5+
},
6+
"core": "nRF5",
7+
"cpu": "cortex-m4",
8+
"extra_flags": "-DNRF52840_XXAA",
9+
"f_cpu": "64000000L",
10+
"hwids": [
11+
["0x239A","0x4405"],
12+
["0x239A","0x0029"],
13+
["0x239A","0x002A"],
14+
["0x239A","0x0071"]
15+
],
16+
"usb_product": "HT-n5262",
17+
"mcu": "nrf52840",
18+
"variant": "heltec_tower_v2",
19+
"bsp": {
20+
"name": "adafruit"
21+
},
22+
"softdevice": {
23+
"sd_flags": "-DS140",
24+
"sd_name": "s140",
25+
"sd_version": "6.1.1",
26+
"sd_fwid": "0x00B6"
27+
},
28+
"bootloader": {
29+
"settings_addr": "0xFF000"
30+
}
31+
},
32+
"connectivity": [
33+
"bluetooth"
34+
],
35+
"debug": {
36+
"jlink_device": "nRF52840_xxAA",
37+
"svd_path": "nrf52840.svd",
38+
"openocd_target": "nrf52.cfg"
39+
},
40+
"frameworks": [
41+
"arduino"
42+
],
43+
"name": "Heltec Tower V2 Board",
44+
"upload": {
45+
"maximum_ram_size": 235520,
46+
"maximum_size": 815104,
47+
"speed": 115200,
48+
"protocol": "nrfutil",
49+
"protocols": [
50+
"jlink",
51+
"nrfjprog",
52+
"nrfutil",
53+
"stlink"
54+
],
55+
"use_1200bps_touch": true,
56+
"require_upload_port": true,
57+
"wait_for_upload_port": true
58+
},
59+
"url": "https://heltec.org/",
60+
"vendor": "Heltec"
61+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#include "HeltecTowerV2Board.h"
2+
3+
#include <Arduino.h>
4+
#include <Wire.h>
5+
6+
extern void variant_shutdown();
7+
8+
#ifdef NRF52_POWER_MANAGEMENT
9+
const PowerMgtConfig power_config = {
10+
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
11+
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
12+
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
13+
};
14+
15+
void HeltecTowerV2Board::initiateShutdown(uint8_t reason) {
16+
pinMode(PIN_GPS_EN, OUTPUT);
17+
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
18+
pinMode(PIN_GPS_STANDBY, OUTPUT);
19+
digitalWrite(PIN_GPS_STANDBY, LOW);
20+
pinMode(PIN_GPS_RESET, OUTPUT);
21+
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
22+
loRaFEMControl.setSleepModeEnable();
23+
24+
bool enable_lpcomp = (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
25+
reason == SHUTDOWN_REASON_BOOT_PROTECT);
26+
pinMode(PIN_BAT_CTL, OUTPUT);
27+
digitalWrite(PIN_BAT_CTL, enable_lpcomp ? HIGH : LOW);
28+
29+
if (enable_lpcomp) {
30+
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
31+
}
32+
33+
variant_shutdown();
34+
enterSystemOff(reason);
35+
}
36+
#endif
37+
38+
void HeltecTowerV2Board::begin() {
39+
NRF52Board::begin();
40+
41+
pinMode(P_LORA_TX_LED, OUTPUT);
42+
digitalWrite(P_LORA_TX_LED, !LED_STATE_ON);
43+
44+
pinMode(PIN_BAT_CTL, OUTPUT);
45+
digitalWrite(PIN_BAT_CTL, LOW);
46+
47+
#ifdef NRF52_POWER_MANAGEMENT
48+
checkBootVoltage(&power_config);
49+
#endif
50+
51+
Wire.setPins(PIN_BOARD_SDA, PIN_BOARD_SCL);
52+
Wire.begin();
53+
54+
pinMode(PIN_GPS_EN, OUTPUT);
55+
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
56+
pinMode(PIN_GPS_RESET, OUTPUT);
57+
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
58+
pinMode(PIN_GPS_STANDBY, OUTPUT);
59+
digitalWrite(PIN_GPS_STANDBY, HIGH);
60+
loRaFEMControl.init();
61+
}
62+
63+
void HeltecTowerV2Board::onBeforeTransmit() {
64+
digitalWrite(P_LORA_TX_LED, LED_STATE_ON);
65+
loRaFEMControl.setTxModeEnable();
66+
}
67+
68+
void HeltecTowerV2Board::onAfterTransmit() {
69+
digitalWrite(P_LORA_TX_LED, !LED_STATE_ON);
70+
loRaFEMControl.setRxModeEnable();
71+
}
72+
73+
uint16_t HeltecTowerV2Board::getBattMilliVolts() {
74+
analogReadResolution(12);
75+
analogReference(VBAT_AR_INTERNAL);
76+
pinMode(PIN_VBAT_READ, INPUT);
77+
pinMode(PIN_BAT_CTL, OUTPUT);
78+
digitalWrite(PIN_BAT_CTL, HIGH);
79+
80+
delay(10);
81+
int adcvalue = analogRead(PIN_VBAT_READ);
82+
digitalWrite(PIN_BAT_CTL, LOW);
83+
84+
return (uint16_t)((float)adcvalue * MV_LSB * ADC_MULTIPLIER);
85+
}
86+
87+
const char* HeltecTowerV2Board::getManufacturerName() const {
88+
return "Heltec Tower V2";
89+
}
90+
91+
void HeltecTowerV2Board::powerOff() {
92+
pinMode(PIN_GPS_EN, OUTPUT);
93+
digitalWrite(PIN_GPS_EN, !PIN_GPS_EN_ACTIVE);
94+
pinMode(PIN_GPS_STANDBY, OUTPUT);
95+
digitalWrite(PIN_GPS_STANDBY, LOW);
96+
pinMode(PIN_GPS_RESET, OUTPUT);
97+
digitalWrite(PIN_GPS_RESET, GPS_RESET_MODE);
98+
loRaFEMControl.setSleepModeEnable();
99+
pinMode(PIN_BAT_CTL, OUTPUT);
100+
digitalWrite(PIN_BAT_CTL, LOW);
101+
variant_shutdown();
102+
sd_power_system_off();
103+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <Arduino.h>
4+
#include <MeshCore.h>
5+
#include <helpers/NRF52Board.h>
6+
#include "LoRaFEMControl.h"
7+
8+
class HeltecTowerV2Board : public NRF52BoardDCDC {
9+
protected:
10+
#ifdef NRF52_POWER_MANAGEMENT
11+
void initiateShutdown(uint8_t reason) override;
12+
#endif
13+
14+
public:
15+
LoRaFEMControl loRaFEMControl;
16+
17+
HeltecTowerV2Board() : NRF52Board("TOWER_V2_OTA") {}
18+
void begin();
19+
void onBeforeTransmit() override;
20+
void onAfterTransmit() override;
21+
uint16_t getBattMilliVolts() override;
22+
const char* getManufacturerName() const override;
23+
void powerOff() override;
24+
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include "LoRaFEMControl.h"
2+
3+
#include <Arduino.h>
4+
#include "variant.h"
5+
6+
static void enableFEMPower() {
7+
bool wasOff = digitalRead(LORA_KCT8103L_EN) != HIGH;
8+
digitalWrite(LORA_KCT8103L_EN, HIGH);
9+
if (wasOff) {
10+
delay(5);
11+
}
12+
}
13+
14+
void LoRaFEMControl::init() {
15+
pinMode(LORA_KCT8103L_EN, OUTPUT);
16+
digitalWrite(LORA_KCT8103L_EN, HIGH);
17+
delay(1);
18+
pinMode(LORA_KCT8103L_TX_RX, OUTPUT);
19+
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
20+
}
21+
22+
void LoRaFEMControl::setSleepModeEnable() {
23+
pinMode(LORA_KCT8103L_EN, OUTPUT);
24+
digitalWrite(LORA_KCT8103L_EN, LOW);
25+
}
26+
27+
void LoRaFEMControl::setTxModeEnable() {
28+
enableFEMPower();
29+
digitalWrite(LORA_KCT8103L_TX_RX, HIGH);
30+
}
31+
32+
void LoRaFEMControl::setRxModeEnable() {
33+
enableFEMPower();
34+
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
35+
}
36+
37+
void LoRaFEMControl::setRxModeEnableWhenMCUSleep() {
38+
enableFEMPower();
39+
digitalWrite(LORA_KCT8103L_TX_RX, LOW);
40+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
3+
class LoRaFEMControl {
4+
public:
5+
LoRaFEMControl() {}
6+
virtual ~LoRaFEMControl() {}
7+
8+
void init();
9+
void setSleepModeEnable();
10+
void setTxModeEnable();
11+
void setRxModeEnable();
12+
void setRxModeEnableWhenMCUSleep();
13+
};
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
[Heltec_tower_v2]
2+
extends = nrf52_base
3+
board = heltec_tower_v2
4+
board_build.ldscript = boards/nrf52840_s140_v6.ld
5+
build_flags = ${nrf52_base.build_flags}
6+
-D ENV_INCLUDE_GPS=1
7+
-I lib/nrf52/s140_nrf52_6.1.1_API/include
8+
-I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52
9+
-I variants/heltec_tower_v2
10+
-D HELTEC_TOWER_V2
11+
-D NRF52_POWER_MANAGEMENT
12+
-D RADIO_CLASS=CustomSX1262
13+
-D WRAPPER_CLASS=CustomSX1262Wrapper
14+
-D LORA_TX_POWER=12
15+
-D MAX_LORA_TX_POWER=22 ; Max SX1262 output -> ~29dBm at antenna
16+
-D SX126X_CURRENT_LIMIT=140
17+
-D SX126X_RX_BOOSTED_GAIN=1
18+
build_src_filter = ${nrf52_base.build_src_filter}
19+
+<helpers/*.cpp>
20+
+<helpers/sensors>
21+
+<../variants/heltec_tower_v2>
22+
lib_deps =
23+
${nrf52_base.lib_deps}
24+
stevemarple/MicroNMEA @ ^2.0.6
25+
debug_tool = jlink
26+
upload_protocol = nrfutil
27+
28+
[env:Heltec_tower_v2_repeater]
29+
extends = Heltec_tower_v2
30+
build_src_filter = ${Heltec_tower_v2.build_src_filter}
31+
+<../examples/simple_repeater>
32+
build_flags =
33+
${Heltec_tower_v2.build_flags}
34+
-D ADVERT_NAME='"Heltec_Tower_V2 Repeater"'
35+
-D ADVERT_LAT=0.0
36+
-D ADVERT_LON=0.0
37+
-D ADMIN_PASSWORD='"password"'
38+
-D MAX_NEIGHBOURS=50
39+
; -D MESH_PACKET_LOGGING=1
40+
; -D MESH_DEBUG=1
41+
42+
[env:Heltec_tower_v2_room_server]
43+
extends = Heltec_tower_v2
44+
build_src_filter = ${Heltec_tower_v2.build_src_filter}
45+
+<../examples/simple_room_server>
46+
build_flags =
47+
${Heltec_tower_v2.build_flags}
48+
-D ADVERT_NAME='"Heltec_Tower_V2 Room"'
49+
-D ADVERT_LAT=0.0
50+
-D ADVERT_LON=0.0
51+
-D ADMIN_PASSWORD='"password"'
52+
-D ROOM_PASSWORD='"hello"'
53+
; -D MESH_PACKET_LOGGING=1
54+
; -D MESH_DEBUG=1
55+
56+
[env:Heltec_tower_v2_companion_radio_ble]
57+
extends = Heltec_tower_v2
58+
board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
59+
board_upload.maximum_size = 712704
60+
build_flags =
61+
${Heltec_tower_v2.build_flags}
62+
-I examples/companion_radio/ui-new
63+
-D DISPLAY_CLASS=NullDisplayDriver
64+
-D MAX_CONTACTS=350
65+
-D MAX_GROUP_CHANNELS=40
66+
-D BLE_PIN_CODE=123456
67+
; -D BLE_DEBUG_LOGGING=1
68+
-D OFFLINE_QUEUE_SIZE=256
69+
; -D MESH_PACKET_LOGGING=1
70+
; -D MESH_DEBUG=1
71+
build_src_filter = ${Heltec_tower_v2.build_src_filter}
72+
+<helpers/nrf52/SerialBLEInterface.cpp>
73+
+<../examples/companion_radio/*.cpp>
74+
+<../examples/companion_radio/ui-new/*.cpp>
75+
lib_deps =
76+
${Heltec_tower_v2.lib_deps}
77+
densaugeo/base64 @ ~1.4.0
78+
79+
[env:Heltec_tower_v2_companion_radio_usb]
80+
extends = Heltec_tower_v2
81+
board_build.ldscript = boards/nrf52840_s140_v6_extrafs.ld
82+
board_upload.maximum_size = 712704
83+
build_flags =
84+
${Heltec_tower_v2.build_flags}
85+
-I examples/companion_radio/ui-new
86+
-D DISPLAY_CLASS=NullDisplayDriver
87+
-D MAX_CONTACTS=350
88+
-D MAX_GROUP_CHANNELS=40
89+
; -D BLE_PIN_CODE=123456
90+
; -D BLE_DEBUG_LOGGING=1
91+
; -D MESH_PACKET_LOGGING=1
92+
; -D MESH_DEBUG=1
93+
build_src_filter = ${Heltec_tower_v2.build_src_filter}
94+
+<helpers/nrf52/*.cpp>
95+
+<../examples/companion_radio/*.cpp>
96+
+<../examples/companion_radio/ui-new/*.cpp>
97+
lib_deps =
98+
${Heltec_tower_v2.lib_deps}
99+
densaugeo/base64 @ ~1.4.0
100+
101+
[env:Heltec_tower_v2_kiss_modem]
102+
extends = Heltec_tower_v2
103+
build_src_filter = ${Heltec_tower_v2.build_src_filter}
104+
+<../examples/kiss_modem/>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include "target.h"
2+
3+
#include <Arduino.h>
4+
#include <helpers/ArduinoHelpers.h>
5+
#include <helpers/sensors/MicroNMEALocationProvider.h>
6+
7+
HeltecTowerV2Board board;
8+
9+
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
10+
11+
WRAPPER_CLASS radio_driver(radio, board);
12+
13+
VolatileRTCClock fallback_clock;
14+
AutoDiscoverRTCClock rtc_clock(fallback_clock);
15+
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock);
16+
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
17+
18+
#ifdef DISPLAY_CLASS
19+
DISPLAY_CLASS display;
20+
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
21+
#endif
22+
23+
bool radio_init() {
24+
rtc_clock.begin(Wire);
25+
return radio.std_init(&SPI);
26+
}
27+
28+
mesh::LocalIdentity radio_new_identity() {
29+
RadioNoiseListener rng(radio);
30+
return mesh::LocalIdentity(&rng);
31+
}

0 commit comments

Comments
 (0)