Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [Unreleased]

### Added
- **Heltec WiFi LoRa 32 V3 support** - ESP32-S3 with 128x64 OLED, LoRa SX1262

# Changelog

All notable changes to SparkMiner will be documented in this file.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ Find your board below and download the matching firmware from [Releases](https:/
| **Wemos/Lolin S3 Mini** | `esp32-s3-mini_firmware.bin` | RGB LED status indicator |
| **WeAct S3 Mini** | `esp32-s3-mini_firmware.bin` | Compatible with Lolin |
| **ESP32-S3 + SSD1306 OLED** | `esp32-s3-oled_firmware.bin` | 128x64 I2C OLED |
| **Heltec WiFi LoRa 32 V3** | `heltec-wifi-lora32-v3_firmware.bin` | ESP32-S3, 128x64 OLED, LoRa SX1262 |

### ESP32-C3 Boards

Expand Down Expand Up @@ -165,6 +166,7 @@ Find your board below and download the matching firmware from [Releases](https:/
| ESP32-S3/C3 + OLED | ✅ Full | 128x64 SSD1306 I2C |
| ESP32-S3/C3 Mini | ✅ Full | RGB LED status |
| ESP32 Headless | ✅ Full | GPIO LED status indicator |
| Heltec WiFi LoRa 32 V3 | ✅ Full | ESP32-S3, 128x64 OLED, LoRa SX1262 |
| LILYGO T-Display S3 | ❌ None | Not yet supported |
| LILYGO T-Display V1 | ❌ None | Not yet supported |
| ESP32-S2 boards | ❌ None | Single-core not supported |
Expand Down
38 changes: 37 additions & 1 deletion devtool.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@ def build(self, board: BoardConfig = None, verbose: bool = True) -> bool:

def get_firmware_path(self, board: BoardConfig) -> Optional[Path]:
"""Find firmware file for a board"""
is_xiao_s3 = board.key.startswith("seeed-xiao-esp32s3") or board.env.startswith("seeed-xiao-esp32s3")

# Guard: never pick *_factory.bin for XIAO S3 unless merge layout is explicitly verified.
# XIAO should use standard PlatformIO upload path (bootloader/partitions/app offsets).
if is_xiao_s3:
build_fw = self.script_dir / ".pio" / "build" / board.env / "firmware.bin"
if build_fw.exists():
return build_fw
return None

# Check release firmware first (try friendly key name, then env name)
version = self.get_version()
fw_dir = self.get_firmware_dir() / version
Expand Down Expand Up @@ -623,6 +633,8 @@ def flash(self, board: BoardConfig = None, port: str = None,
print(f"{c('[ERROR]', Colors.RED)} No board selected!")
return False

is_xiao_s3 = board.key.startswith("seeed-xiao-esp32s3") or board.env.startswith("seeed-xiao-esp32s3")

firmware = self.get_firmware_path(board)
if not firmware:
print(f"{c('[ERROR]', Colors.RED)} No firmware found! Build first.")
Expand All @@ -647,6 +659,25 @@ def flash(self, board: BoardConfig = None, port: str = None,
self.print_bootloader_instructions()
input(f"\n{c('[?]', Colors.CYAN)} Press ENTER when in download mode...")

if is_xiao_s3:
print(f"{c('[INFO]', Colors.YELLOW)} XIAO S3 guard active: skipping factory-bin flashing path")
cmd = self.get_pio_cmd() + [
"run",
"-e", board.env,
"-t", "upload",
"--upload-port", port,
]

result = self.run_cmd(cmd)

if result and result.returncode == 0:
print(f"\n{c('[SUCCESS]', Colors.GREEN)} Upload completed via PlatformIO!")
self.current_port = port
return True
else:
print(f"\n{c('[ERROR]', Colors.RED)} Upload failed!")
return False

flash_addr = "0x0" if "factory" in firmware.name else "0x10000"

cmd = [
Expand Down Expand Up @@ -701,7 +732,12 @@ def monitor(self, board: BoardConfig = None, port: str = None,
print(f" Exit: Ctrl+C")
print(f"{c('=' * 60, Colors.CYAN)}\n")

cmd = self.get_pio_cmd() + ["device", "monitor", "-b", str(board.monitor_baud), "-p", port]
cmd = self.get_pio_cmd() + [
"device", "monitor",
"-e", board.env,
"-b", str(board.monitor_baud),
"-p", port
]

# Add filters
for f in self.config.monitor_filters:
Expand Down
33 changes: 32 additions & 1 deletion devtool.toml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,37 @@ needs_boot_mode = true
port_changes_on_reset = true
group = "Headless (No Display)"

[boards.heltec-wifi-lora32-v3]
name = "Heltec WiFi LoRa 32 V3"
env = "heltec-wifi-lora32-v3"
chip = "esp32s3"
description = "Heltec WiFi LoRa 32 V3: ESP32-S3, 128x64 OLED (I2C), LoRa SX1262, no PSRAM (~280 H/s)"
needs_boot_mode = true
port_changes_on_reset = true
group = "OLED Display"

[boards.seeed-xiao-esp32s3]
name = "Seeed XIAO ESP32-S3"
env = "seeed-xiao-esp32s3"
chip = "esp32s3"
description = "Compact ESP32-S3 headless miner (22x26.5mm, USB-C, 16MB flash, no PSRAM)"
needs_boot_mode = true
port_changes_on_reset = true
flash_mode = "dio"
flash_freq = "80m"
group = "Headless (No Display)"

[boards.seeed-xiao-esp32s3-safe]
name = "Seeed XIAO ESP32-S3 (Safe Upload)"
env = "seeed-xiao-esp32s3-safe"
chip = "esp32s3"
description = "Safe recovery path: always upload via PlatformIO offset layout, no factory-bin flash"
needs_boot_mode = true
port_changes_on_reset = true
flash_mode = "dio"
flash_freq = "40m"
group = "Headless (No Display)"

# ============================================================
# Release Settings
# ============================================================
Expand All @@ -169,7 +200,7 @@ firmware_suffix = "_firmware.bin"

[monitor]
# Filters for platformio device monitor
filters = ["colorize", "esp32_exception_decoder", "time"]
filters = ["esp32_exception_decoder", "time"]
# Auto-reconnect on disconnect
auto_reconnect = true
# Log to file (empty = disabled)
Expand Down
60 changes: 60 additions & 0 deletions include/board_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,66 @@

// SHA Implementation: Defined in platformio.ini (USE_HARDWARE_SHA=1)

// ============================================================
// Heltec WiFi LoRa 32 V3 - ESP32-S3, 128x64 OLED (I2C), LoRa SX1262
// ============================================================
#elif defined(HELTEC_V3)
#define BOARD_NAME "Heltec WiFi LoRa 32 V3"

// Use OLED display (not TFT)
#ifndef USE_DISPLAY
#define USE_DISPLAY 0
#endif
#ifndef USE_OLED_DISPLAY
#define USE_OLED_DISPLAY 1
#endif

// OLED configuration (128x64 SSD1306 I2C)
#define OLED_WIDTH 128
#define OLED_HEIGHT 64
#define OLED_SDA_PIN 17
#define OLED_SCL_PIN 18
#define OLED_I2C_ADDR 0x3C
#define OLED_RST_PIN 21

// Display power enable (Vext)
#define VEXT_PIN 36

// Onboard LED
#define LED_PIN 35

// Buttons
#define BUTTON_PIN 0 // BOOT
#define USER_BUTTON_PIN 14
#define BUTTON_ACTIVE_LOW 1

// SHA Implementation: Defined in platformio.ini (USE_HARDWARE_SHA=1)

// ============================================================
// Seeed XIAO ESP32-S3 - Compact dual-core headless miner
// Ultra-compact form factor (22x26.5mm), USB-C, 16MB flash
// ============================================================
#elif defined(SEEED_XIAO_ESP32S3)
#define BOARD_NAME "Seeed XIAO ESP32-S3"

#ifndef USE_DISPLAY
#define USE_DISPLAY 0
#endif
#ifndef USE_OLED_DISPLAY
#define USE_OLED_DISPLAY 0
#endif
#ifndef USE_EINK_DISPLAY
#define USE_EINK_DISPLAY 0
#endif

// No built-in LED (XIAO boards are minimal)
#define USE_LED_STATUS 0

// NO BUTTON on XIAO - GPIO0 is BOOT button, cannot be used for app purposes
#define BUTTON_PIN -1

// SHA Implementation: Defined in platformio.ini (USE_HARDWARE_SHA=1)

// ============================================================
// Default - Generic ESP32
// ============================================================
Expand Down
135 changes: 132 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
; SparkMiner - Best of BitsyMiner + NerdMiner
; ESP32 Bitcoin Solo Miner with optimized performance
;
; Build: pio run -e esp32-2432s028
; Upload: pio run -e esp32-2432s028 -t upload
; Build: pio run -e heltec-wifi-lora32-v3
; Upload: pio run -e heltec-wifi-lora32-v3 -t upload
; Monitor: pio device monitor

[platformio]
default_envs = esp32-2432s028
default_envs = heltec-wifi-lora32-v3

[env]
platform = espressif32@6.6.0
Expand All @@ -20,6 +20,7 @@ monitor_filters =
log2file

extra_scripts =
pre:scripts/gen_build_info.py
post:scripts/post_build_merge.py

lib_deps =
Expand Down Expand Up @@ -681,6 +682,134 @@ lib_ignore =
SD_MMC
FastLED

; ============================================================
; Heltec WiFi LoRa 32 V3 - ESP32-S3, 128x64 OLED (I2C), LoRa SX1262
; Compatible with SparkMiner (SSD1306, U8g2, no PSRAM)
; ============================================================
[env:heltec-wifi-lora32-v3]
board = heltec_wifi_lora_32_V3
board_build.partitions = default_8MB.csv
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
upload_speed = 921600
monitor_filters =
esp32_exception_decoder
time
log2file

build_unflags = -Os

build_flags =
-D AUTO_VERSION=\"v2.9.5\"
-D HELTEC_V3=1
-D USE_HARDWARE_SHA=1
-D USE_DISPLAY=0
-D USE_OLED_DISPLAY=1
-D OLED_WIDTH=128
-D OLED_HEIGHT=64
-D OLED_SDA_PIN=17
-D OLED_SCL_PIN=18
-D OLED_I2C_ADDR=0x3C
-D OLED_RST_PIN=21
-D VEXT_PIN=36
-D LED_PIN=35
-D BUTTON_PIN=0
-D USER_BUTTON_PIN=14
-O3
-funroll-loops
; -D DEBUG_MINING=1
-D DEBUG_SHARE_VALIDATION=1
; -D DEBUG_HASH_TIMING=1
; Experimental: alternative compressor in miner_sha256_complete_from_midstate* (OFF by default)
; -D MINER_EXPERIMENTAL_COMPRESSOR=1
; -D S3_DEBUG_NONCE_WINDOW_ENABLE=1
; -D S3_DEBUG_NONCE_WINDOW_START=0x00000000
; -D S3_DEBUG_NONCE_WINDOW_END=0x0000FFFF
; Optional S3 hardware-path experiments (boot-time, deterministic vectors + microbench)
; -D S3_HW_EXPERIMENTS_ENABLE=1
; -D S3_HW_EXPERIMENTS_NONCES=4096
; -D S3_HW_EXPERIMENTS_ENABLE=1
; Baseline benchmark (run once at boot to measure cycle-level performance)
-D ENABLE_BASELINE_BENCHMARK=1

lib_deps =
${env.lib_deps}
olikraus/U8g2@^2.35.9

lib_ignore =
TFT_eSPI
OpenFontRender
SD
SD_MMC
FastLED




; ============================================================
; Seeed XIAO ESP32-S3 - Compact dual-core headless miner (MINIMAL)
; Conservative settings for stability, USB-C, no PSRAM
; ============================================================
[env:seeed-xiao-esp32s3]
board = seeed_xiao_esp32s3
board_build.partitions = default_8MB.csv
board_build.mcu = esp32s3
board_build.f_cpu = 240000000L
upload_speed = 921600
; Conservative flash settings for XIAO compatibility
board_build.flash_mode = dio
board_build.flash_size = 8MB
; Framework 2.0.14 for ESP32-S3 does not ship bootloader_dio_40m.elf,
; so force DIO mode but keep supported 80m bootloader variant.
board_build.flash_freq = 80m

build_unflags = -Os

build_flags =
-D AUTO_VERSION=\"v2.9.5\"
-D SEEED_XIAO_ESP32S3=1
-D USE_HARDWARE_SHA=1
-D CORE_0_YIELD_COUNT=1024
; No PSRAM on standard XIAO S3 - disable completely
; ARDUINO_USB_MODE=1 for USB host mode, =0 for device (default for CDC)
-D ARDUINO_USB_MODE=0
-D ARDUINO_USB_CDC_ON_BOOT=1
-D USE_DISPLAY=0
-D USE_OLED_DISPLAY=0
-D USE_EINK_DISPLAY=0
; Disable non-essential features for boot stability
-D BUTTON_PIN=-1
; Enable boot diagnostics
-D BOOT_DEBUG=1
; Optimization - but not as aggressive as Heltec (was -O3)
-O3
-funroll-loops
; -D DEBUG_MINING=1
; -D DEBUG_HASH_TIMING=1
; Enable comprehensive hash evaluation logging for v2.9.5 regression diagnosis
; -D DEBUG_HASH_EVAL=1
; -D DEBUG_HASH_EVAL_SAMPLE_RATE=10000
; Optional S3 hardware-path experiments (boot-time, deterministic vectors + microbench)
; -D S3_HW_EXPERIMENTS_ENABLE=1
; -D S3_HW_EXPERIMENTS_NONCES=4096

lib_deps =
${env.lib_deps}

lib_ignore =
TFT_eSPI
OpenFontRender
SD
SD_MMC
FastLED

; ============================================================
; Seeed XIAO ESP32-S3 SAFE alias
; Use this env for explicit recovery uploads/debug sessions
; ============================================================
[env:seeed-xiao-esp32s3-safe]
extends = env:seeed-xiao-esp32s3

; ============================================================
; ESP32-S3 Headless - No display, serial only
; Dual-core with monochrome display and LoRa
Expand Down
Loading