Skip to content

Commit 8ee251a

Browse files
authored
Merge pull request #185 from fdlamotte/xiao-nrf52
Xiao nrf52
2 parents 1d4ae9f + 82bcd74 commit 8ee251a

File tree

8 files changed

+621
-0
lines changed

8 files changed

+621
-0
lines changed
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_v7.ld"
5+
},
6+
"core": "nRF5",
7+
"cpu": "cortex-m4",
8+
"extra_flags": "-DARDUINO_Seeed_XIAO_nRF52840 -DNRF52840_XXAA -DSEEED_XIAO_NRF52840 ",
9+
"f_cpu": "64000000L",
10+
"hwids": [
11+
[ "0x2886", "0x8044" ],
12+
[ "0x2886", "0x0044" ]
13+
],
14+
"mcu": "nrf52840",
15+
"variant": "Seeed_XIAO_nRF52840",
16+
"softdevice": {
17+
"sd_flags": "-DS140",
18+
"sd_name": "s140",
19+
"sd_version": "7.3.0",
20+
"sd_fwid": "0x0123"
21+
},
22+
"bsp": {
23+
"name": "adafruit"
24+
},
25+
"bootloader": {
26+
"settings_addr": "0xFF000"
27+
},
28+
"usb_product": "XIAO nRF52840"
29+
},
30+
"connectivity": [
31+
"bluetooth"
32+
],
33+
"debug": {
34+
"jlink_device": "nRF52840_xxAA",
35+
"openocd_target": "nrf52.cfg",
36+
"svd_path": "nrf52840.svd"
37+
},
38+
"frameworks": [
39+
"arduino"
40+
],
41+
"name": "Seeed Studio XIAO nRF52840",
42+
"upload": {
43+
"maximum_ram_size": 237568,
44+
"maximum_size": 811008,
45+
"protocol": "nrfutil",
46+
"speed": 115200,
47+
"protocols": [
48+
"jlink",
49+
"nrfjprog",
50+
"nrfutil",
51+
"cmsis-dap",
52+
"sam-ba",
53+
"blackmagic"
54+
],
55+
"use_1200bps_touch": true,
56+
"require_upload_port": true,
57+
"wait_for_upload_port": true
58+
},
59+
"url": "https://wiki.seeedstudio.com/XIAO_BLE",
60+
"vendor": "Seeed Studio"
61+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include <Arduino.h>
2+
#include "XiaoNrf52Board.h"
3+
4+
#include <bluefruit.h>
5+
#include <Wire.h>
6+
7+
static BLEDfu bledfu;
8+
9+
static void connect_callback(uint16_t conn_handle)
10+
{
11+
(void)conn_handle;
12+
MESH_DEBUG_PRINTLN("BLE client connected");
13+
}
14+
15+
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
16+
{
17+
(void)conn_handle;
18+
(void)reason;
19+
20+
MESH_DEBUG_PRINTLN("BLE client disconnected");
21+
}
22+
23+
void XiaoNrf52Board::begin() {
24+
// for future use, sub-classes SHOULD call this from their begin()
25+
startup_reason = BD_STARTUP_NORMAL;
26+
27+
pinMode(PIN_VBAT, INPUT);
28+
pinMode(VBAT_ENABLE, OUTPUT);
29+
digitalWrite(VBAT_ENABLE, HIGH);
30+
31+
#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL)
32+
Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL);
33+
#endif
34+
35+
Wire.begin();
36+
37+
#ifdef P_LORA_TX_LED
38+
pinMode(P_LORA_TX_LED, OUTPUT);
39+
digitalWrite(P_LORA_TX_LED, HIGH);
40+
#endif
41+
42+
// pinMode(SX126X_POWER_EN, OUTPUT);
43+
// digitalWrite(SX126X_POWER_EN, HIGH);
44+
delay(10); // give sx1262 some time to power up
45+
}
46+
47+
bool XiaoNrf52Board::startOTAUpdate(const char* id, char reply[]) {
48+
// Config the peripheral connection with maximum bandwidth
49+
// more SRAM required by SoftDevice
50+
// Note: All config***() function must be called before begin()
51+
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
52+
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
53+
54+
Bluefruit.begin(1, 0);
55+
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
56+
Bluefruit.setTxPower(4);
57+
// Set the BLE device name
58+
Bluefruit.setName("XIAO_NRF52_OTA");
59+
60+
Bluefruit.Periph.setConnectCallback(connect_callback);
61+
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
62+
63+
// To be consistent OTA DFU should be added first if it exists
64+
bledfu.begin();
65+
66+
// Set up and start advertising
67+
// Advertising packet
68+
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
69+
Bluefruit.Advertising.addTxPower();
70+
Bluefruit.Advertising.addName();
71+
72+
/* Start Advertising
73+
- Enable auto advertising if disconnected
74+
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
75+
- Timeout for fast mode is 30 seconds
76+
- Start(timeout) with timeout = 0 will advertise forever (until connected)
77+
78+
For recommended advertising interval
79+
https://developer.apple.com/library/content/qa/qa1931/_index.html
80+
*/
81+
Bluefruit.Advertising.restartOnDisconnect(true);
82+
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
83+
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
84+
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
85+
86+
strcpy(reply, "OK - started");
87+
return true;
88+
89+
90+
return false;
91+
}

src/helpers/nrf52/XiaoNrf52Board.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#pragma once
2+
3+
#include <MeshCore.h>
4+
#include <Arduino.h>
5+
6+
// LoRa radio module pins for Seeed Xiao-nrf52
7+
#ifdef SX1262_XIAO_S3_VARIANT
8+
#define P_LORA_DIO_1 D0
9+
#define P_LORA_BUSY D1
10+
#define P_LORA_RESET D2
11+
#define P_LORA_NSS D3
12+
#define LORA_TX_BOOST_PIN D4
13+
#else
14+
#define P_LORA_DIO_1 D1
15+
#define P_LORA_BUSY D3
16+
#define P_LORA_RESET D2
17+
#define P_LORA_NSS D4
18+
#define LORA_TX_BOOST_PIN D5
19+
#endif
20+
#define P_LORA_SCLK PIN_SPI_SCK
21+
#define P_LORA_MISO PIN_SPI_MISO
22+
#define P_LORA_MOSI PIN_SPI_MOSI
23+
//#define SX126X_POWER_EN 37
24+
25+
#define SX126X_DIO2_AS_RF_SWITCH true
26+
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
27+
28+
29+
class XiaoNrf52Board : public mesh::MainBoard {
30+
protected:
31+
uint8_t startup_reason;
32+
33+
public:
34+
void begin();
35+
uint8_t getStartupReason() const override { return startup_reason; }
36+
37+
#if defined(P_LORA_TX_LED)
38+
void onBeforeTransmit() override {
39+
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
40+
}
41+
void onAfterTransmit() override {
42+
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
43+
}
44+
#endif
45+
46+
uint16_t getBattMilliVolts() override {
47+
// Please read befor going further ;)
48+
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
49+
50+
pinMode(BAT_NOT_CHARGING, INPUT);
51+
if (digitalRead(BAT_NOT_CHARGING) == HIGH) {
52+
int adcvalue = 0;
53+
analogReadResolution(12);
54+
analogReference(AR_INTERNAL_3_0);
55+
digitalWrite(VBAT_ENABLE, LOW);
56+
delay(10);
57+
adcvalue = analogRead(PIN_VBAT);
58+
digitalWrite(VBAT_ENABLE, HIGH);
59+
return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;
60+
} else {
61+
digitalWrite(VBAT_ENABLE, HIGH); // ensures high !
62+
return 4200; // charging value
63+
}
64+
}
65+
66+
const char* getManufacturerName() const override {
67+
return "Seeed Xiao-nrf52";
68+
}
69+
70+
void reboot() override {
71+
NVIC_SystemReset();
72+
}
73+
74+
bool startOTAUpdate(const char* id, char reply[]) override;
75+
};

variants/xiao_nrf52/platformio.ini

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
[nrf52840_xiao]
2+
extends = nrf52_base
3+
platform_packages =
4+
toolchain-gccarmnoneeabi@~1.100301.0
5+
framework-arduinoadafruitnrf52
6+
board = seeed-xiao-afruitnrf52-nrf52840
7+
board_build.ldscript = boards/nrf52840_s140_v7.ld
8+
build_flags = ${nrf52_base.build_flags}
9+
-D NRF52_PLATFORM -D XIAO_NRF52
10+
-I lib/nrf52/s140_nrf52_7.3.0_API/include
11+
-I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52
12+
lib_ignore =
13+
BluetoothOTA
14+
lvgl
15+
lib5b4
16+
lib_deps =
17+
${nrf52_base.lib_deps}
18+
rweather/Crypto @ ^0.4.0
19+
20+
[Xiao_nrf52]
21+
extends = nrf52840_xiao
22+
;board_build.ldscript = boards/nrf52840_s140_v7.ld
23+
build_flags = ${nrf52840_xiao.build_flags}
24+
-D P_LORA_TX_LED=11
25+
-I variants/xiao_nrf52
26+
-I src/helpers/nrf52
27+
-D RADIO_CLASS=CustomSX1262
28+
-D WRAPPER_CLASS=CustomSX1262Wrapper
29+
-D LORA_TX_POWER=22
30+
-D SX126X_CURRENT_LIMIT=130
31+
-D SX126X_RX_BOOSTED_GAIN=1
32+
build_src_filter = ${nrf52840_xiao.build_src_filter}
33+
+<helpers/*.cpp>
34+
+<helpers/nrf52/XiaoNrf52Board.cpp>
35+
+<../variants/xiao_nrf52>
36+
debug_tool = jlink
37+
upload_protocol = nrfutil
38+
39+
[env:Xiao_nrf52_companion_radio_ble]
40+
extends = Xiao_nrf52
41+
build_flags =
42+
${Xiao_nrf52.build_flags}
43+
-D MAX_CONTACTS=100
44+
-D MAX_GROUP_CHANNELS=8
45+
-D BLE_PIN_CODE=123456
46+
; -D BLE_DEBUG_LOGGING=1
47+
; -D ENABLE_PRIVATE_KEY_IMPORT=1
48+
; -D ENABLE_PRIVATE_KEY_EXPORT=1
49+
-D MESH_PACKET_LOGGING=1
50+
-D MESH_DEBUG=1
51+
build_src_filter = ${Xiao_nrf52.build_src_filter}
52+
+<helpers/nrf52/SerialBLEInterface.cpp>
53+
+<../examples/companion_radio/main.cpp>
54+
lib_deps =
55+
${Xiao_nrf52.lib_deps}
56+
densaugeo/base64 @ ~1.4.0
57+
58+
[env:Xiao_nrf52_alt_pinout_companion_radio_ble]
59+
extends = env:Xiao_nrf52_companion_radio_ble
60+
build_flags =
61+
${env:Xiao_nrf52_companion_radio_ble.build_flags}
62+
-D SX1262_XIAO_S3_VARIANT
63+
64+
[env:Xiao_nrf52_repeater]
65+
extends = Xiao_nrf52
66+
build_flags =
67+
${Xiao_nrf52.build_flags}
68+
-D ADVERT_NAME='"Xiao_nrf52 Repeater"'
69+
-D ADVERT_LAT=0.0
70+
-D ADVERT_LON=0.0
71+
-D ADMIN_PASSWORD='"password"'
72+
; -D MESH_PACKET_LOGGING=1
73+
; -D MESH_DEBUG=1
74+
build_src_filter = ${Xiao_nrf52.build_src_filter}
75+
+<../examples/simple_repeater/main.cpp>
76+
77+
[env:Xiao_nrf52_alt_pinout_repeater]
78+
extends = env:Xiao_nrf52_repeater
79+
build_flags =
80+
${env:Xiao_nrf52_repeater.build_flags}
81+
-D SX1262_XIAO_S3_VARIANT

variants/xiao_nrf52/target.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <Arduino.h>
2+
#include "target.h"
3+
#include <helpers/ArduinoHelpers.h>
4+
5+
XiaoNrf52Board board;
6+
7+
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
8+
9+
WRAPPER_CLASS radio_driver(radio, board);
10+
11+
VolatileRTCClock rtc_clock;
12+
13+
#ifndef LORA_CR
14+
#define LORA_CR 5
15+
#endif
16+
17+
bool radio_init() {
18+
// rtc_clock.begin(Wire);
19+
20+
#ifdef SX126X_DIO3_TCXO_VOLTAGE
21+
float tcxo = SX126X_DIO3_TCXO_VOLTAGE;
22+
#else
23+
float tcxo = 1.6f;
24+
#endif
25+
26+
SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI);
27+
SPI.begin();
28+
int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo);
29+
if (status != RADIOLIB_ERR_NONE) {
30+
Serial.print("ERROR: radio init failed: ");
31+
Serial.println(status);
32+
return false; // fail
33+
}
34+
35+
radio.setCRC(1);
36+
37+
#ifdef SX126X_CURRENT_LIMIT
38+
radio.setCurrentLimit(SX126X_CURRENT_LIMIT);
39+
#endif
40+
#ifdef SX126X_DIO2_AS_RF_SWITCH
41+
radio.setDio2AsRfSwitch(SX126X_DIO2_AS_RF_SWITCH);
42+
#endif
43+
#ifdef SX126X_RX_BOOSTED_GAIN
44+
radio.setRxBoostedGainMode(SX126X_RX_BOOSTED_GAIN);
45+
#endif
46+
47+
return true; // success
48+
}
49+
50+
uint32_t radio_get_rng_seed() {
51+
return radio.random(0x7FFFFFFF);
52+
}
53+
54+
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
55+
radio.setFrequency(freq);
56+
radio.setSpreadingFactor(sf);
57+
radio.setBandwidth(bw);
58+
radio.setCodingRate(cr);
59+
}
60+
61+
void radio_set_tx_power(uint8_t dbm) {
62+
radio.setOutputPower(dbm);
63+
}
64+
65+
mesh::LocalIdentity radio_new_identity() {
66+
RadioNoiseListener rng(radio);
67+
return mesh::LocalIdentity(&rng); // create new random identity
68+
}

0 commit comments

Comments
 (0)