mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-01 23:08:19 +00:00
initial port of heltec v4 and v4.3 boards
This commit is contained in:
@@ -187,7 +187,7 @@ if(BOARD MATCHES ".*nrf52.*" OR BOARD MATCHES "rak4631" OR BOARD MATCHES "rak_wi
|
||||
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/nrf52_common.conf")
|
||||
elseif(DEFINED BOARD_QUALIFIERS AND BOARD_QUALIFIERS MATCHES ".*nrf52.*")
|
||||
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/nrf52_common.conf")
|
||||
elseif(BOARD MATCHES ".*esp32.*" OR BOARD MATCHES "station_g2" OR BOARD MATCHES "lilygo_tlora_c6" OR BOARD MATCHES "heltec_wifi_lora32_v3")
|
||||
elseif(BOARD MATCHES ".*esp32.*" OR BOARD MATCHES "station_g2" OR BOARD MATCHES "lilygo_tlora_c6" OR BOARD MATCHES "heltec_wifi_lora32_v3" OR BOARD MATCHES "heltec_wifi_lora32_v4")
|
||||
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/esp32_common.conf")
|
||||
elseif(DEFINED BOARD_QUALIFIERS AND BOARD_QUALIFIERS MATCHES ".*esp32.*")
|
||||
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/esp32_common.conf")
|
||||
|
||||
@@ -305,6 +305,16 @@ config ZEPHCORE_MAX_TX_POWER_DBM
|
||||
above this, protecting external PAs from damage.
|
||||
Example: Station G2 caps at 19 dBm to stay below PA P1dB (35 dBm).
|
||||
|
||||
config ZEPHCORE_SX126X_HELTEC_REG_PATCH
|
||||
bool "Apply undocumented SX126x register 0x8B5 RX improvement (Heltec V4)"
|
||||
depends on ZEPHCORE_RADIO_NATIVE
|
||||
default n
|
||||
help
|
||||
Sets the LSB of undocumented register 0x8B5 after the first lora_config().
|
||||
Described by Heltec engineer @Quency-D in MeshCore PR#1398 — consistently
|
||||
improves RX reception on boards with GC1109 or KCT8103L PA (Heltec V4/V4.3).
|
||||
Enable in board.conf for Heltec V4 boards.
|
||||
|
||||
endmenu # Radio Configuration
|
||||
|
||||
menu "Board Configuration"
|
||||
|
||||
@@ -29,6 +29,13 @@ void SX126xRadio::begin()
|
||||
startTxThread(sx126x_tx_wait_stack,
|
||||
K_THREAD_STACK_SIZEOF(sx126x_tx_wait_stack));
|
||||
LoRaRadioBase::begin();
|
||||
|
||||
#if IS_ENABLED(CONFIG_ZEPHCORE_SX126X_HELTEC_REG_PATCH)
|
||||
/* Apply undocumented register 0x8B5 RX improvement (MeshCore PR#1398).
|
||||
* Must run after lora_config() has been called (via startReceive above). */
|
||||
sx126x_apply_heltec_reg_patch(_dev);
|
||||
LOG_INF("Applied Heltec reg 0x8B5 RX patch");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ── Hardware primitives ──────────────────────────────────────────────── */
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
config HEAP_MEM_POOL_ADD_SIZE_BOARD
|
||||
int
|
||||
default 4096
|
||||
@@ -0,0 +1,3 @@
|
||||
config BOARD_HELTEC_WIFI_LORA32_V4
|
||||
select SOC_ESP32S3_WROOM_N16R2
|
||||
select SOC_ESP32S3_PROCPU if BOARD_HELTEC_WIFI_LORA32_V4_ESP32S3_PROCPU
|
||||
@@ -0,0 +1,7 @@
|
||||
if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*")
|
||||
set(OPENOCD OPENOCD-NOTFOUND)
|
||||
endif()
|
||||
find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH)
|
||||
|
||||
include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
|
||||
@@ -0,0 +1,25 @@
|
||||
# Heltec WiFi LoRa 32 V4 — ESP32-S3, 16 MB flash, 2 MB QSPI PSRAM
|
||||
#
|
||||
# Hardware:
|
||||
# SX1262 + GC1109 external PA (10 dBm in → ~22 dBm out)
|
||||
# SSD1306 128x64 OLED on I2C0
|
||||
# User button on GPIO0
|
||||
#
|
||||
# Include order: prj.conf → zephcore_common.conf → esp32_common.conf → board.conf
|
||||
|
||||
# Board identification
|
||||
CONFIG_ZEPHCORE_BOARD_NAME="Heltec V4"
|
||||
CONFIG_BT_DIS_MODEL_NUMBER_STR="Heltec WiFi LoRa 32 V4"
|
||||
|
||||
# Flash size — 16 MB (override esp32_common.conf 4 MB default)
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||
|
||||
# Undocumented register 0x8B5 RX improvement (MeshCore PR#1398)
|
||||
# Described by Heltec engineer @Quency-D — improves RX on GC1109/KCT8103L PA boards.
|
||||
CONFIG_ZEPHCORE_SX126X_HELTEC_REG_PATCH=y
|
||||
|
||||
# TX power — SX1262 input to GC1109 PA.
|
||||
# 10 dBm → ~22 dBm radiated output (GC1109 ~12 dB gain).
|
||||
# Do not exceed 10 dBm into the PA to avoid compression.
|
||||
CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=10
|
||||
CONFIG_ZEPHCORE_MAX_TX_POWER_DBM=10
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Heltec WiFi LoRa 32 V4 — ZephCore overlay
|
||||
*
|
||||
* The DTS already defines: SX1262 (lora0), SSD1306 OLED, button, LED, PWM,
|
||||
* vext_ctrl, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi.
|
||||
* This overlay adds ZephCore-specific integration on top.
|
||||
*
|
||||
* LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa ctrl: DIO1=14, BUSY=13, RESET=12
|
||||
* FEM: POWER=7, GC1109 CSD=2, CPS=46 (V4.2 — for V4.3/KCT8103L see heltec_wifi_lora32_v43)
|
||||
* Display I2C0: SDA=17, SCL=18, RST=21
|
||||
* Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K
|
||||
* Vext: GPIO36 (active-HIGH, powers OLED)
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
/* Native USB serial for ZephCore console/CLI */
|
||||
zephyr,console = &usb_serial;
|
||||
zephyr,shell-uart = &usb_serial;
|
||||
};
|
||||
|
||||
/* Battery ADC — ZephCore reads via zephyr,user { io-channels }.
|
||||
* Multiplier: 3300mV full-scale * 5.42x empirical divider = 17886 mV.
|
||||
* (Same as V3 — identical resistor divider topology.) */
|
||||
zephyr,user {
|
||||
io-channels = <&adc1 0>;
|
||||
vbat-mv-multiplier = <17886>;
|
||||
};
|
||||
|
||||
/* Battery ADC enable — ZephCore uses vbat_enable regulator alias.
|
||||
* GPIO37 (gpio1 pin 5) driven HIGH enables the ADC input path.
|
||||
* The DTS adc_ctrl node is power-domain-gpio which ZephCore doesn't use;
|
||||
* this regulator-fixed is the actual driver. */
|
||||
vbat_enable: vbat-enable {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vbat-enable";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5 */
|
||||
};
|
||||
|
||||
/* ---- Button input filter chain ----
|
||||
* Button emits INPUT_KEY_0. Split into:
|
||||
* short press → KEY_A (consumed by multi-tap)
|
||||
* long press (1 s) → KEY_POWER (deep sleep) */
|
||||
user_btn_longpress {
|
||||
compatible = "zephyr,input-longpress";
|
||||
input = <&buttons>;
|
||||
input-codes = <INPUT_KEY_0>;
|
||||
short-codes = <INPUT_KEY_A>;
|
||||
long-codes = <INPUT_KEY_POWER>;
|
||||
long-delay-ms = <1000>;
|
||||
};
|
||||
|
||||
/* Multi-tap decodes short presses:
|
||||
* 1 tap (400 ms wait) → KEY_1 = page next
|
||||
* 2 taps (400 ms wait) → KEY_B = flood advert
|
||||
* 3 taps (400 ms wait) → KEY_D = buzzer mute toggle
|
||||
* 4 taps (immediate) → KEY_C = GPS on/off */
|
||||
user_btn_multitap {
|
||||
compatible = "zephcore,input-multi-tap";
|
||||
/* No 'input' phandle — listen to ALL devices.
|
||||
* KEY_A is emitted by the longpress pseudo-device. */
|
||||
input-codes = <INPUT_KEY_A>;
|
||||
tap-codes = <INPUT_KEY_1 INPUT_KEY_B INPUT_KEY_D INPUT_KEY_C>;
|
||||
tap-delay-ms = <400>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Enable native USB serial for console/CLI */
|
||||
&usb_serial {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Patch LoRa radio: add pull-down on DIO1 and enable RX boosted mode.
|
||||
* DTS defines antenna-enable, tx-enable, dio2-tx-enable, and TCXO already. */
|
||||
&lora0 {
|
||||
dio1-gpios = <&gpio0 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
|
||||
rx-boosted;
|
||||
};
|
||||
|
||||
/* I2C sensors — auto-detected at runtime */
|
||||
&i2c0 {
|
||||
#include "../../common/sensors-i2c.dtsi"
|
||||
};
|
||||
|
||||
/*
|
||||
* Flash partitions — repartition 16 MB layout for ZephCore.
|
||||
* Delete lpcore slots, storage, scratch, and coredump to reclaim space.
|
||||
* Place LittleFS at 0xFA0000 - 0x1000000 (384 KB).
|
||||
*/
|
||||
/delete-node/ &slot0_lpcore_partition;
|
||||
/delete-node/ &slot1_lpcore_partition;
|
||||
/delete-node/ &storage_partition;
|
||||
/delete-node/ &scratch_partition;
|
||||
/delete-node/ &coredump_partition;
|
||||
|
||||
&flash0 {
|
||||
partitions {
|
||||
/* LittleFS 384 KB for DataStore + file-based BLE settings */
|
||||
lfs_partition: partition@fa0000 {
|
||||
label = "lfs";
|
||||
reg = <0xFA0000 0x60000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* LittleFS auto-mount — standard /lfs mount point */
|
||||
#include "../../common/filesystem.dtsi"
|
||||
@@ -0,0 +1,6 @@
|
||||
board:
|
||||
name: heltec_wifi_lora32_v4
|
||||
full_name: Heltec WiFi LoRa 32 V4
|
||||
vendor: heltec
|
||||
socs:
|
||||
- name: esp32s3
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Heltec WiFi LoRa 32 V4 — Pin Control Definitions
|
||||
*
|
||||
* Pin assignments (identical to V3):
|
||||
* UART0: TX=GPIO43, RX=GPIO44
|
||||
* I2C0: SDA=GPIO17, SCL=GPIO18 (SSD1306 OLED + sensors)
|
||||
* SPI2: SCLK=GPIO9, MOSI=GPIO10, MISO=GPIO11 (SX1262 LoRa)
|
||||
* LEDC0: CH0=GPIO35 (PWM LED)
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h>
|
||||
|
||||
&pinctrl {
|
||||
uart0_default: uart0_default {
|
||||
group1 {
|
||||
pinmux = <UART0_TX_GPIO43>;
|
||||
output-high;
|
||||
};
|
||||
group2 {
|
||||
pinmux = <UART0_RX_GPIO44>;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_default: i2c0_default {
|
||||
group1 {
|
||||
pinmux = <I2C0_SDA_GPIO17>,
|
||||
<I2C0_SCL_GPIO18>;
|
||||
drive-open-drain;
|
||||
};
|
||||
};
|
||||
|
||||
spim2_default: spim2_default {
|
||||
group1 {
|
||||
pinmux = <SPIM2_MISO_GPIO11>,
|
||||
<SPIM2_SCLK_GPIO9>;
|
||||
};
|
||||
group2 {
|
||||
pinmux = <SPIM2_MOSI_GPIO10>;
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
|
||||
ledc0_default: ledc0_default {
|
||||
group1 {
|
||||
pinmux = <LEDC_CH0_GPIO35>;
|
||||
output-enable;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Heltec WiFi LoRa 32 V4 — ZephCore procpu DTS
|
||||
*
|
||||
* Hardware:
|
||||
* MCU: ESP32-S3 (16 MB flash, 2 MB QSPI PSRAM)
|
||||
* Radio: SX1262 on SPI2, GC1109 external PA/FEM (V4.2)
|
||||
* OLED: SSD1306 128x64 on I2C0
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35 (PWM via LEDC0)
|
||||
* Vext: GPIO36 active-HIGH (powers OLED and sensors)
|
||||
* BatADC: GPIO1 (ADC1 ch0), enable GPIO37 active-LOW
|
||||
*
|
||||
* V4.2 (this file) — GC1109 PA, TX_EN on GPIO46.
|
||||
* V4.3 (KCT8103L PA, CTX on GPIO5) → see heltec_wifi_lora32_v43.
|
||||
*
|
||||
* Key V4 differences vs V3:
|
||||
* - 16 MB flash + 2 MB QSPI PSRAM (was 8 MB, no PSRAM)
|
||||
* - External PA/FEM (GC1109):
|
||||
* GPIO7 = VFEM_Ctrl LDO power (active-HIGH, always-on)
|
||||
* GPIO2 = GC1109 CSD (chip enable, active-HIGH)
|
||||
* GPIO46 = GC1109 CPS (TX mode select, active-HIGH)
|
||||
* - Vext control is active-HIGH (was active-LOW on V3)
|
||||
* - DIO2 used as RF switch alongside external FEM TX control
|
||||
*
|
||||
* LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa ctrl: DIO1=14, BUSY=13, RESET=12
|
||||
* FEM: POWER=7, CSD=2, CPS=46
|
||||
* Display I2C0: SDA=17, SCL=18, RST=21
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <espressif/esp32s3/esp32s3_wroom_n16r2.dtsi>
|
||||
#include "heltec_wifi_lora32_v4-pinctrl.dtsi"
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
#include <zephyr/dt-bindings/lora/sx126x.h>
|
||||
#include <espressif/partitions_0x0_amp_16M.dtsi>
|
||||
|
||||
/ {
|
||||
model = "Heltec WiFi LoRa 32 V4 PROCPU";
|
||||
compatible = "heltec,wifi-lora32-v4";
|
||||
|
||||
aliases {
|
||||
led0 = &led0;
|
||||
pwm-0 = &ledc0;
|
||||
pwm-led0 = &pwm_led_white;
|
||||
uart-0 = &uart0;
|
||||
i2c-0 = &i2c0;
|
||||
lora0 = &lora0;
|
||||
sw0 = &button0;
|
||||
watchdog0 = &wdt0;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led0: led {
|
||||
gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; /* GPIO35 = gpio1 pin 3 */
|
||||
label = "White LED";
|
||||
};
|
||||
};
|
||||
|
||||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
pwm_led_white: pwm_led_gpio35 {
|
||||
label = "White PWM LED";
|
||||
pwms = <&ledc0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
|
||||
};
|
||||
};
|
||||
|
||||
buttons: buttons {
|
||||
compatible = "gpio-keys";
|
||||
button0: button_0 {
|
||||
gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
|
||||
label = "USER Key";
|
||||
zephyr,code = <INPUT_KEY_0>;
|
||||
};
|
||||
};
|
||||
|
||||
vbatt {
|
||||
compatible = "voltage-divider";
|
||||
io-channels = <&adc1 0>; /* GPIO1 = ADC1 ch0 */
|
||||
output-ohms = <100000>;
|
||||
full-ohms = <(100000 + 390000)>;
|
||||
};
|
||||
|
||||
/* Vext — powers OLED and external peripherals.
|
||||
* V4 DIFFERENCE: active-HIGH (GPIO36 HIGH = power on).
|
||||
* V3 was active-LOW on the same GPIO. */
|
||||
vext_ctrl: vext_ctrl {
|
||||
compatible = "power-domain-gpio";
|
||||
enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; /* GPIO36 = gpio1 pin 4 */
|
||||
#power-domain-cells = <0>;
|
||||
label = "Vext Control";
|
||||
};
|
||||
|
||||
/* ADC enable — GPIO37 (gpio1 pin 5) must be driven HIGH to read battery.
|
||||
* ZephCore uses the vbat_enable regulator alias for this. */
|
||||
adc_ctrl: adc_ctrl {
|
||||
compatible = "power-domain-gpio";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5, active-LOW */
|
||||
#power-domain-cells = <0>;
|
||||
label = "ADC Control";
|
||||
};
|
||||
|
||||
/* FEM LDO power supply — GPIO7 powers the GC1109/KCT8103L LDO.
|
||||
* Must be HIGH before any radio operation. Keep always-on. */
|
||||
fem_power: fem-power {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "fem-power";
|
||||
enable-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; /* VFEM_Ctrl = GPIO7 */
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
chosen {
|
||||
zephyr,sram = &sram1;
|
||||
zephyr,console = &uart0;
|
||||
zephyr,shell-uart = &uart0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,code-partition = &slot0_partition;
|
||||
zephyr,bt-hci = &esp32_bt_hci;
|
||||
zephyr,display = &ssd1306_128x64;
|
||||
};
|
||||
};
|
||||
|
||||
&adc1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Reduce CPU clock from 240 MHz to 160 MHz — saves power, HAL minimum */
|
||||
&cpu0 {
|
||||
clock-frequency = <DT_FREQ_M(160)>;
|
||||
};
|
||||
|
||||
&cpu1 {
|
||||
clock-frequency = <DT_FREQ_M(160)>;
|
||||
};
|
||||
|
||||
&ledc0 {
|
||||
pinctrl-0 = <&ledc0_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel0@0 {
|
||||
reg = <0x0>;
|
||||
timer = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
clock-frequency = <I2C_BITRATE_FAST>;
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
ssd1306_128x64: display-controller@3c {
|
||||
compatible = "solomon,ssd1306";
|
||||
reg = <0x3c>;
|
||||
width = <128>;
|
||||
height = <64>;
|
||||
segment-offset = <0>;
|
||||
page-offset = <0>;
|
||||
display-offset = <0>;
|
||||
multiplex-ratio = <63>;
|
||||
segment-remap;
|
||||
com-invdir;
|
||||
inversion-on;
|
||||
prechargep = <0x22>;
|
||||
reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; /* RST_OLED = GPIO21 */
|
||||
power-domains = <&vext_ctrl>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spim2_default>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
cs-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; /* NSS = GPIO8 */
|
||||
|
||||
lora0: modem@0 {
|
||||
compatible = "semtech,sx1262";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio0 12 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; /* RESET = GPIO12 */
|
||||
busy-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; /* BUSY = GPIO13 */
|
||||
dio1-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; /* DIO1 = GPIO14 */
|
||||
|
||||
/* External PA/FEM control (GC1109, V4.2):
|
||||
* GPIO2 = CSD (chip select/enable): driven HIGH during radio, LOW in sleep
|
||||
* GPIO46 = CPS (TX select): HIGH during TX, LOW during RX
|
||||
* V4.3 (KCT8103L) uses GPIO5 instead of GPIO46 — see heltec_wifi_lora32_v43. */
|
||||
antenna-enable-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; /* GC1109 CSD = GPIO2 */
|
||||
tx-enable-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; /* GC1109 CPS = GPIO46 = gpio1 pin 14 */
|
||||
|
||||
/* DIO2 drives the SX1262 internal RF switch (TX path select).
|
||||
* Combined with tx-enable-gpios, this keeps both the internal and
|
||||
* external PA switch in sync with no software intervention needed. */
|
||||
dio2-tx-enable;
|
||||
|
||||
/* TCXO 1.8V via DIO3 — same as V3 */
|
||||
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
|
||||
tcxo-power-startup-delay-ms = <5>;
|
||||
|
||||
spi-max-frequency = <4000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&timer0 { status = "okay"; };
|
||||
&timer1 { status = "okay"; };
|
||||
&timer2 { status = "okay"; };
|
||||
&timer3 { status = "okay"; };
|
||||
|
||||
&wdt0 { status = "okay"; };
|
||||
&trng0 { status = "okay"; };
|
||||
|
||||
&esp32_bt_hci { status = "okay"; };
|
||||
&wifi { status = "okay"; };
|
||||
@@ -0,0 +1,12 @@
|
||||
# Heltec WiFi LoRa 32 V4 — minimal Zephyr defconfig (procpu)
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_NVS=y
|
||||
@@ -0,0 +1,3 @@
|
||||
config HEAP_MEM_POOL_ADD_SIZE_BOARD
|
||||
int
|
||||
default 4096
|
||||
@@ -0,0 +1,3 @@
|
||||
config BOARD_HELTEC_WIFI_LORA32_V43
|
||||
select SOC_ESP32S3_WROOM_N16R2
|
||||
select SOC_ESP32S3_PROCPU if BOARD_HELTEC_WIFI_LORA32_V43_ESP32S3_PROCPU
|
||||
@@ -0,0 +1,7 @@
|
||||
if(NOT "${OPENOCD}" MATCHES "^${ESPRESSIF_TOOLCHAIN_PATH}/.*")
|
||||
set(OPENOCD OPENOCD-NOTFOUND)
|
||||
endif()
|
||||
find_program(OPENOCD openocd PATHS ${ESPRESSIF_TOOLCHAIN_PATH}/openocd-esp32/bin NO_DEFAULT_PATH)
|
||||
|
||||
include(${ZEPHYR_BASE}/boards/common/esp32.board.cmake)
|
||||
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
|
||||
@@ -0,0 +1,26 @@
|
||||
# Heltec WiFi LoRa 32 V4.3 — ESP32-S3, 16 MB flash, 2 MB QSPI PSRAM
|
||||
#
|
||||
# Hardware:
|
||||
# SX1262 + KCT8103L external PA/FEM (GPIO5 CTX instead of GC1109 GPIO46 CPS)
|
||||
# SSD1306 128x64 OLED on I2C0
|
||||
# User button on GPIO0
|
||||
#
|
||||
# V4.3 vs V4.2: FEM chip changed GC1109 → KCT8103L, TX control pin GPIO46 → GPIO5.
|
||||
# Include order: prj.conf → zephcore_common.conf → esp32_common.conf → board.conf
|
||||
|
||||
# Board identification
|
||||
CONFIG_ZEPHCORE_BOARD_NAME="Heltec V4.3"
|
||||
CONFIG_BT_DIS_MODEL_NUMBER_STR="Heltec WiFi LoRa 32 V4.3"
|
||||
|
||||
# Flash size — 16 MB (override esp32_common.conf 4 MB default)
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
|
||||
|
||||
# Undocumented register 0x8B5 RX improvement (MeshCore PR#1398)
|
||||
# Applies to both GC1109 and KCT8103L PA boards.
|
||||
CONFIG_ZEPHCORE_SX126X_HELTEC_REG_PATCH=y
|
||||
|
||||
# TX power — SX1262 input to KCT8103L PA.
|
||||
# 10 dBm → ~22 dBm radiated output (KCT8103L similar gain to GC1109).
|
||||
# Do not exceed 10 dBm into the PA to avoid compression.
|
||||
CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=10
|
||||
CONFIG_ZEPHCORE_MAX_TX_POWER_DBM=10
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Heltec WiFi LoRa 32 V4.3 — ZephCore overlay
|
||||
*
|
||||
* The DTS already defines: SX1262 (lora0), SSD1306 OLED, button, LED, PWM,
|
||||
* vext_ctrl, adc_ctrl, fem_power, I2C0, SPI2, BLE, WiFi.
|
||||
* This overlay adds ZephCore-specific integration on top.
|
||||
*
|
||||
* LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa ctrl: DIO1=14, BUSY=13, RESET=12
|
||||
* FEM: POWER=7, KCT8103L CSD=2, CTX=5
|
||||
* Display I2C0: SDA=17, SCL=18, RST=21
|
||||
* Battery ADC: GPIO1 (ADC1 ch0), enable GPIO37, divider 100K/390K
|
||||
* Vext: GPIO36 (active-HIGH, powers OLED)
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
/* Native USB serial for ZephCore console/CLI */
|
||||
zephyr,console = &usb_serial;
|
||||
zephyr,shell-uart = &usb_serial;
|
||||
};
|
||||
|
||||
/* Battery ADC — ZephCore reads via zephyr,user { io-channels }.
|
||||
* Multiplier: 3300mV full-scale * 5.42x empirical divider = 17886 mV.
|
||||
* (Same as V3 — identical resistor divider topology.) */
|
||||
zephyr,user {
|
||||
io-channels = <&adc1 0>;
|
||||
vbat-mv-multiplier = <17886>;
|
||||
};
|
||||
|
||||
/* Battery ADC enable — ZephCore uses vbat_enable regulator alias.
|
||||
* GPIO37 (gpio1 pin 5) driven HIGH enables the ADC input path.
|
||||
* The DTS adc_ctrl node is power-domain-gpio which ZephCore doesn't use;
|
||||
* this regulator-fixed is the actual driver. */
|
||||
vbat_enable: vbat-enable {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "vbat-enable";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5 */
|
||||
};
|
||||
|
||||
/* ---- Button input filter chain ----
|
||||
* Button emits INPUT_KEY_0. Split into:
|
||||
* short press → KEY_A (consumed by multi-tap)
|
||||
* long press (1 s) → KEY_POWER (deep sleep) */
|
||||
user_btn_longpress {
|
||||
compatible = "zephyr,input-longpress";
|
||||
input = <&buttons>;
|
||||
input-codes = <INPUT_KEY_0>;
|
||||
short-codes = <INPUT_KEY_A>;
|
||||
long-codes = <INPUT_KEY_POWER>;
|
||||
long-delay-ms = <1000>;
|
||||
};
|
||||
|
||||
/* Multi-tap decodes short presses:
|
||||
* 1 tap (400 ms wait) → KEY_1 = page next
|
||||
* 2 taps (400 ms wait) → KEY_B = flood advert
|
||||
* 3 taps (400 ms wait) → KEY_D = buzzer mute toggle
|
||||
* 4 taps (immediate) → KEY_C = GPS on/off */
|
||||
user_btn_multitap {
|
||||
compatible = "zephcore,input-multi-tap";
|
||||
/* No 'input' phandle — listen to ALL devices.
|
||||
* KEY_A is emitted by the longpress pseudo-device. */
|
||||
input-codes = <INPUT_KEY_A>;
|
||||
tap-codes = <INPUT_KEY_1 INPUT_KEY_B INPUT_KEY_D INPUT_KEY_C>;
|
||||
tap-delay-ms = <400>;
|
||||
};
|
||||
};
|
||||
|
||||
/* Enable native USB serial for console/CLI */
|
||||
&usb_serial {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Patch LoRa radio: add pull-down on DIO1 and enable RX boosted mode.
|
||||
* DTS defines antenna-enable, tx-enable, dio2-tx-enable, and TCXO already. */
|
||||
&lora0 {
|
||||
dio1-gpios = <&gpio0 14 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
|
||||
rx-boosted;
|
||||
};
|
||||
|
||||
/* I2C sensors — auto-detected at runtime */
|
||||
&i2c0 {
|
||||
#include "../../common/sensors-i2c.dtsi"
|
||||
};
|
||||
|
||||
/*
|
||||
* Flash partitions — repartition 16 MB layout for ZephCore.
|
||||
* Delete lpcore slots, storage, scratch, and coredump to reclaim space.
|
||||
* Place LittleFS at 0xFA0000 - 0x1000000 (384 KB).
|
||||
*/
|
||||
/delete-node/ &slot0_lpcore_partition;
|
||||
/delete-node/ &slot1_lpcore_partition;
|
||||
/delete-node/ &storage_partition;
|
||||
/delete-node/ &scratch_partition;
|
||||
/delete-node/ &coredump_partition;
|
||||
|
||||
&flash0 {
|
||||
partitions {
|
||||
/* LittleFS 384 KB for DataStore + file-based BLE settings */
|
||||
lfs_partition: partition@fa0000 {
|
||||
label = "lfs";
|
||||
reg = <0xFA0000 0x60000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* LittleFS auto-mount — standard /lfs mount point */
|
||||
#include "../../common/filesystem.dtsi"
|
||||
@@ -0,0 +1,6 @@
|
||||
board:
|
||||
name: heltec_wifi_lora32_v43
|
||||
full_name: Heltec WiFi LoRa 32 V4.3
|
||||
vendor: heltec
|
||||
socs:
|
||||
- name: esp32s3
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Heltec WiFi LoRa 32 V4.3 — Pin Control Definitions
|
||||
*
|
||||
* Pin assignments identical to V4.2 (GPIO5/CTX is plain GPIO, no pinctrl entry needed):
|
||||
* UART0: TX=GPIO43, RX=GPIO44
|
||||
* I2C0: SDA=GPIO17, SCL=GPIO18 (SSD1306 OLED + sensors)
|
||||
* SPI2: SCLK=GPIO9, MOSI=GPIO10, MISO=GPIO11 (SX1262 LoRa)
|
||||
* LEDC0: CH0=GPIO35 (PWM LED)
|
||||
*/
|
||||
|
||||
#include <zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h>
|
||||
#include <zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h>
|
||||
|
||||
&pinctrl {
|
||||
uart0_default: uart0_default {
|
||||
group1 {
|
||||
pinmux = <UART0_TX_GPIO43>;
|
||||
output-high;
|
||||
};
|
||||
group2 {
|
||||
pinmux = <UART0_RX_GPIO44>;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
|
||||
i2c0_default: i2c0_default {
|
||||
group1 {
|
||||
pinmux = <I2C0_SDA_GPIO17>,
|
||||
<I2C0_SCL_GPIO18>;
|
||||
drive-open-drain;
|
||||
};
|
||||
};
|
||||
|
||||
spim2_default: spim2_default {
|
||||
group1 {
|
||||
pinmux = <SPIM2_MISO_GPIO11>,
|
||||
<SPIM2_SCLK_GPIO9>;
|
||||
};
|
||||
group2 {
|
||||
pinmux = <SPIM2_MOSI_GPIO10>;
|
||||
output-low;
|
||||
};
|
||||
};
|
||||
|
||||
ledc0_default: ledc0_default {
|
||||
group1 {
|
||||
pinmux = <LEDC_CH0_GPIO35>;
|
||||
output-enable;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Heltec WiFi LoRa 32 V4.3 — ZephCore procpu DTS
|
||||
*
|
||||
* Hardware:
|
||||
* MCU: ESP32-S3 (16 MB flash, 2 MB QSPI PSRAM)
|
||||
* Radio: SX1262 on SPI2, KCT8103L external PA/FEM
|
||||
* OLED: SSD1306 128x64 on I2C0
|
||||
* Button: GPIO0
|
||||
* LED: GPIO35 (PWM via LEDC0)
|
||||
* Vext: GPIO36 active-HIGH (powers OLED and sensors)
|
||||
* BatADC: GPIO1 (ADC1 ch0), enable GPIO37 active-LOW
|
||||
*
|
||||
* V4.3 vs V4.2 difference — FEM chip changed:
|
||||
* V4.2: GC1109 PA — TX_EN on GPIO46 (CPS)
|
||||
* V4.3: KCT8103L PA — CTX on GPIO5 (HIGH=TX, LOW=RX/LNA)
|
||||
* Detection: GPIO2 default pull differs (GC1109: pull-down, KCT8103L: pull-up)
|
||||
* (See MeshCore PR#1867, Heltec schematic HTIT-WB32LAF_V4.3)
|
||||
*
|
||||
* All other hardware is identical to V4.2:
|
||||
* GPIO7 = VFEM_Ctrl LDO power (active-HIGH, always-on)
|
||||
* GPIO2 = KCT8103L CSD (chip enable, active-HIGH)
|
||||
* GPIO5 = KCT8103L CTX (TX/RX select: HIGH=TX, LOW=RX/LNA) ← V4.3 change
|
||||
*
|
||||
* LoRa SPI2: SCLK=9, MOSI=10, MISO=11, NSS=8
|
||||
* LoRa ctrl: DIO1=14, BUSY=13, RESET=12
|
||||
* FEM: POWER=7, CSD=2, CTX=5
|
||||
* Display I2C0: SDA=17, SCL=18, RST=21
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
#include <espressif/esp32s3/esp32s3_wroom_n16r2.dtsi>
|
||||
#include "heltec_wifi_lora32_v43-pinctrl.dtsi"
|
||||
#include <zephyr/dt-bindings/pwm/pwm.h>
|
||||
#include <zephyr/dt-bindings/input/input-event-codes.h>
|
||||
#include <zephyr/dt-bindings/lora/sx126x.h>
|
||||
#include <espressif/partitions_0x0_amp_16M.dtsi>
|
||||
|
||||
/ {
|
||||
model = "Heltec WiFi LoRa 32 V4.3 PROCPU";
|
||||
compatible = "heltec,wifi-lora32-v4_3";
|
||||
|
||||
aliases {
|
||||
led0 = &led0;
|
||||
pwm-0 = &ledc0;
|
||||
pwm-led0 = &pwm_led_white;
|
||||
uart-0 = &uart0;
|
||||
i2c-0 = &i2c0;
|
||||
lora0 = &lora0;
|
||||
sw0 = &button0;
|
||||
watchdog0 = &wdt0;
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
led0: led {
|
||||
gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; /* GPIO35 = gpio1 pin 3 */
|
||||
label = "White LED";
|
||||
};
|
||||
};
|
||||
|
||||
pwmleds {
|
||||
compatible = "pwm-leds";
|
||||
pwm_led_white: pwm_led_gpio35 {
|
||||
label = "White PWM LED";
|
||||
pwms = <&ledc0 0 PWM_MSEC(10) PWM_POLARITY_NORMAL>;
|
||||
};
|
||||
};
|
||||
|
||||
buttons: buttons {
|
||||
compatible = "gpio-keys";
|
||||
button0: button_0 {
|
||||
gpios = <&gpio0 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
|
||||
label = "USER Key";
|
||||
zephyr,code = <INPUT_KEY_0>;
|
||||
};
|
||||
};
|
||||
|
||||
vbatt {
|
||||
compatible = "voltage-divider";
|
||||
io-channels = <&adc1 0>; /* GPIO1 = ADC1 ch0 */
|
||||
output-ohms = <100000>;
|
||||
full-ohms = <(100000 + 390000)>;
|
||||
};
|
||||
|
||||
/* Vext — powers OLED and external peripherals (active-HIGH, same as V4.2) */
|
||||
vext_ctrl: vext_ctrl {
|
||||
compatible = "power-domain-gpio";
|
||||
enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; /* GPIO36 = gpio1 pin 4 */
|
||||
#power-domain-cells = <0>;
|
||||
label = "Vext Control";
|
||||
};
|
||||
|
||||
/* ADC enable — GPIO37 (gpio1 pin 5) must be driven HIGH to read battery */
|
||||
adc_ctrl: adc_ctrl {
|
||||
compatible = "power-domain-gpio";
|
||||
enable-gpios = <&gpio1 5 GPIO_ACTIVE_LOW>; /* GPIO37 = gpio1 pin 5, active-LOW */
|
||||
#power-domain-cells = <0>;
|
||||
label = "ADC Control";
|
||||
};
|
||||
|
||||
/* FEM LDO power supply — GPIO7 powers the KCT8103L LDO.
|
||||
* Must be HIGH before any radio operation. Keep always-on. */
|
||||
fem_power: fem-power {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-name = "fem-power";
|
||||
enable-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; /* VFEM_Ctrl = GPIO7 */
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
chosen {
|
||||
zephyr,sram = &sram1;
|
||||
zephyr,console = &uart0;
|
||||
zephyr,shell-uart = &uart0;
|
||||
zephyr,flash = &flash0;
|
||||
zephyr,code-partition = &slot0_partition;
|
||||
zephyr,bt-hci = &esp32_bt_hci;
|
||||
zephyr,display = &ssd1306_128x64;
|
||||
};
|
||||
};
|
||||
|
||||
&adc1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
current-speed = <115200>;
|
||||
pinctrl-0 = <&uart0_default>;
|
||||
pinctrl-names = "default";
|
||||
};
|
||||
|
||||
&gpio0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gpio1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
/* Reduce CPU clock from 240 MHz to 160 MHz — saves power, HAL minimum */
|
||||
&cpu0 {
|
||||
clock-frequency = <DT_FREQ_M(160)>;
|
||||
};
|
||||
|
||||
&cpu1 {
|
||||
clock-frequency = <DT_FREQ_M(160)>;
|
||||
};
|
||||
|
||||
&ledc0 {
|
||||
pinctrl-0 = <&ledc0_default>;
|
||||
pinctrl-names = "default";
|
||||
status = "okay";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
channel0@0 {
|
||||
reg = <0x0>;
|
||||
timer = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
clock-frequency = <I2C_BITRATE_FAST>;
|
||||
pinctrl-0 = <&i2c0_default>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
ssd1306_128x64: display-controller@3c {
|
||||
compatible = "solomon,ssd1306";
|
||||
reg = <0x3c>;
|
||||
width = <128>;
|
||||
height = <64>;
|
||||
segment-offset = <0>;
|
||||
page-offset = <0>;
|
||||
display-offset = <0>;
|
||||
multiplex-ratio = <63>;
|
||||
segment-remap;
|
||||
com-invdir;
|
||||
inversion-on;
|
||||
prechargep = <0x22>;
|
||||
reset-gpios = <&gpio0 21 GPIO_ACTIVE_LOW>; /* RST_OLED = GPIO21 */
|
||||
power-domains = <&vext_ctrl>;
|
||||
};
|
||||
};
|
||||
|
||||
&spi2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "okay";
|
||||
pinctrl-0 = <&spim2_default>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
cs-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>; /* NSS = GPIO8 */
|
||||
|
||||
lora0: modem@0 {
|
||||
compatible = "semtech,sx1262";
|
||||
reg = <0>;
|
||||
reset-gpios = <&gpio0 12 (GPIO_OPEN_DRAIN | GPIO_ACTIVE_LOW)>; /* RESET = GPIO12 */
|
||||
busy-gpios = <&gpio0 13 GPIO_ACTIVE_HIGH>; /* BUSY = GPIO13 */
|
||||
dio1-gpios = <&gpio0 14 GPIO_ACTIVE_HIGH>; /* DIO1 = GPIO14 */
|
||||
|
||||
/* External PA/FEM control (KCT8103L, V4.3):
|
||||
* GPIO2 = CSD (chip enable): driven HIGH during radio, LOW in sleep
|
||||
* GPIO5 = CTX (TX/RX select): HIGH during TX, LOW during RX/LNA
|
||||
* V4.3 CHANGE: CTX moved from GPIO46 (GC1109 CPS) to GPIO5 (KCT8103L CTX). */
|
||||
antenna-enable-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; /* KCT8103L CSD = GPIO2 */
|
||||
tx-enable-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>; /* KCT8103L CTX = GPIO5 */
|
||||
|
||||
/* DIO2 drives the SX1262 internal RF switch (TX path select).
|
||||
* Combined with tx-enable-gpios, this keeps both the internal and
|
||||
* external PA switch in sync with no software intervention needed. */
|
||||
dio2-tx-enable;
|
||||
|
||||
/* TCXO 1.8V via DIO3 — same as V4.2 */
|
||||
dio3-tcxo-voltage = <SX126X_DIO3_TCXO_1V8>;
|
||||
tcxo-power-startup-delay-ms = <5>;
|
||||
|
||||
spi-max-frequency = <4000000>;
|
||||
};
|
||||
};
|
||||
|
||||
&timer0 { status = "okay"; };
|
||||
&timer1 { status = "okay"; };
|
||||
&timer2 { status = "okay"; };
|
||||
&timer3 { status = "okay"; };
|
||||
|
||||
&wdt0 { status = "okay"; };
|
||||
&trng0 { status = "okay"; };
|
||||
|
||||
&esp32_bt_hci { status = "okay"; };
|
||||
&wifi { status = "okay"; };
|
||||
@@ -0,0 +1,12 @@
|
||||
# Heltec WiFi LoRa 32 V4.3 — minimal Zephyr defconfig (procpu)
|
||||
CONFIG_CONSOLE=y
|
||||
CONFIG_SERIAL=y
|
||||
CONFIG_UART_CONSOLE=y
|
||||
CONFIG_GPIO=y
|
||||
CONFIG_CLOCK_CONTROL=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_I2C=y
|
||||
CONFIG_FLASH=y
|
||||
CONFIG_FLASH_MAP=y
|
||||
CONFIG_NVS=y
|
||||
@@ -32,6 +32,13 @@ SWD flash: `west flash` (requires J-Link, pyocd, or nrfjprog connected).
|
||||
| XIAO ESP32-S3 | `west build -b xiao_esp32s3/esp32s3/procpu zephcore` | `west flash` |
|
||||
| Station G2 | `west build -b station_g2/esp32s3/procpu zephcore` | `west flash` |
|
||||
| Heltec V3 | `west build -b heltec_wifi_lora32_v3/esp32s3/procpu zephcore` | `west flash` |
|
||||
| Heltec V4.2 (GC1109 PA) | `west build -b heltec_wifi_lora32_v4/esp32s3/procpu zephcore` | `west flash` |
|
||||
| Heltec V4.3 (KCT8103L PA) | `west build -b heltec_wifi_lora32_v43/esp32s3/procpu zephcore` | `west flash` |
|
||||
|
||||
**Heltec V4.2 vs V4.3:** The hardware revision is printed on the PCB silkscreen. If
|
||||
unclear, check GPIO2's default pull: the V4.2 GC1109 PA has an internal pull-down
|
||||
(GPIO2 reads LOW at boot), while the V4.3 KCT8103L PA has an internal pull-up
|
||||
(GPIO2 reads HIGH). Only difference in firmware: TX control pin GPIO46→GPIO5.
|
||||
|
||||
ESP32 flash uses esptool over USB. Hold BOOT button if device doesn't enter download mode.
|
||||
|
||||
|
||||
@@ -62,6 +62,19 @@ void sx126x_set_rx_boost(const struct device *dev, bool enable);
|
||||
*/
|
||||
bool sx126x_is_chip_busy(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Apply undocumented register 0x8B5 RX improvement for Heltec V4
|
||||
*
|
||||
* Sets the LSB of register 0x8B5 which consistently improves RX reception
|
||||
* on boards with GC1109 or KCT8103L PA (Heltec V4/V4.3). Described by
|
||||
* Heltec engineer @Quency-D in MeshCore PR#1398.
|
||||
*
|
||||
* Must be called after the first lora_config() completes.
|
||||
*
|
||||
* @param dev LoRa device
|
||||
*/
|
||||
void sx126x_apply_heltec_reg_patch(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Reset AGC by performing warm sleep + full recalibration
|
||||
*
|
||||
|
||||
@@ -1,5 +1,74 @@
|
||||
diff --git a/drivers/lora/CMakeLists.txt b/drivers/lora/CMakeLists.txt
|
||||
index 9cd035fcf2b..18d04ec099a 100644
|
||||
--- a/drivers/lora/CMakeLists.txt
|
||||
+++ b/drivers/lora/CMakeLists.txt
|
||||
@@ -1,7 +1,11 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
+# ZephCore patch: adds lr11xx driver subdirectory.
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_LORA_SHELL shell.c)
|
||||
|
||||
+add_subdirectory_ifdef(CONFIG_LORA_LR11XX lr11xx)
|
||||
+add_subdirectory_ifdef(CONFIG_LORA_LR20XX lr20xx)
|
||||
+
|
||||
# zephyr-keep-sorted-start
|
||||
add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_LORAMAC_NODE loramac-node)
|
||||
add_subdirectory_ifdef(CONFIG_LORA_MODULE_BACKEND_LORA_BASICS_MODEM lora-basics-modem)
|
||||
diff --git a/drivers/lora/Kconfig b/drivers/lora/Kconfig
|
||||
index 657bdb9ce28..f8513b37044 100644
|
||||
--- a/drivers/lora/Kconfig
|
||||
+++ b/drivers/lora/Kconfig
|
||||
@@ -5,6 +5,7 @@
|
||||
#
|
||||
|
||||
# Top-level configuration file for LORA drivers.
|
||||
+# ZephCore patch: adds lr11xx driver Kconfig.
|
||||
|
||||
menuconfig LORA
|
||||
bool "LoRa drivers"
|
||||
@@ -60,6 +61,8 @@ config LORA_INIT_PRIORITY
|
||||
|
||||
rsource "Kconfig.sx12xx"
|
||||
rsource "Kconfig.rylrxxx"
|
||||
+rsource "lr11xx/Kconfig"
|
||||
+rsource "lr20xx/Kconfig"
|
||||
rsource "lora-basics-modem/Kconfig"
|
||||
rsource "native/Kconfig"
|
||||
|
||||
diff --git a/drivers/lora/loramac-node/sx12xx_common.c b/drivers/lora/loramac-node/sx12xx_common.c
|
||||
index 17689720dd2..09982dc2e70 100644
|
||||
--- a/drivers/lora/loramac-node/sx12xx_common.c
|
||||
+++ b/drivers/lora/loramac-node/sx12xx_common.c
|
||||
@@ -195,8 +195,15 @@ static void sx12xx_ev_rx_error(void)
|
||||
/**
|
||||
* @brief Convert Zephyr bandwidth enum to loramac-node bandwidth index
|
||||
*
|
||||
- * The loramac-node library expects bandwidth as an index (0, 1, 2) into its
|
||||
- * internal Bandwidths[] array, not the actual kHz value.
|
||||
+ * The loramac-node library expects bandwidth as an index into its internal
|
||||
+ * Bandwidths[] array (not the actual kHz value). The SX127x hardware
|
||||
+ * supports sub-125 kHz LoRa bandwidths; index 3 maps to 62.5 kHz (reg BW=6).
|
||||
+ *
|
||||
+ * Index mapping (kept in sync with sx1276.c / sx1272.c):
|
||||
+ * 0 → 125 kHz (reg BW 7)
|
||||
+ * 1 → 250 kHz (reg BW 8)
|
||||
+ * 2 → 500 kHz (reg BW 9)
|
||||
+ * 3 → 62.5 kHz (reg BW 6) — SX127x only
|
||||
*
|
||||
* @param bandwidth Zephyr lora_signal_bandwidth enum value
|
||||
* @param bw_idx Pointer to store the resulting bandwidth index
|
||||
@@ -215,6 +222,9 @@ static int sx12xx_get_bandwidth_idx(enum lora_signal_bandwidth bandwidth,
|
||||
case BW_500_KHZ:
|
||||
*bw_idx = 2;
|
||||
break;
|
||||
+ case BW_62_KHZ:
|
||||
+ *bw_idx = 3;
|
||||
+ break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
diff --git a/drivers/lora/native/sx126x/sx126x.c b/drivers/lora/native/sx126x/sx126x.c
|
||||
index 30243ba5dc7..0ba41d05da0 100644
|
||||
index 30243ba5dc7..ddc4ce19660 100644
|
||||
--- a/drivers/lora/native/sx126x/sx126x.c
|
||||
+++ b/drivers/lora/native/sx126x/sx126x.c
|
||||
@@ -10,10 +10,19 @@
|
||||
@@ -423,7 +492,7 @@ index 30243ba5dc7..0ba41d05da0 100644
|
||||
|
||||
/* Set packet parameters */
|
||||
ret = sx126x_set_packet_params(dev,
|
||||
@@ -1083,14 +1303,407 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
|
||||
@@ -1083,14 +1303,423 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -529,6 +598,22 @@ index 30243ba5dc7..0ba41d05da0 100644
|
||||
+ k_mutex_unlock(&data->lock);
|
||||
+}
|
||||
+
|
||||
+void sx126x_apply_heltec_reg_patch(const struct device *dev)
|
||||
+{
|
||||
+ struct sx126x_data *data = dev->data;
|
||||
+ uint8_t val = 0;
|
||||
+
|
||||
+ /* Set LSB of undocumented register 0x8B5 to improve RX performance.
|
||||
+ * Described by Heltec engineer @Quency-D in MeshCore PR#1398 —
|
||||
+ * consistently improves reception on boards with GC1109/KCT8103L PA
|
||||
+ * (Heltec V4/V4.3). Must be called after lora_config(). */
|
||||
+ k_mutex_lock(&data->lock, K_FOREVER);
|
||||
+ sx126x_hal_read_regs(dev, 0x08B5, &val, 1);
|
||||
+ val |= 0x01;
|
||||
+ sx126x_hal_write_regs(dev, 0x08B5, &val, 1);
|
||||
+ k_mutex_unlock(&data->lock);
|
||||
+}
|
||||
+
|
||||
+/* ── Driver API: CAD ────────────────────────────────────────────────── */
|
||||
+
|
||||
+/* Recommended cad_detect_peak values per SF for 2-symbol CAD.
|
||||
@@ -838,7 +923,7 @@ index 30243ba5dc7..0ba41d05da0 100644
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
@@ -1121,9 +1734,18 @@ static int sx126x_init(const struct device *dev)
|
||||
@@ -1121,9 +1750,18 @@ static int sx126x_init(const struct device *dev)
|
||||
k_msgq_init(&data->rx_msgq, (char *)&data->rx_result,
|
||||
sizeof(struct sx126x_rx_result), 1);
|
||||
k_work_init(&data->irq_work, sx126x_irq_work_handler);
|
||||
|
||||
Reference in New Issue
Block a user