add wehooper4 SolarXiao builds

remap I2C to prevent boot lock up

(cherry picked from commit 2253a38a54ef902e1740cbd92c91984af143e31f)

fix broken bridge solarxiao bridge build

(cherry picked from commit 27e5aac41c904923c17c390ed46c2d49558efa1a)

add wehooper4 SolarXiao builds
This commit is contained in:
lincomatic
2026-07-15 10:36:29 -07:00
committed by mikecarper
parent 710790b81d
commit f5bf311862
7 changed files with 625 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
#ifdef SOLARXIAO
#include <Arduino.h>
#include <Wire.h>
#include "SolarXiaoBoard.h"
#ifdef NRF52_POWER_MANAGEMENT
// Static configuration for power management
// Values set in variant.h defines
const PowerMgtConfig power_config = {
.lpcomp_ain_channel = PWRMGT_LPCOMP_AIN,
.lpcomp_refsel = PWRMGT_LPCOMP_REFSEL,
.voltage_bootlock = PWRMGT_VOLTAGE_BOOTLOCK
};
void SolarXiaoBoard::initiateShutdown(uint8_t reason) {
bool enable_lpcomp = (reason == SHUTDOWN_REASON_LOW_VOLTAGE ||
reason == SHUTDOWN_REASON_BOOT_PROTECT);
pinMode(VBAT_ENABLE, OUTPUT);
digitalWrite(VBAT_ENABLE, enable_lpcomp ? LOW : HIGH);
if (enable_lpcomp) {
configureVoltageWake(power_config.lpcomp_ain_channel, power_config.lpcomp_refsel);
}
enterSystemOff(reason);
}
#endif // NRF52_POWER_MANAGEMENT
void SolarXiaoBoard::begin() {
NRF52BoardDCDC::begin();
// Configure battery voltage ADC
pinMode(PIN_VBAT, INPUT);
pinMode(VBAT_ENABLE, OUTPUT);
digitalWrite(VBAT_ENABLE, LOW); // Enable VBAT divider for reading
analogReadResolution(12);
analogReference(AR_INTERNAL_3_0);
delay(50); // Allow ADC to settle
#ifdef PIN_USER_BTN
pinMode(PIN_USER_BTN, INPUT_PULLUP);
#endif
#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL)
Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL);
#endif
Wire.begin();
#ifdef P_LORA_TX_LED
pinMode(P_LORA_TX_LED, OUTPUT);
digitalWrite(P_LORA_TX_LED, HIGH);
#endif
#ifdef NRF52_POWER_MANAGEMENT
// Boot voltage protection check (may not return if voltage too low)
checkBootVoltage(&power_config);
#endif
delay(10); // Give sx1262 some time to power up
}
uint16_t SolarXiaoBoard::getBattMilliVolts() {
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
// VBAT_ENABLE must be LOW to read battery voltage
digitalWrite(VBAT_ENABLE, LOW);
int adcvalue = analogRead(PIN_VBAT);
return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;
}
#endif
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#include <MeshCore.h>
#include <Arduino.h>
#include <helpers/NRF52Board.h>
#ifdef SOLARXIAO
class SolarXiaoBoard : public NRF52BoardDCDC {
protected:
#if NRF52_POWER_MANAGEMENT
void initiateShutdown(uint8_t reason) override;
#endif
public:
SolarXiaoBoard() : NRF52Board("XIAO_NRF52_OTA") {}
void begin();
#if defined(P_LORA_TX_LED)
void onBeforeTransmit() override {
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
}
void onAfterTransmit() override {
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
}
#endif
uint16_t getBattMilliVolts() override;
const char* getManufacturerName() const override {
return "Seeed Xiao-nrf52";
}
void powerOff() override {
// set led on and wait for button release before poweroff
digitalWrite(PIN_LED, LOW);
#ifdef PIN_USER_BTN
while(digitalRead(PIN_USER_BTN) == LOW);
#endif
digitalWrite(LED_GREEN, HIGH);
digitalWrite(LED_BLUE, HIGH);
digitalWrite(PIN_LED, HIGH);
#ifdef PIN_USER_BTN
// configure button press to wake up when in powered off state
nrf_gpio_cfg_sense_input(digitalPinToInterrupt(g_ADigitalPinMap[PIN_USER_BTN]), NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_LOW);
#endif
sd_power_system_off();
}
};
#endif
+172
View File
@@ -0,0 +1,172 @@
[solarxiao]
extends = nrf52_base
board = seeed-xiao-afruitnrf52-nrf52840
board_build.ldscript = boards/nrf52840_s140_v7.ld
build_flags = ${nrf52_base.build_flags}
${sensor_base.build_flags}
-I lib/nrf52/s140_nrf52_7.3.0_API/include
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
-I variants/solarxiao
-D NRF52_PLATFORM
-D NRF52_POWER_MANAGEMENT
-D SOLARXIAO
-D RADIO_CLASS=CustomSX1262
-D WRAPPER_CLASS=CustomSX1262Wrapper
-D LORA_TX_POWER=22
-D P_LORA_TX_LED=11
-D P_LORA_DIO_1=D1
-D P_LORA_RESET=D2
-D P_LORA_BUSY=D3
-D P_LORA_NSS=D4
-D SX126X_RXEN=D5
-D SX126X_TXEN=RADIOLIB_NC
-D SX126X_DIO2_AS_RF_SWITCH=1
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
-D SX126X_CURRENT_LIMIT=140
-D SX126X_RX_BOOSTED_GAIN=1
-D PIN_WIRE_SCL=PIN_NFC1
-D PIN_WIRE_SDA=PIN_NFC2
-D PIN_USER_BTN=PIN_BUTTON1
-D QSPIFLASH=1
-D DISPLAY_CLASS=NullDisplayDriver
build_src_filter = ${nrf52_base.build_src_filter}
+<helpers/*.cpp>
+<helpers/sensors>
+<../variants/solarxiao>
+<helpers/ui/NullDisplayDriver.cpp>
debug_tool = jlink
upload_protocol = nrfutil
lib_deps = ${nrf52_base.lib_deps}
${sensor_base.lib_deps}
[env:solarxiao_30S_companion_radio_ble]
extends = solarxiao
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
board_upload.maximum_size = 708608
build_flags =
${solarxiao.build_flags}
-I examples/companion_radio/ui-orig
-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 = ${solarxiao.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps =
${solarxiao.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:solarxiao_33S_companion_radio_ble]
extends = env:solarxiao_30S_companion_radio_ble
build_flags =
${env:solarxiao_30S_companion_radio_ble.build_flags}
-D LORA_TX_POWER=9
[env:solarxiao_30S_companion_radio_usb]
extends = solarxiao
board_build.ldscript = boards/nrf52840_s140_v7_extrafs.ld
board_upload.maximum_size = 708608
build_flags =
${solarxiao.build_flags}
-I examples/companion_radio/ui-orig
-D MAX_CONTACTS=350
-D MAX_GROUP_CHANNELS=40
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${solarxiao.build_src_filter}
+<helpers/nrf52/SerialBLEInterface.cpp>
+<../examples/companion_radio/*.cpp>
+<../examples/companion_radio/ui-orig/*.cpp>
lib_deps =
${solarxiao.lib_deps}
densaugeo/base64 @ ~1.4.0
[env:solarxiao_33S_companion_radio_usb]
extends = env:solarxiao_30S_companion_radio_usb
build_flags =
${env:solarxiao_30S_companion_radio_usb.build_flags}
-D LORA_TX_POWER=9
[env:solarxiao_30S_repeater]
extends = solarxiao
build_flags =
${solarxiao.build_flags}
-D ADVERT_NAME='"SolarXiao 30S Repeater"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D MAX_NEIGHBOURS=50
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${solarxiao.build_src_filter}
+<../examples/simple_repeater/*.cpp>
[env:solarxiao_33S_repeater]
extends = env:solarxiao_30S_repeater
build_flags =
${env:solarxiao_30S_repeater.build_flags}
-D LORA_TX_POWER=9
-D ADVERT_NAME='"SolarXiao 33S Repeater"'
[env:solarxiao_30S_repeater_bridge_rs232]
extends = env:solarxiao_30S_repeater
build_flags =
${env:solarxiao_30S_repeater.build_flags}
-D ADVERT_NAME='"SolarXiao 30S RS232"'
-UENV_INCLUDE_GPS
-D WITH_RS232_BRIDGE=Serial1
-D WITH_RS232_BRIDGE_RX=PIN_SERIAL1_RX
-D WITH_RS232_BRIDGE_TX=PIN_SERIAL1_TX
-D BRIDGE_MAX_BAUD=500000
build_src_filter =
${env:solarxiao_30S_repeater.build_src_filter}
+<helpers/bridges/RS232Bridge.cpp>
[env:solarxiao_33S_repeater_bridge_rs232]
extends = env:solarxiao_30S_repeater_bridge_rs232
build_flags =
${env:solarxiao_30S_repeater_bridge_rs232.build_flags}
-D LORA_TX_POWER=9
-D ADVERT_NAME='"SolarXiao 33S RS232"'
[env:solarxiao_30S_room_server]
extends = solarxiao
build_flags =
${solarxiao.build_flags}
-D ADVERT_NAME='"SolarXiao 30S Room"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
; -D MESH_PACKET_LOGGING=1
; -D MESH_DEBUG=1
build_src_filter = ${solarxiao.build_src_filter}
+<../examples/simple_room_server/*.cpp>
[env:solarxiao_33S_room_server]
extends = env:solarxiao_30S_room_server
build_flags =
${env:solarxiao_30S_room_server.build_flags}
-D LORA_TX_POWER=9
-D ADVERT_NAME='"SolarXiao 33S Room"'
[env:solarxiao_30S_kiss_modem]
extends = solarxiao
build_flags =
${solarxiao.build_flags}
build_src_filter = ${solarxiao.build_src_filter}
+<../examples/kiss_modem/*.cpp>
lib_deps =
${solarxiao.lib_deps}
[env:solarxiao_33S_kiss_modem]
extends = solarxiao_30S_kiss_modem
build_flags =
${env:solarxiao_30S_kiss_modem.build_flags}
-D LORA_TX_POWER=9
+50
View File
@@ -0,0 +1,50 @@
#include <Arduino.h>
#include "target.h"
#include <helpers/ArduinoHelpers.h>
#ifdef DISPLAY_CLASS
DISPLAY_CLASS display;
#endif
SolarXiaoBoard board;
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);
VolatileRTCClock fallback_clock;
AutoDiscoverRTCClock rtc_clock(fallback_clock);
#if ENV_INCLUDE_GPS
#include <helpers/sensors/MicroNMEALocationProvider.h>
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1);
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea);
#else
EnvironmentSensorManager sensors;
#endif
bool radio_init() {
rtc_clock.begin(Wire);
return radio.std_init(&SPI);
}
uint32_t radio_get_rng_seed() {
return radio.random(0x7FFFFFFF);
}
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
radio.setFrequency(freq);
radio.setSpreadingFactor(sf);
radio.setBandwidth(bw);
radio.setCodingRate(cr);
}
void radio_set_tx_power(int8_t dbm) {
radio.setOutputPower(dbm);
}
mesh::LocalIdentity radio_new_identity() {
RadioNoiseListener rng(radio);
return mesh::LocalIdentity(&rng); // create new random identity
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#define RADIOLIB_STATIC_ONLY 1
#include <RadioLib.h>
#include <helpers/radiolib/RadioLibWrappers.h>
#include <SolarXiaoBoard.h>
#include <helpers/radiolib/CustomSX1262Wrapper.h>
#include <helpers/AutoDiscoverRTCClock.h>
#include <helpers/ArduinoHelpers.h>
#include <helpers/sensors/EnvironmentSensorManager.h>
#ifdef DISPLAY_CLASS
#include <helpers/ui/NullDisplayDriver.h>
extern DISPLAY_CLASS display;
#endif
extern SolarXiaoBoard board;
extern WRAPPER_CLASS radio_driver;
extern AutoDiscoverRTCClock rtc_clock;
extern EnvironmentSensorManager sensors;
bool radio_init();
uint32_t radio_get_rng_seed();
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
void radio_set_tx_power(int8_t dbm);
mesh::LocalIdentity radio_new_identity();
+85
View File
@@ -0,0 +1,85 @@
#include "variant.h"
#include "nrf.h"
#include "wiring_constants.h"
#include "wiring_digital.h"
const uint32_t g_ADigitalPinMap[] = {
// D0 .. D10
2, // D0 is P0.02 (A0)
3, // D1 is P0.03 (A1)
28, // D2 is P0.28 (A2)
29, // D3 is P0.29 (A3)
4, // D4 is P0.04 (A4,SDA)
5, // D5 is P0.05 (A5,SCL)
43, // D6 is P1.11 (TX)
44, // D7 is P1.12 (RX)
45, // D8 is P1.13 (SCK)
46, // D9 is P1.14 (MISO)
47, // D10 is P1.15 (MOSI)
// LEDs
26, // D11 is P0.26 (LED RED)
6, // D12 is P0.06 (LED BLUE)
30, // D13 is P0.30 (LED GREEN)
14, // D14 is P0.14 (READ_BAT)
// LSM6DS3TR
40, // D15 is P1.08 (6D_PWR)
27, // D16 is P0.27 (6D_I2C_SCL)
7, // D17 is P0.07 (6D_I2C_SDA)
11, // D18 is P0.11 (6D_INT1)
// MIC
42, // D19 is P1.10 (MIC_PWR)
32, // D20 is P1.00 (PDM_CLK)
16, // D21 is P0.16 (PDM_DATA)
// BQ25100
13, // D22 is P0.13 (HICHG)
17, // D23 is P0.17 (~CHG)
//
21, // D24 is P0.21 (QSPI_SCK)
25, // D25 is P0.25 (QSPI_CSN)
20, // D26 is P0.20 (QSPI_SIO_0 DI)
24, // D27 is P0.24 (QSPI_SIO_1 DO)
22, // D28 is P0.22 (QSPI_SIO_2 WP)
23, // D29 is P0.23 (QSPI_SIO_3 HOLD)
// NFC
9, // D30 is P0.09 (NFC1)
10, // D31 is P0.10 (NFC2)
// VBAT
31, // D32 is P0.31 (VBAT)
};
void initVariant() {
// Disable reading of the BAT voltage.
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
pinMode(VBAT_ENABLE, OUTPUT);
// digitalWrite(VBAT_ENABLE, HIGH);
// This was taken from Seeed github butis not coherent with the doc,
// VBAT_ENABLE should be kept to LOW to protect P0.14, (1500/500)*(4.2-3.3)+3.3 = 3.9V > 3.6V
// This induces a 3mA current in the resistors :( but it's better than burning the nrf
digitalWrite(VBAT_ENABLE, LOW);
// Low charging current (50mA)
// https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current
// pinMode(PIN_CHARGING_CURRENT, INPUT);
// High charging current (100mA)
pinMode(PIN_CHARGING_CURRENT, OUTPUT);
digitalWrite(PIN_CHARGING_CURRENT, LOW);
pinMode(PIN_QSPI_CS, OUTPUT);
digitalWrite(PIN_QSPI_CS, HIGH);
pinMode(LED_RED, OUTPUT);
digitalWrite(LED_RED, HIGH);
pinMode(LED_GREEN, OUTPUT);
digitalWrite(LED_GREEN, HIGH);
pinMode(LED_BLUE, OUTPUT);
digitalWrite(LED_BLUE, HIGH);
}
+165
View File
@@ -0,0 +1,165 @@
#ifndef _SEEED_XIAO_NRF52840_H_
#define _SEEED_XIAO_NRF52840_H_
/** Master clock frequency */
#define VARIANT_MCK (64000000ul)
#define USE_LFXO // Board uses 32khz crystal for LF
//#define USE_LFRC // Board uses RC for LF
/*----------------------------------------------------------------------------
* Headers
*----------------------------------------------------------------------------*/
#include "WVariant.h"
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
#define PINS_COUNT (33)
#define NUM_DIGITAL_PINS (33)
#define NUM_ANALOG_INPUTS (8)
#define NUM_ANALOG_OUTPUTS (0)
// LEDs
#define PIN_LED (LED_RED)
#define LED_PWR (PINS_COUNT)
#define PIN_NEOPIXEL (PINS_COUNT)
#define NEOPIXEL_NUM (0)
#define LED_BUILTIN (PIN_LED)
#define LED_RED (11)
#define LED_GREEN (13)
#define LED_BLUE (12)
#define PIN_STATUS_LED (LED_BLUE)
#define LED_STATE_ON (0) // State when LED is on
// Buttons
#define PIN_BUTTON1 (0)
// Digital PINs
static const uint8_t D0 = 0 ;
static const uint8_t D1 = 1 ;
static const uint8_t D2 = 2 ;
static const uint8_t D3 = 3 ;
static const uint8_t D4 = 4 ;
static const uint8_t D5 = 5 ;
static const uint8_t D6 = 6 ;
static const uint8_t D7 = 7 ;
static const uint8_t D8 = 8 ;
static const uint8_t D9 = 9 ;
static const uint8_t D10 = 10;
#define VBAT_ENABLE (14) // Output LOW to enable reading of the BAT voltage.
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
#define PIN_CHARGING_CURRENT (22) // Battery Charging current
// https://wiki.seeedstudio.com/XIAO_BLE#battery-charging-current
// Analog pins
#define PIN_A0 (0)
#define PIN_A1 (1)
#define PIN_A2 (2)
#define PIN_A3 (3)
#define PIN_A4 (4)
#define PIN_A5 (5)
#define PIN_VBAT (32) // Read the BAT voltage.
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
#define BAT_NOT_CHARGING (23) // LOW when charging
#define AREF_VOLTAGE (3.0)
#define ADC_MULTIPLIER (3.0F) // 1M, 512k divider bridge
// Power management boot protection threshold (millivolts)
// Set to 0 to disable boot protection
#define PWRMGT_VOLTAGE_BOOTLOCK 3300 // Won't boot below this voltage
// LPCOMP wake configuration (voltage recovery from SYSTEMOFF)
#define PWRMGT_LPCOMP_AIN 7 // AIN7 = P0.31 = PIN_VBAT
// IMPORTANT: The XIAO exposes battery via a resistor divider (ADC_MULTIPLIER = 3.0).
// LPCOMP measures the divided voltage, not the battery voltage directly.
// Vpin = VDD * (REFSEL fraction), and VBAT ≈ Vpin * ADC_MULTIPLIER.
//
// Using 3/8 VDD gives a wake threshold above the boot protection point:
// - If VDD ≈ 3.0V: VBAT ≈ (3.0 * 3/8) * 3 ≈ 3375mV
// - If VDD ≈ 3.3V: VBAT ≈ (3.3 * 3/8) * 3 ≈ 3712mV
#define PWRMGT_LPCOMP_REFSEL 2 // 3/8 VDD (~3.38-3.71V)
static const uint8_t A0 = PIN_A0;
static const uint8_t A1 = PIN_A1;
static const uint8_t A2 = PIN_A2;
static const uint8_t A3 = PIN_A3;
static const uint8_t A4 = PIN_A4;
static const uint8_t A5 = PIN_A5;
#define ADC_RESOLUTION (12)
// Other pins
#define PIN_NFC1 (30)
#define PIN_NFC2 (31)
// Serial interfaces
#define PIN_SERIAL1_RX (7)
#define PIN_SERIAL1_TX (6)
#define PIN_GPS_RX (7)
#define PIN_GPS_TX (6)
// SPI Interfaces
#define SPI_INTERFACES_COUNT (2)
#define PIN_SPI_MISO (9)
#define PIN_SPI_MOSI (10)
#define PIN_SPI_SCK (8)
#define PIN_SPI1_MISO (25)
#define PIN_SPI1_MOSI (26)
#define PIN_SPI1_SCK (29)
// Lora SPI is on SPI0
#define P_LORA_SCLK PIN_SPI_SCK
#define P_LORA_MISO PIN_SPI_MISO
#define P_LORA_MOSI PIN_SPI_MOSI
// Wire Interfaces
#define WIRE_INTERFACES_COUNT (1)
// PIN_WIRE_SCL/SDA default to D6/D7, which are Serial1. remap to NFC pins
#define PIN_WIRE_SDA PIN_NFC1
#define PIN_WIRE_SCL PIN_NFC2
#define PIN_LSM6DS3TR_C_POWER (15)
#define PIN_LSM6DS3TR_C_INT1 (18)
// PDM Interfaces
#define PIN_PDM_PWR (19)
#define PIN_PDM_CLK (20)
#define PIN_PDM_DIN (21)
// QSPI Pins
#define PIN_QSPI_SCK (24)
#define PIN_QSPI_CS (25)
#define PIN_QSPI_IO0 (26)
#define PIN_QSPI_IO1 (27)
#define PIN_QSPI_IO2 (28)
#define PIN_QSPI_IO3 (29)
// On-board QSPI Flash
#define EXTERNAL_FLASH_DEVICES (P25Q16H)
#define EXTERNAL_FLASH_USE_QSPI
#ifdef __cplusplus
}
#endif
/*----------------------------------------------------------------------------
* Arduino objects - C++ only
*----------------------------------------------------------------------------*/
#endif