From c2f65e5f7f36a89ecee75f62f85876a0b51db580 Mon Sep 17 00:00:00 2001 From: Martin-hub1 Date: Thu, 22 Oct 2026 17:53:57 +0800 Subject: [PATCH] Add DFRobot LoRaWAN ESP32-S3 Companion BLE firmware Add a board variant for the DFRobot DFR1195 (ESP32-S3-WROOM-1-N4, SX1262, 80x160 ST7735S) and a Companion BLE environment. The display and radio use separate SPI controllers: the SX1262 is on FSPI and the ST7735 is on HSPI. ST7735Display selects that HSPI bus and the 160x80 init sequence only when DFROBOT_LORAWAN_ESP32S3 is defined. --- boards/dfrobot_lorawan_esp32s3.json | 39 ++++++++++ src/helpers/ui/ST7735Display.cpp | 5 +- .../DFRobotLoRaBoard.cpp | 20 +++++ .../DFRobotLoRaBoard.h | 15 ++++ .../dfrobot_lorawan_esp32s3/platformio.ini | 73 +++++++++++++++++++ variants/dfrobot_lorawan_esp32s3/target.cpp | 34 +++++++++ variants/dfrobot_lorawan_esp32s3/target.h | 26 +++++++ 7 files changed, 210 insertions(+), 2 deletions(-) create mode 100644 boards/dfrobot_lorawan_esp32s3.json create mode 100644 variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.cpp create mode 100644 variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.h create mode 100644 variants/dfrobot_lorawan_esp32s3/platformio.ini create mode 100644 variants/dfrobot_lorawan_esp32s3/target.cpp create mode 100644 variants/dfrobot_lorawan_esp32s3/target.h diff --git a/boards/dfrobot_lorawan_esp32s3.json b/boards/dfrobot_lorawan_esp32s3.json new file mode 100644 index 00000000000..62e6cfed34d --- /dev/null +++ b/boards/dfrobot_lorawan_esp32s3.json @@ -0,0 +1,39 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld" + }, + "core": "esp32", + "extra_flags": [ + "-D ARDUINO_USB_CDC_ON_BOOT=0", + "-D ARDUINO_USB_MSC_ON_BOOT=0", + "-D ARDUINO_USB_DFU_ON_BOOT=0", + "-D ARDUINO_USB_MODE=0", + "-D ARDUINO_RUNNING_CORE=1", + "-D ARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "hwids": [["0x303A", "0x1001"]], + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": ["wifi", "bluetooth", "lora"], + "debug": { + "default_tool": "esp-builtin", + "onboard_tools": ["esp-builtin"], + "openocd_target": "esp32s3.cfg" + }, + "frameworks": ["arduino", "espidf"], + "name": "DFRobot LoRaWAN ESP32-S3 (4 MB Flash, No PSRAM)", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 524288, + "maximum_size": 4194304, + "require_upload_port": true, + "speed": 921600 + }, + "url": "https://www.dfrobot.com", + "vendor": "DFRobot" +} diff --git a/src/helpers/ui/ST7735Display.cpp b/src/helpers/ui/ST7735Display.cpp index 344f5b1d9d3..9143ee010b3 100644 --- a/src/helpers/ui/ST7735Display.cpp +++ b/src/helpers/ui/ST7735Display.cpp @@ -102,7 +102,8 @@ static TFT_eSPI lcd = TFT_eSPI(160, 80); static uint32_t curr_color; -#if defined(HELTEC_LORA_V3) || defined(HELTEC_TRACKER_V2) +#if defined(HELTEC_LORA_V3) || defined(HELTEC_TRACKER_V2) || defined(DFROBOT_LORAWAN_ESP32S3) + // ESP32-S3: HSPI is SPI3. The SX1262 uses FSPI (SPI2) so the two buses do not share a controller. static SPIClass tft_spi(HSPI); #define _spi (&tft_spi) #else @@ -490,7 +491,7 @@ void ST7735Display::_resetAndInit() { // run init commands displayInit(Rcmd1); -#if defined(HELTEC_TRACKER_V2) || defined(HELTEC_T096) +#if defined(HELTEC_TRACKER_V2) || defined(HELTEC_T096) || defined(DFROBOT_LORAWAN_ESP32S3) displayInit(Rcmd2green160x80); //uint8_t madctl = ST77XX_MADCTL_MY | ST77XX_MADCTL_MV |ST7735_MADCTL_BGR;//Adjust color to BGR //display.sendCommand(ST77XX_MADCTL, &madctl, 1); diff --git a/variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.cpp b/variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.cpp new file mode 100644 index 00000000000..fd04a971fce --- /dev/null +++ b/variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.cpp @@ -0,0 +1,20 @@ +#include "DFRobotLoRaBoard.h" + +void DFRobotLoRaBoard::begin() { + // SX1262 module power. Held high for the whole boot; Companion does not + // drop into deep sleep, so the pin does not need an RTC hold. + pinMode(LORA_POWER_EN, OUTPUT); + digitalWrite(LORA_POWER_EN, HIGH); + delay(10); + + periph_power.begin(); + + pinMode(PIN_LED, OUTPUT); + digitalWrite(PIN_LED, HIGH); + + ESP32Board::begin(); +} + +const char* DFRobotLoRaBoard::getManufacturerName() const { + return "DFRobot LoRaWAN ESP32-S3"; +} diff --git a/variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.h b/variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.h new file mode 100644 index 00000000000..80423486db1 --- /dev/null +++ b/variants/dfrobot_lorawan_esp32s3/DFRobotLoRaBoard.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include +#include + +class DFRobotLoRaBoard : public ESP32Board { +public: + RefCountedDigitalPin periph_power; + + DFRobotLoRaBoard() : periph_power(PIN_VEXT_EN, PIN_VEXT_EN_ACTIVE) { } + + void begin(); + const char* getManufacturerName() const override; +}; diff --git a/variants/dfrobot_lorawan_esp32s3/platformio.ini b/variants/dfrobot_lorawan_esp32s3/platformio.ini new file mode 100644 index 00000000000..0f69e2761de --- /dev/null +++ b/variants/dfrobot_lorawan_esp32s3/platformio.ini @@ -0,0 +1,73 @@ +; DFRobot LoRaWAN ESP32-S3 (DFR1195) +; ESP32-S3-WROOM-1-N4 (4 MB flash, no PSRAM), SX1262, SPI ST7735S 80x160. +; Pin map follows variants/esp32s3/DFRobot_LoRaWAN_ESP32-S3 in the Meshtastic tree. +; LoRa is on FSPI. The display is on HSPI (SPI3), matching ST7735_SPI_HOST. +[DFRobot_LoRaWAN_ESP32S3] +extends = esp32_base +board = dfrobot_lorawan_esp32s3 +; 4 MB module: app slots are 1.9 MB. The default 4 MB table only leaves 1.25 MB. +board_build.partitions = min_spiffs.csv +build_flags = + ${esp32_base.build_flags} + -I variants/dfrobot_lorawan_esp32s3 + -D DFROBOT_LORAWAN_ESP32S3 + -D ESP32_CPU_FREQ=80 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D P_LORA_NSS=10 + -D P_LORA_DIO_1=4 + -D P_LORA_RESET=41 + -D P_LORA_BUSY=40 + -D P_LORA_SCLK=7 + -D P_LORA_MISO=5 + -D P_LORA_MOSI=6 + -D LORA_POWER_EN=42 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=3.3 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D PIN_USER_BTN=18 + -D PIN_LED=21 + -D PIN_VEXT_EN=48 + -D PIN_VEXT_EN_ACTIVE=LOW + -D PIN_BOARD_SDA=8 + -D PIN_BOARD_SCL=9 + -D PIN_TFT_CS=17 + -D PIN_TFT_DC=14 + -D PIN_TFT_RST=15 + -D PIN_TFT_SDA=11 + -D PIN_TFT_SCL=12 + -D PIN_TFT_LEDA_CTL=16 + -D PIN_TFT_LEDA_CTL_ACTIVE=HIGH +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/dfrobot_lorawan_esp32s3> +lib_deps = + ${esp32_base.lib_deps} + bodmer/TFT_eSPI @ ^2.4.31 + +; Landscape UI on the 80x160 panel. Use 3 if the picture is upside down. +[env:DFRobot_LoRaWAN_ESP32S3_companion_radio_ble] +extends = DFRobot_LoRaWAN_ESP32S3 +build_flags = + ${DFRobot_LoRaWAN_ESP32S3.build_flags} + -I src/helpers/ui + -I examples/companion_radio/ui-new + -D DISPLAY_ROTATION=3 + -D DISPLAY_CLASS=ST7735Display + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 + -D OFFLINE_QUEUE_SIZE=256 +; -D BLE_DEBUG_LOGGING=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${DFRobot_LoRaWAN_ESP32S3.build_src_filter} + + + + + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${DFRobot_LoRaWAN_ESP32S3.lib_deps} + densaugeo/base64 @ ~1.4.0 diff --git a/variants/dfrobot_lorawan_esp32s3/target.cpp b/variants/dfrobot_lorawan_esp32s3/target.cpp new file mode 100644 index 00000000000..bf723516657 --- /dev/null +++ b/variants/dfrobot_lorawan_esp32s3/target.cpp @@ -0,0 +1,34 @@ +#include +#include +#include "target.h" + +DFRobotLoRaBoard board; + +// FSPI is SPI2. The ST7735 driver takes HSPI (SPI3); the default SPIClass +// constructor on ESP32-S3 is HSPI and would collide with the display. +static SPIClass spi(FSPI); +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display(&board.periph_power); + // Active-low button, internal pull-up. + MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true); +#endif + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + + return radio.std_init(&spi); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/dfrobot_lorawan_esp32s3/target.h b/variants/dfrobot_lorawan_esp32s3/target.h new file mode 100644 index 00000000000..07cec79ba79 --- /dev/null +++ b/variants/dfrobot_lorawan_esp32s3/target.h @@ -0,0 +1,26 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#ifdef DISPLAY_CLASS + #include + #include +#endif + +extern DFRobotLoRaBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +#ifdef DISPLAY_CLASS + extern DISPLAY_CLASS display; + extern MomentaryButton user_btn; +#endif + +bool radio_init(); +mesh::LocalIdentity radio_new_identity();