From 463cee9b31a55e01afa769c9327c4b8adbe5a3d5 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Sun, 8 Mar 2026 21:23:28 +0100 Subject: [PATCH] thinknode m3 + wismesh tag ADC fix + fast advert for 1 min --- .gitignore | 1 + zephcore/CMakeLists.txt | 2 +- zephcore/Kconfig | 2 +- zephcore/adapters/ble/ZephyrBLE.cpp | 38 ++- .../boards/nrf52840/rak4631/board.overlay | 2 +- .../rak_wismesh_tag/rak_wismesh_tag.dts | 6 +- .../thinknode_m3/Kconfig.thinknode_m3 | 6 + .../boards/nrf52840/thinknode_m3/board.cmake | 13 + .../boards/nrf52840/thinknode_m3/board.conf | 35 +++ .../nrf52840/thinknode_m3/board.overlay | 72 +++++ .../boards/nrf52840/thinknode_m3/board.yml | 10 + .../thinknode_m3/thinknode_m3-pinctrl.dtsi | 83 ++++++ .../nrf52840/thinknode_m3/thinknode_m3.dts | 256 ++++++++++++++++++ .../nrf52840/thinknode_m3/thinknode_m3.yaml | 20 ++ .../thinknode_m3/thinknode_m3_defconfig | 21 ++ 15 files changed, 557 insertions(+), 10 deletions(-) create mode 100644 zephcore/boards/nrf52840/thinknode_m3/Kconfig.thinknode_m3 create mode 100644 zephcore/boards/nrf52840/thinknode_m3/board.cmake create mode 100644 zephcore/boards/nrf52840/thinknode_m3/board.conf create mode 100644 zephcore/boards/nrf52840/thinknode_m3/board.overlay create mode 100644 zephcore/boards/nrf52840/thinknode_m3/board.yml create mode 100644 zephcore/boards/nrf52840/thinknode_m3/thinknode_m3-pinctrl.dtsi create mode 100644 zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.dts create mode 100644 zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.yaml create mode 100644 zephcore/boards/nrf52840/thinknode_m3/thinknode_m3_defconfig diff --git a/.gitignore b/.gitignore index 75644cf..b001782 100644 --- a/.gitignore +++ b/.gitignore @@ -87,3 +87,4 @@ WEST_UPDATE.md # Side projects (not part of main firmware) /doom/ +THINKNODE_M1_HANDOVER.md diff --git a/zephcore/CMakeLists.txt b/zephcore/CMakeLists.txt index 1fafe28..24b82dd 100644 --- a/zephcore/CMakeLists.txt +++ b/zephcore/CMakeLists.txt @@ -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") diff --git a/zephcore/Kconfig b/zephcore/Kconfig index a07a58a..1289d57 100644 --- a/zephcore/Kconfig +++ b/zephcore/Kconfig @@ -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 diff --git a/zephcore/adapters/ble/ZephyrBLE.cpp b/zephcore/adapters/ble/ZephyrBLE.cpp index d95ec76..1a729f7 100644 --- a/zephcore/adapters/ble/ZephyrBLE.cpp +++ b/zephcore/adapters/ble/ZephyrBLE.cpp @@ -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"); } diff --git a/zephcore/boards/nrf52840/rak4631/board.overlay b/zephcore/boards/nrf52840/rak4631/board.overlay index 7d57000..0514762 100644 --- a/zephcore/boards/nrf52840/rak4631/board.overlay +++ b/zephcore/boards/nrf52840/rak4631/board.overlay @@ -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 */ }; }; diff --git a/zephcore/boards/nrf52840/rak_wismesh_tag/rak_wismesh_tag.dts b/zephcore/boards/nrf52840/rak_wismesh_tag/rak_wismesh_tag.dts index 5e00886..f60be7a 100644 --- a/zephcore/boards/nrf52840/rak_wismesh_tag/rak_wismesh_tag.dts +++ b/zephcore/boards/nrf52840/rak_wismesh_tag/rak_wismesh_tag.dts @@ -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 ---- */ diff --git a/zephcore/boards/nrf52840/thinknode_m3/Kconfig.thinknode_m3 b/zephcore/boards/nrf52840/thinknode_m3/Kconfig.thinknode_m3 new file mode 100644 index 0000000..ffe9312 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/Kconfig.thinknode_m3 @@ -0,0 +1,6 @@ +# Copyright (c) 2025 ZephCore +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_THINKNODE_M3 + select SOC_NRF52840_QIAA diff --git a/zephcore/boards/nrf52840/thinknode_m3/board.cmake b/zephcore/boards/nrf52840/thinknode_m3/board.cmake new file mode 100644 index 0000000..34bb176 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/board.cmake @@ -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) diff --git a/zephcore/boards/nrf52840/thinknode_m3/board.conf b/zephcore/boards/nrf52840/thinknode_m3/board.conf new file mode 100644 index 0000000..28c0dd7 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/board.conf @@ -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 diff --git a/zephcore/boards/nrf52840/thinknode_m3/board.overlay b/zephcore/boards/nrf52840/thinknode_m3/board.overlay new file mode 100644 index 0000000..f5b7ba7 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/board.overlay @@ -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"; + }; +}; diff --git a/zephcore/boards/nrf52840/thinknode_m3/board.yml b/zephcore/boards/nrf52840/thinknode_m3/board.yml new file mode 100644 index 0000000..97dccb0 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/board.yml @@ -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 diff --git a/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3-pinctrl.dtsi b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3-pinctrl.dtsi new file mode 100644 index 0000000..2ea032c --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3-pinctrl.dtsi @@ -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 = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + /* I2C0 for on-board sensors */ + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + /* PWM0 for buzzer on P0.23 (PIN_BUZZER=23 from platformio.ini) */ + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + /* SPI1 for LR1110 - CS controlled manually (P1.12) */ + spi1_default: spi1_default { + group1 { + psels = , + , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; +}; diff --git a/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.dts b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.dts new file mode 100644 index 0000000..c098924 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.dts @@ -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 +#include +#include +#include +#include +#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 = ; + label = "User Button"; + }; + }; + + /* Long-press detection (1000ms) */ + user_btn_longpress { + compatible = "zephyr,input-longpress"; + input = <&buttons>; + input-codes = ; + short-codes = ; + long-codes = ; + 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 = ; + tap-codes = ; + 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; + }; +}; + +®0 { + status = "okay"; +}; + +®1 { + regulator-initial-mode = ; +}; + +&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 = ; + zephyr,input-positive = ; + 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 = ; + 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" diff --git a/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.yaml b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.yaml new file mode 100644 index 0000000..db20174 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3.yaml @@ -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 diff --git a/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3_defconfig b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3_defconfig new file mode 100644 index 0000000..b6fe6d7 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m3/thinknode_m3_defconfig @@ -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