Skip to content

Commit 1897f51

Browse files
authored
Merge pull request #601 from khudson/dev
Adding support for Ikoka Stick with Seeed Xiao nRF54 baseboard.
2 parents a2eed71 + bed3113 commit 1897f51

File tree

8 files changed

+605
-0
lines changed

8 files changed

+605
-0
lines changed

src/helpers/ui/SSD1306Display.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ bool SSD1306Display::i2c_probe(TwoWire& wire, uint8_t addr) {
77
}
88

99
bool SSD1306Display::begin() {
10+
#ifdef DISPLAY_ROTATION
11+
display.setRotation(DISPLAY_ROTATION);
12+
#endif
1013
return display.begin(SSD1306_SWITCHCAPVCC, DISPLAY_ADDRESS, true, false) && i2c_probe(Wire, DISPLAY_ADDRESS);
1114
}
1215

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#ifdef XIAO_NRF52
2+
3+
#include <Arduino.h>
4+
#include "ikoka_stick_nrf_board.h"
5+
6+
#include <bluefruit.h>
7+
#include <Wire.h>
8+
9+
static BLEDfu bledfu;
10+
11+
static void connect_callback(uint16_t conn_handle)
12+
{
13+
(void)conn_handle;
14+
MESH_DEBUG_PRINTLN("BLE client connected");
15+
}
16+
17+
static void disconnect_callback(uint16_t conn_handle, uint8_t reason)
18+
{
19+
(void)conn_handle;
20+
(void)reason;
21+
22+
MESH_DEBUG_PRINTLN("BLE client disconnected");
23+
}
24+
25+
void ikoka_stick_nrf_board::begin() {
26+
// for future use, sub-classes SHOULD call this from their begin()
27+
startup_reason = BD_STARTUP_NORMAL;
28+
29+
pinMode(PIN_VBAT, INPUT);
30+
pinMode(VBAT_ENABLE, OUTPUT);
31+
digitalWrite(VBAT_ENABLE, HIGH);
32+
33+
#ifdef PIN_USER_BTN
34+
pinMode(PIN_USER_BTN, INPUT_PULLUP);
35+
#endif
36+
37+
#if defined(PIN_WIRE_SDA) && defined(PIN_WIRE_SCL)
38+
Wire.setPins(PIN_WIRE_SDA, PIN_WIRE_SCL);
39+
#endif
40+
41+
Wire.begin();
42+
43+
#ifdef P_LORA_TX_LED
44+
pinMode(P_LORA_TX_LED, OUTPUT);
45+
digitalWrite(P_LORA_TX_LED, HIGH);
46+
#endif
47+
48+
// pinMode(SX126X_POWER_EN, OUTPUT);
49+
// digitalWrite(SX126X_POWER_EN, HIGH);
50+
delay(10); // give sx1262 some time to power up
51+
}
52+
53+
bool ikoka_stick_nrf_board::startOTAUpdate(const char* id, char reply[]) {
54+
// Config the peripheral connection with maximum bandwidth
55+
// more SRAM required by SoftDevice
56+
// Note: All config***() function must be called before begin()
57+
Bluefruit.configPrphBandwidth(BANDWIDTH_MAX);
58+
Bluefruit.configPrphConn(92, BLE_GAP_EVENT_LENGTH_MIN, 16, 16);
59+
60+
Bluefruit.begin(1, 0);
61+
// Set max power. Accepted values are: -40, -30, -20, -16, -12, -8, -4, 0, 4
62+
Bluefruit.setTxPower(4);
63+
// Set the BLE device name
64+
Bluefruit.setName("XIAO_NRF52_OTA");
65+
66+
Bluefruit.Periph.setConnectCallback(connect_callback);
67+
Bluefruit.Periph.setDisconnectCallback(disconnect_callback);
68+
69+
// To be consistent OTA DFU should be added first if it exists
70+
bledfu.begin();
71+
72+
// Set up and start advertising
73+
// Advertising packet
74+
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
75+
Bluefruit.Advertising.addTxPower();
76+
Bluefruit.Advertising.addName();
77+
78+
/* Start Advertising
79+
- Enable auto advertising if disconnected
80+
- Interval: fast mode = 20 ms, slow mode = 152.5 ms
81+
- Timeout for fast mode is 30 seconds
82+
- Start(timeout) with timeout = 0 will advertise forever (until connected)
83+
84+
For recommended advertising interval
85+
https://developer.apple.com/library/content/qa/qa1931/_index.html
86+
*/
87+
Bluefruit.Advertising.restartOnDisconnect(true);
88+
Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms
89+
Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode
90+
Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds
91+
92+
strcpy(reply, "OK - started");
93+
return true;
94+
95+
96+
return false;
97+
}
98+
99+
#endif
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#pragma once
2+
3+
#include <MeshCore.h>
4+
#include <Arduino.h>
5+
6+
#ifdef XIAO_NRF52
7+
8+
// redefine lora pins if using the S3 variant of SX1262 board
9+
#ifdef SX1262_XIAO_S3_VARIANT
10+
#undef P_LORA_DIO_1
11+
#undef P_LORA_BUSY
12+
#undef P_LORA_RESET
13+
#undef P_LORA_NSS
14+
#undef SX126X_RXEN
15+
#define P_LORA_DIO_1 D0
16+
#define P_LORA_BUSY D1
17+
#define P_LORA_RESET D2
18+
#define P_LORA_NSS D3
19+
#define SX126X_RXEN D4
20+
#endif
21+
22+
class ikoka_stick_nrf_board : public mesh::MainBoard {
23+
protected:
24+
uint8_t startup_reason;
25+
26+
public:
27+
void begin();
28+
uint8_t getStartupReason() const override { return startup_reason; }
29+
30+
#if defined(P_LORA_TX_LED)
31+
void onBeforeTransmit() override {
32+
digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED on
33+
}
34+
void onAfterTransmit() override {
35+
digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED off
36+
}
37+
#endif
38+
39+
uint16_t getBattMilliVolts() override {
40+
// Please read befor going further ;)
41+
// https://wiki.seeedstudio.com/XIAO_BLE#q3-what-are-the-considerations-when-using-xiao-nrf52840-sense-for-battery-charging
42+
43+
// We can't drive VBAT_ENABLE to HIGH as long
44+
// as we don't know wether we are charging or not ...
45+
// this is a 3mA loss (4/1500)
46+
digitalWrite(VBAT_ENABLE, LOW);
47+
int adcvalue = 0;
48+
analogReadResolution(12);
49+
analogReference(AR_INTERNAL_3_0);
50+
delay(10);
51+
adcvalue = analogRead(PIN_VBAT);
52+
return (adcvalue * ADC_MULTIPLIER * AREF_VOLTAGE) / 4.096;
53+
}
54+
55+
const char* getManufacturerName() const override {
56+
return "Ikoka Stick (Xiao-nrf52)";
57+
}
58+
59+
void reboot() override {
60+
NVIC_SystemReset();
61+
}
62+
63+
bool startOTAUpdate(const char* id, char reply[]) override;
64+
};
65+
66+
#endif
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
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+
adafruit/Adafruit INA3221 Library @ ^1.0.1
20+
adafruit/Adafruit INA219 @ ^1.2.3
21+
adafruit/Adafruit AHTX0 @ ^2.0.5
22+
adafruit/Adafruit BME280 Library @ ^2.3.0
23+
adafruit/Adafruit SSD1306 @ ^2.5.13
24+
25+
26+
[ikoka_stick_nrf]
27+
extends = nrf52840_xiao
28+
;board_build.ldscript = boards/nrf52840_s140_v7.ld
29+
build_flags = ${nrf52840_xiao.build_flags}
30+
-D P_LORA_TX_LED=11
31+
-I variants/ikoka_stick_nrf
32+
-I src/helpers/nrf52
33+
-D DISPLAY_CLASS=SSD1306Display
34+
-D DISPLAY_ROTATION=2
35+
-D RADIO_CLASS=CustomSX1262
36+
-D WRAPPER_CLASS=CustomSX1262Wrapper
37+
-D LORA_TX_POWER=9
38+
-D P_LORA_DIO_1=D1
39+
-D P_LORA_RESET=D2
40+
-D P_LORA_BUSY=D3
41+
-D P_LORA_NSS=D4
42+
-D SX126X_RXEN=D5
43+
-D SX126X_TXEN=RADIOLIB_NC
44+
-D SX126X_DIO2_AS_RF_SWITCH=1
45+
-D SX126X_DIO3_TCXO_VOLTAGE=1.8
46+
-D SX126X_CURRENT_LIMIT=140
47+
-D SX126X_RX_BOOSTED_GAIN=1
48+
-D PIN_USER_BTN=0
49+
-D PIN_WIRE_SCL=7
50+
-D PIN_WIRE_SDA=6
51+
-D ENV_INCLUDE_AHTX0=1
52+
-D ENV_INCLUDE_BME280=1
53+
-D ENV_INCLUDE_INA3221=1
54+
-D ENV_INCLUDE_INA219=1
55+
build_src_filter = ${nrf52840_xiao.build_src_filter}
56+
+<helpers/*.cpp>
57+
+<helpers/sensors>
58+
+<helpers/ui/SSD1306Display.cpp>
59+
+<../variants/ikoka_stick_nrf>
60+
debug_tool = jlink
61+
upload_protocol = nrfutil
62+
63+
[env:ikoka_stick_nrf_companion_radio_ble]
64+
extends = ikoka_stick_nrf
65+
build_flags =
66+
${ikoka_stick_nrf.build_flags}
67+
-D MAX_CONTACTS=100
68+
-D MAX_GROUP_CHANNELS=8
69+
-D BLE_PIN_CODE=123456
70+
-D OFFLINE_QUEUE_SIZE=256
71+
; -D BLE_DEBUG_LOGGING=1
72+
; -D MESH_PACKET_LOGGING=1
73+
; -D MESH_DEBUG=1
74+
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
75+
+<helpers/nrf52/SerialBLEInterface.cpp>
76+
+<../examples/companion_radio>
77+
lib_deps =
78+
${ikoka_stick_nrf.lib_deps}
79+
densaugeo/base64 @ ~1.4.0
80+
81+
[env:ikoka_stick_nrf_companion_radio_usb]
82+
extends = ikoka_stick_nrf
83+
build_flags =
84+
${ikoka_stick_nrf.build_flags}
85+
-D MAX_CONTACTS=100
86+
-D MAX_GROUP_CHANNELS=8
87+
; -D MESH_PACKET_LOGGING=1
88+
; -D MESH_DEBUG=1
89+
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
90+
+<helpers/nrf52/SerialBLEInterface.cpp>
91+
+<../examples/companion_radio>
92+
lib_deps =
93+
${ikoka_stick_nrf.lib_deps}
94+
densaugeo/base64 @ ~1.4.0
95+
96+
[env:ikoka_stick_nrf_alt_pinout_companion_radio_ble]
97+
extends = env:ikoka_stick_nrf_companion_radio_ble
98+
build_flags =
99+
${env:ikoka_stick_nrf_companion_radio_ble.build_flags}
100+
-D SX1262_XIAO_S3_VARIANT
101+
102+
[env:ikoka_stick_nrf_repeater]
103+
extends = ikoka_stick_nrf
104+
build_flags =
105+
${ikoka_stick_nrf.build_flags}
106+
-D ADVERT_NAME='"Ikoka Stick Repeater"'
107+
-D ADVERT_LAT=0.0
108+
-D ADVERT_LON=0.0
109+
-D ADMIN_PASSWORD='"password"'
110+
-D MAX_NEIGHBOURS=8
111+
; -D MESH_PACKET_LOGGING=1
112+
; -D MESH_DEBUG=1
113+
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
114+
+<../examples/simple_repeater/main.cpp>
115+
116+
[env:ikoka_stick_nrf_alt_pinout_repeater]
117+
extends = env:ikoka_stick_nrf_repeater
118+
build_flags =
119+
${env:ikoka_stick_nrf_repeater.build_flags}
120+
-D SX1262_XIAO_S3_VARIANT
121+
122+
[env:ikoka_stick_nrf_room_server]
123+
extends = ikoka_stick_nrf
124+
build_flags =
125+
${ikoka_stick_nrf.build_flags}
126+
-D ADVERT_NAME='"Ikoka Stick Room"'
127+
-D ADVERT_LAT=0.0
128+
-D ADVERT_LON=0.0
129+
-D ADMIN_PASSWORD='"password"'
130+
; -D MESH_PACKET_LOGGING=1
131+
; -D MESH_DEBUG=1
132+
build_src_filter = ${ikoka_stick_nrf.build_src_filter}
133+
+<../examples/simple_room_server/main.cpp>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <Arduino.h>
2+
#include "target.h"
3+
#include <helpers/ArduinoHelpers.h>
4+
5+
ikoka_stick_nrf_board board;
6+
7+
#ifdef DISPLAY_CLASS
8+
DISPLAY_CLASS display;
9+
#endif
10+
11+
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI);
12+
13+
WRAPPER_CLASS radio_driver(radio, board);
14+
15+
VolatileRTCClock fallback_clock;
16+
AutoDiscoverRTCClock rtc_clock(fallback_clock);
17+
EnvironmentSensorManager sensors;
18+
19+
bool radio_init() {
20+
rtc_clock.begin(Wire);
21+
22+
return radio.std_init(&SPI);
23+
}
24+
25+
uint32_t radio_get_rng_seed() {
26+
return radio.random(0x7FFFFFFF);
27+
}
28+
29+
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) {
30+
radio.setFrequency(freq);
31+
radio.setSpreadingFactor(sf);
32+
radio.setBandwidth(bw);
33+
radio.setCodingRate(cr);
34+
}
35+
36+
void radio_set_tx_power(uint8_t dbm) {
37+
radio.setOutputPower(dbm);
38+
}
39+
40+
mesh::LocalIdentity radio_new_identity() {
41+
RadioNoiseListener rng(radio);
42+
return mesh::LocalIdentity(&rng); // create new random identity
43+
}

variants/ikoka_stick_nrf/target.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#define RADIOLIB_STATIC_ONLY 1
4+
#include <RadioLib.h>
5+
#include <helpers/radiolib/RadioLibWrappers.h>
6+
#include <ikoka_stick_nrf_board.h>
7+
#include <helpers/radiolib/CustomSX1262Wrapper.h>
8+
#include <helpers/AutoDiscoverRTCClock.h>
9+
#include <helpers/ArduinoHelpers.h>
10+
#include <helpers/sensors/EnvironmentSensorManager.h>
11+
12+
#ifdef DISPLAY_CLASS
13+
#include <helpers/ui/SSD1306Display.h>
14+
extern DISPLAY_CLASS display;
15+
#endif
16+
17+
extern ikoka_stick_nrf_board board;
18+
extern WRAPPER_CLASS radio_driver;
19+
extern AutoDiscoverRTCClock rtc_clock;
20+
extern EnvironmentSensorManager sensors;
21+
22+
bool radio_init();
23+
uint32_t radio_get_rng_seed();
24+
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
25+
void radio_set_tx_power(uint8_t dbm);
26+
mesh::LocalIdentity radio_new_identity();

0 commit comments

Comments
 (0)