thinknode m3 + wismesh tag ADC fix + fast advert for 1 min

This commit is contained in:
liquidraver
2026-03-08 21:23:28 +01:00
parent a71da9ba70
commit 463cee9b31
15 changed files with 557 additions and 10 deletions
+1
View File
@@ -87,3 +87,4 @@ WEST_UPDATE.md
# Side projects (not part of main firmware)
/doom/
THINKNODE_M1_HANDOVER.md
+1 -1
View File
@@ -210,7 +210,7 @@ set(ZEPHCORE_COMMON_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/zephcore_com
# Detect platform from board name and add platform-specific common config
# For boards with qualifiers like "wio_tracker_l1/nrf52840", check both the full BOARD
# string and the BOARD_QUALIFIERS which contains just the qualifier (e.g., "nrf52840")
if(BOARD MATCHES ".*nrf52.*" OR BOARD MATCHES "rak4631" OR BOARD MATCHES "rak_wismesh_tag" OR BOARD MATCHES "wio_tracker" OR BOARD MATCHES "ikoka_nano" OR BOARD MATCHES "t1000_e" OR BOARD MATCHES "thinknode_m1")
if(BOARD MATCHES ".*nrf52.*" OR BOARD MATCHES "rak4631" OR BOARD MATCHES "rak_wismesh_tag" OR BOARD MATCHES "wio_tracker" OR BOARD MATCHES "ikoka_nano" OR BOARD MATCHES "t1000_e" OR BOARD MATCHES "thinknode_m1" OR BOARD MATCHES "thinknode_m3")
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/nrf52_common.conf")
elseif(DEFINED BOARD_QUALIFIERS AND BOARD_QUALIFIERS MATCHES ".*nrf52.*")
set(ZEPHCORE_PLATFORM_CONF "${CMAKE_CURRENT_SOURCE_DIR}/boards/common/nrf52_common.conf")
+1 -1
View File
@@ -198,7 +198,7 @@ config ZEPHCORE_BLE_ADV_SLOW_INTERVAL
range 244 3200
help
Advertising interval in 0.625ms units.
338 = 211.25ms (Apple-compliant, balanced discovery/battery).
338 = 211.25ms (Apple-compliant, used after 60s fast window).
endmenu # BLE Configuration
+33 -5
View File
@@ -48,7 +48,9 @@ LOG_MODULE_REGISTER(zephcore_ble, CONFIG_ZEPHCORE_BLE_LOG_LEVEL);
* BLE stack when the link is marginal, fast enough to recover quickly. */
#define BLE_TX_OVERFLOW_RETRY_MS 250
/* Advertising interval (Apple Accessory Design Guidelines) */
/* Advertising intervals (Apple Accessory Design Guidelines §5.5) */
#define BT_ADV_FAST_INTERVAL 32 /* 20ms in 0.625ms units */
#define BT_ADV_FAST_DURATION_MS (60 * 1000) /* fast window after boot/disconnect */
#define BT_ADV_INTERVAL CONFIG_ZEPHCORE_BLE_ADV_SLOW_INTERVAL
/* ========== Frame type for queues ========== */
@@ -116,6 +118,9 @@ static enum zephcore_iface active_iface = ZEPHCORE_IFACE_NONE;
/* DLE tracking — set after successful DLE request to avoid double-request */
static bool dle_requested;
/* Fast advertising — true for BT_ADV_FAST_DURATION_MS after boot or disconnect */
static bool fast_adv_active;
/* Runtime BLE passkey */
static uint32_t ble_passkey = CONFIG_ZEPHCORE_BLE_PASSKEY;
@@ -171,9 +176,11 @@ STRUCT_SECTION_ITERABLE(bt_nus_inst, secure_nus) = {
static void tx_drain_work_fn(struct k_work *work);
static void overflow_retry_work_fn(struct k_work *work);
static void adv_slow_work_fn(struct k_work *work);
K_WORK_DELAYABLE_DEFINE(tx_drain_work, tx_drain_work_fn);
K_WORK_DELAYABLE_DEFINE(overflow_retry_work, overflow_retry_work_fn);
K_WORK_DELAYABLE_DEFINE(adv_slow_work, adv_slow_work_fn);
/* ========== TX completion callback ========== */
@@ -262,6 +269,9 @@ static void connected(struct bt_conn *conn, uint8_t err)
LOG_INF("connected: %s", addr);
current_conn = bt_conn_ref(conn);
/* Cancel fast→slow transition — already connected, no need to switch */
k_work_cancel_delayable(&adv_slow_work);
/* DLE is NOT requested here — the phone may start a PHY update LL
* procedure immediately, and BLE allows only one at a time.
* DLE is deferred to le_phy_updated() (after PHY negotiation completes)
@@ -338,6 +348,8 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
static void recycled(void)
{
LOG_DBG("restart advertising");
fast_adv_active = true;
k_work_reschedule(&adv_slow_work, K_MSEC(BT_ADV_FAST_DURATION_MS));
start_adv();
}
@@ -750,20 +762,32 @@ static ssize_t secure_nus_rx_write(struct bt_conn *conn, const struct bt_gatt_at
/* ========== Advertising ========== */
static void adv_slow_work_fn(struct k_work *work)
{
ARG_UNUSED(work);
LOG_INF("fast adv window expired, switching to slow interval");
bt_le_adv_stop();
fast_adv_active = false;
start_adv();
}
static void start_adv(void)
{
uint16_t interval = fast_adv_active ? BT_ADV_FAST_INTERVAL : BT_ADV_INTERVAL;
struct bt_le_adv_param adv_param = {
.id = BT_ID_DEFAULT,
.options = BT_LE_ADV_OPT_CONN,
.interval_min = BT_ADV_INTERVAL,
.interval_max = BT_ADV_INTERVAL,
.interval_min = interval,
.interval_max = interval,
};
int err = bt_le_adv_start(&adv_param, ad, ad_len, sd, sd_len);
if (err && err != -EALREADY) {
LOG_ERR("adv start failed: %d", err);
} else {
LOG_INF("BLE advertising: 211ms");
LOG_INF("BLE advertising: %s",
fast_adv_active ? "20ms fast (60s)" : "211ms slow");
}
}
@@ -791,6 +815,8 @@ void zephcore_ble_start(const char *name)
build_device_name_and_adv(name);
LOG_DBG("init complete, starting adv");
fast_adv_active = true;
k_work_reschedule(&adv_slow_work, K_MSEC(BT_ADV_FAST_DURATION_MS));
start_adv();
}
@@ -869,7 +895,9 @@ void zephcore_ble_set_enabled(bool enable)
bt_le_adv_stop();
LOG_INF("BLE disabled");
} else {
/* Re-enable advertising */
/* Re-enable advertising — start fast window */
fast_adv_active = true;
k_work_reschedule(&adv_slow_work, K_MSEC(BT_ADV_FAST_DURATION_MS));
start_adv();
LOG_INF("BLE enabled");
}
@@ -38,7 +38,7 @@
/ {
zephyr,user {
io-channels = <&adc 3>;
vbat-mv-multiplier = <4216>; /* RAK4631 voltage divider */
vbat-mv-multiplier = <6161>; /* Arduino: (3 * 1.73 * 1.187 * 1000) ≈ 6161, GAIN_1_6 + 0.6V ref */
};
};
@@ -132,10 +132,12 @@
};
/* ---- Battery ADC ---- */
/* P0.05 (AIN3), same divider circuit as RAK4631 */
/* P0.05 (AIN3), same divider circuit as RAK4631
* Arduino ADC_MULTIPLIER = (3 * 1.73 * 1.187 * 1000) ≈ 6161,
* applied to 12-bit average with default ref (GAIN_1_6 + 0.6V internal = 3.6V FS). */
zephyr,user {
io-channels = <&adc 3>;
vbat-mv-multiplier = <4216>;
vbat-mv-multiplier = <6161>;
};
/* ---- Buzzer on PWM0 ---- */
@@ -0,0 +1,6 @@
# Copyright (c) 2025 ZephCore
#
# SPDX-License-Identifier: Apache-2.0
config BOARD_THINKNODE_M3
select SOC_NRF52840_QIAA
@@ -0,0 +1,13 @@
# Copyright (c) 2025 ZephCore
# SPDX-License-Identifier: Apache-2.0
board_runner_args(jlink "--device=nRF52840_xxAA" "--speed=4000")
board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000")
set(OPENOCD_NRF5_SUBFAMILY "nrf52")
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/openocd-nrf5.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
@@ -0,0 +1,35 @@
# Elecrow ThinkNode M3 (nRF52840 + LR1110)
# Board-specific configuration
#
# Hardware:
# - nRF52840 SoC with BLE
# - LR1110 LoRa radio (TCXO 3.3V, DIO5/DIO6 RF switch)
# - GPS module on UART0 (9600 baud, 3-pin control)
# - Battery ADC on AIN3 (P0.05), 2:1 voltage divider
# - LEDs: GREEN=P1.03, RED=P1.01, POWER=P0.29
# - Button on P0.12 (active-low, pull-up)
# - Buzzer PWM on P0.23 with enable on P1.04
# Board identification (matches Arduino MeshCore variant name)
CONFIG_ZEPHCORE_BOARD_NAME="ThinkNode M3"
# Device Information Service model name
CONFIG_BT_DIS_MODEL_NUMBER_STR="Elecrow ThinkNode-M3"
# SoftDevice firmware ID (ThinkNode M3 bootloader uses S140 v6, same as M1)
CONFIG_ZEPHCORE_SD_FWID=0x00B6
# Radio type (TCXO, RF switch, PA config in DTS)
CONFIG_ZEPHCORE_RADIO_LR1110=y
# SPI for LR1110
CONFIG_SPI=y
# PWM for buzzer
CONFIG_PWM=y
# ThinkNode M3 has no display — enable LED heartbeat
CONFIG_ZEPHCORE_UI_DISPLAY=n
# RX duty cycle — note LR1110 guard is active, safe for battery-powered use
CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE=y
@@ -0,0 +1,72 @@
/*
* ThinkNode M3 board overlay - additional ZephCore-specific configuration
* SPDX-License-Identifier: Apache-2.0
*
* GPS control pins for the GPS module (chip TBD, generic NMEA at 9600 baud):
* - GPS_POWER (P0.14) - Main power enable (always HIGH, gpio-hog)
* - GPS_EN (P0.21) - Standby control (HIGH = awake, LOW = standby)
* - GPS_RESET (P0.25) - Reset (GPS_RESET_ACTIVE = LOW, REINIT pin)
*
* Power enable pins (always HIGH):
* - PIN_PWR_EN (P0.16) - Main power domain
* - BAT_POWER (P0.17) - Battery power rail
* - EEPROM_POWER (P0.07) - EEPROM power
* - LED_POWER (P0.29) - Power LED (always on)
*/
/ {
/* GPS standby control - P0.21 (GPS_EN, HIGH = active/awake) */
gps_en: gps-enable {
compatible = "gpio-leds";
gps_enable_pin: gps_enable {
gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>;
label = "GPS Enable";
};
};
aliases {
gps-enable = &gps_enable_pin;
};
};
&gpio0 {
/* GPS_POWER (P0.14) - always HIGH, main GPS power supply */
gps-power-hog {
gpio-hog;
gpios = <14 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "GPS Power";
};
/* PIN_PWR_EN (P0.16) - main power domain enable */
pwr-en-hog {
gpio-hog;
gpios = <16 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "PWR Enable";
};
/* BAT_POWER (P0.17) - battery power rail enable */
bat-power-hog {
gpio-hog;
gpios = <17 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "BAT Power";
};
/* EEPROM_POWER (P0.07) - EEPROM/sensor power */
eeprom-power-hog {
gpio-hog;
gpios = <7 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "EEPROM Power";
};
/* LED_POWER (P0.29) - power indicator LED, always on */
led-power-hog {
gpio-hog;
gpios = <29 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "LED Power";
};
};
@@ -0,0 +1,10 @@
# Copyright (c) 2025 ZephCore
#
# SPDX-License-Identifier: Apache-2.0
board:
name: thinknode_m3
full_name: Elecrow ThinkNode M3 (nRF52840 + LR1110)
vendor: elecrow
socs:
- name: nrf52840
@@ -0,0 +1,83 @@
/*
* Elecrow ThinkNode M3 - Pin Control
* Copyright (c) 2025 ZephCore
* SPDX-License-Identifier: Apache-2.0
*
* Pin assignments from Arduino variant.h and platformio.ini:
* - SPI: SCK=P1.13, MOSI=P1.14, MISO=P1.15, NSS=P1.12 (for LR1110)
* - I2C: SDA=P0.26, SCL=P0.27
* - UART0: TX=P0.22 (PIN_GPS_RX→GPS), RX=P0.20 (PIN_GPS_TX←GPS) at 9600 baud
* - LR1110: DIO1=P1.08, BUSY=P1.11, RESET=P1.10
* - PWM: P0.23 (buzzer, from PIN_BUZZER=23 in platformio.ini)
*/
&pinctrl {
/* GPS UART0 - 9600 baud
* Note: PIN_GPS_TX/RX naming is from GPS module's perspective in variant.h.
* nRF UART TX → P0.22 (PIN_GPS_RX), nRF UART RX ← P0.20 (PIN_GPS_TX). */
uart0_default: uart0_default {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 22)>;
};
group2 {
psels = <NRF_PSEL(UART_RX, 0, 20)>;
bias-pull-up;
};
};
uart0_sleep: uart0_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 0, 22)>,
<NRF_PSEL(UART_RX, 0, 20)>;
low-power-enable;
};
};
/* I2C0 for on-board sensors */
i2c0_default: i2c0_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
<NRF_PSEL(TWIM_SCL, 0, 27)>;
};
};
i2c0_sleep: i2c0_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 0, 26)>,
<NRF_PSEL(TWIM_SCL, 0, 27)>;
low-power-enable;
};
};
/* PWM0 for buzzer on P0.23 (PIN_BUZZER=23 from platformio.ini) */
pwm0_default: pwm0_default {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 0, 23)>;
};
};
pwm0_sleep: pwm0_sleep {
group1 {
psels = <NRF_PSEL(PWM_OUT0, 0, 23)>;
low-power-enable;
};
};
/* SPI1 for LR1110 - CS controlled manually (P1.12) */
spi1_default: spi1_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 13)>,
<NRF_PSEL(SPIM_MOSI, 1, 14)>,
<NRF_PSEL(SPIM_MISO, 1, 15)>;
};
};
spi1_sleep: spi1_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 13)>,
<NRF_PSEL(SPIM_MOSI, 1, 14)>,
<NRF_PSEL(SPIM_MISO, 1, 15)>;
low-power-enable;
};
};
};
@@ -0,0 +1,256 @@
/*
* Elecrow ThinkNode M3 - nRF52840 + LR1110
* Copyright (c) 2025 ZephCore
*
* SPDX-License-Identifier: Apache-2.0
*
* Hardware (from Arduino variant.h / platformio.ini):
* - nRF52840 SoC with BLE
* - LR1110 LoRa radio on SPI1 (TCXO 3.3V, DIO5/DIO6 RF switch)
* - GPS module on UART0 (9600 baud, generic NMEA; chip TBD)
* Control: GPS_POWER=P0.14 (always on), GPS_EN=P0.21 (standby), GPS_RESET=P0.25
* - Battery ADC on AIN3 (P0.05), 2:1 voltage divider
* - LEDs: GREEN=P1.03, RED=P1.01 (active-low), POWER=P0.29 (always on via overlay)
* - Button on P0.12 (active-low, pull-up), single button with multi-tap
* - Buzzer PWM on P0.23 with enable on P1.04
* - I2C on P0.26/P0.27 for on-board sensors
* - Power enables: P0.16 (PWR_EN), P0.17 (BAT_POWER), P0.07 (EEPROM_POWER)
* (all set HIGH via gpio-hogsn in board.overlay)
*/
/dts-v1/;
#include <nordic/nrf52840_qiaa.dtsi>
#include <nordic/nrf52840_partition.dtsi>
#include <zephyr/dt-bindings/adc/nrf-saadc.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include <zephyr/dt-bindings/pwm/pwm.h>
#include "thinknode_m3-pinctrl.dtsi"
/* Delete default partitions from nrf52840_partition.dtsi */
/delete-node/ &boot_partition;
/delete-node/ &slot0_partition;
/delete-node/ &slot1_partition;
/delete-node/ &storage_partition;
/ {
model = "Elecrow ThinkNode M3";
compatible = "elecrow,thinknode-m3";
chosen {
zephyr,code-partition = &code_partition;
zephyr,console = &cdc_acm_uart;
zephyr,shell-uart = &cdc_acm_uart;
};
leds {
compatible = "gpio-leds";
led_green: led_0 {
/* Active-low (LED_STATE_ON = LOW in Arduino variant.h) */
gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
label = "Green LED";
};
led_red: led_1 {
gpios = <&gpio1 1 GPIO_ACTIVE_LOW>;
label = "Red LED";
};
};
buttons: buttons {
compatible = "gpio-keys";
user_button: button_0 {
/* Active-low (USER_BTN_PRESSED = LOW), internal pull-up */
gpios = <&gpio0 12 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
zephyr,code = <INPUT_KEY_0>;
label = "User Button";
};
};
/* Long-press detection (1000ms) */
user_btn_longpress {
compatible = "zephyr,input-longpress";
input = <&buttons>;
input-codes = <INPUT_KEY_0>;
short-codes = <INPUT_KEY_A>;
long-codes = <INPUT_KEY_F>;
long-delay-ms = <1000>;
};
/* Multi-tap detection
* 1 tap → KEY_1 = page next
* 2 taps → KEY_B = flood advert
* 3 taps → KEY_D = buzzer mute toggle
* 4 taps → KEY_C = GPS on/off */
user_btn_multitap {
compatible = "zephcore,input-multi-tap";
input-codes = <INPUT_KEY_A>;
tap-codes = <INPUT_KEY_1 INPUT_KEY_B INPUT_KEY_D INPUT_KEY_C>;
tap-delay-ms = <400>;
};
/* Battery ADC channel reference for ZephyrBoard
* 2:1 voltage divider on AIN3 (P0.05).
* With GAIN_1_6 + internal ref (3600mV full scale) × 2 = 7200 multiplier. */
zephyr,user {
io-channels = <&adc 3>;
vbat-mv-multiplier = <7200>;
};
/* Buzzer on PWM0 channel 0 (P0.23, PIN_BUZZER=23) */
pwmbuzzer {
compatible = "pwm-leds";
buzzer: buzzer {
pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>;
};
};
/* Buzzer enable pin (P1.04, PIN_BUZZER_EN=36) */
buzzer_enable: buzzer-enable {
compatible = "regulator-fixed";
regulator-name = "buzzer-enable";
enable-gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
};
aliases {
led0 = &led_green;
led1 = &led_red;
sw0 = &user_button;
watchdog0 = &wdt0;
buzzer = &buzzer;
buzzer-enable = &buzzer_enable;
lora0 = &lora;
};
};
&reg0 {
status = "okay";
};
&reg1 {
regulator-initial-mode = <NRF5X_REG_MODE_DCDC>;
};
&adc {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
/* Battery voltage on P0.05 (AIN3) - 2:1 voltage divider */
channel@3 {
reg = <3>;
zephyr,gain = "ADC_GAIN_1_6";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME(ADC_ACQ_TIME_MICROSECONDS, 10)>;
zephyr,input-positive = <NRF_SAADC_AIN3>;
zephyr,resolution = <12>;
};
};
&uicr {
nfct-pins-as-gpios;
};
&gpiote {
status = "okay";
};
&gpio0 {
status = "okay";
};
&gpio1 {
status = "okay";
};
/* PWM0 for buzzer on P0.23 */
&pwm0 {
status = "okay";
pinctrl-0 = <&pwm0_default>;
pinctrl-1 = <&pwm0_sleep>;
pinctrl-names = "default", "sleep";
};
/* GPS on UART0 (9600 baud)
*
* Using gnss-nmea-generic (passive NMEA listener) — the GPS chip is unknown
* but the Arduino firmware uses MicroNMEA (generic NMEA parser only, no
* proprietary commands). The module is controlled via 3 GPIOs in the overlay:
* GPS_POWER=P0.14 (always on), GPS_EN=P0.21 (standby via gps-enable alias).
*
* zephyr,deferred-init: GPS module needs GPIO power-up (GPS_EN HIGH) before
* NMEA output. ZephyrGPSManager handles power-up then calls device_init(). */
&uart0 {
compatible = "nordic,nrf-uarte";
status = "okay";
current-speed = <9600>;
pinctrl-0 = <&uart0_default>;
pinctrl-1 = <&uart0_sleep>;
pinctrl-names = "default", "sleep";
gnss: gnss {
compatible = "gnss-nmea-generic";
zephyr,deferred-init;
};
};
/* I2C0 for on-board sensors */
&i2c0 {
compatible = "nordic,nrf-twim";
status = "okay";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c0_default>;
pinctrl-1 = <&i2c0_sleep>;
pinctrl-names = "default", "sleep";
/* All supported environment & power sensors — auto-detected at runtime */
#include "../../common/sensors-i2c.dtsi"
};
/* SPI1 for LR1110 */
&spi1 {
compatible = "nordic,nrf-spim";
status = "okay";
cs-gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi1_default>;
pinctrl-1 = <&spi1_sleep>;
pinctrl-names = "default", "sleep";
lora: lora@0 {
compatible = "semtech,lr1110";
reg = <0>;
reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
busy-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
dio1-gpios = <&gpio1 8 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>;
tcxo-voltage-mv = <1800>;
tcxo-startup-delay-ms = <5>;
rx-boosted;
spi-max-frequency = <8000000>;
/* RF switch: DIO5=bit0, DIO6=bit1
* Table from Arduino target.cpp rfswitch_table:
* STBY: DIO5=L, DIO6=L → 0x00
* RX: DIO5=H, DIO6=L → 0x01
* TX: DIO5=H, DIO6=H → 0x03
* TX_HP: DIO5=L, DIO6=H → 0x02
* GNSS: DIO5=L, DIO6=L → 0x00 */
rfswitch-enable = <0x03>;
rfswitch-standby = <0x00>;
rfswitch-rx = <0x01>;
rfswitch-tx = <0x03>;
rfswitch-tx-hp = <0x02>;
rfswitch-gnss = <0x00>;
};
};
zephyr_udc0: &usbd {
compatible = "nordic,nrf-usbd";
status = "okay";
cdc_acm_uart: cdc_acm_uart {
compatible = "zephyr,cdc-acm-uart";
};
};
/* SoftDevice v6 partition layout (S140 v6 — Adafruit nRF52 bootloader) */
#include "../../common/nrf52_partitions_sdv6.dtsi"
@@ -0,0 +1,20 @@
identifier: thinknode_m3
name: Elecrow ThinkNode M3 (nRF52840 + LR1110)
type: mcu
arch: arm
ram: 256
flash: 1024
toolchain:
- zephyr
- gnuarmemb
- xtools
supported:
- adc
- ble
- gpio
- i2c
- nvs
- spi
- usb_device
- watchdog
vendor: elecrow
@@ -0,0 +1,21 @@
# Copyright (c) 2025 ZephCore
# SPDX-License-Identifier: Apache-2.0
# Enable MPU
CONFIG_ARM_MPU=y
# Enable hardware stack protection
CONFIG_HW_STACK_PROTECTION=y
# Enable GPIO
CONFIG_GPIO=y
# Enable UART driver
CONFIG_SERIAL=y
# Enable console
CONFIG_CONSOLE=y
# Build UF2 by default
CONFIG_BUILD_OUTPUT_UF2=y
CONFIG_USE_DT_CODE_PARTITION=y