From c96112b79f706b3e42435b31583e78f22ca22c3c Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:51:51 +0100 Subject: [PATCH] thinknode m6 port --- zephcore/CMakeLists.txt | 2 +- .../boards/common/nrf52_partitions_sdv6.dtsi | 14 +- .../boards/common/nrf52_partitions_sdv7.dtsi | 14 +- zephcore/boards/example_board/README.md | 20 ++ .../thinknode_m6/Kconfig.thinknode_m6 | 6 + .../boards/nrf52840/thinknode_m6/board.cmake | 13 + .../boards/nrf52840/thinknode_m6/board.conf | 23 ++ .../boards/nrf52840/thinknode_m6/board.yml | 10 + .../thinknode_m6/thinknode_m6-pinctrl.dtsi | 97 ++++++ .../nrf52840/thinknode_m6/thinknode_m6.dts | 325 ++++++++++++++++++ .../nrf52840/thinknode_m6/thinknode_m6.yaml | 20 ++ .../thinknode_m6/thinknode_m6_defconfig | 21 ++ .../formatter/boards/thinknode_m6/board.conf | 12 + .../boards/thinknode_m6/board.overlay | 37 ++ 14 files changed, 611 insertions(+), 3 deletions(-) create mode 100644 zephcore/boards/nrf52840/thinknode_m6/Kconfig.thinknode_m6 create mode 100644 zephcore/boards/nrf52840/thinknode_m6/board.cmake create mode 100644 zephcore/boards/nrf52840/thinknode_m6/board.conf create mode 100644 zephcore/boards/nrf52840/thinknode_m6/board.yml create mode 100644 zephcore/boards/nrf52840/thinknode_m6/thinknode_m6-pinctrl.dtsi create mode 100644 zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.dts create mode 100644 zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.yaml create mode 100644 zephcore/boards/nrf52840/thinknode_m6/thinknode_m6_defconfig create mode 100644 zephcore/tools/formatter/boards/thinknode_m6/board.conf create mode 100644 zephcore/tools/formatter/boards/thinknode_m6/board.overlay diff --git a/zephcore/CMakeLists.txt b/zephcore/CMakeLists.txt index 040e92b..ea81219 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" OR BOARD MATCHES "thinknode_m3") +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" OR BOARD MATCHES "thinknode_m6") 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/boards/common/nrf52_partitions_sdv6.dtsi b/zephcore/boards/common/nrf52_partitions_sdv6.dtsi index a726ad2..0cc2b67 100644 --- a/zephcore/boards/common/nrf52_partitions_sdv6.dtsi +++ b/zephcore/boards/common/nrf52_partitions_sdv6.dtsi @@ -6,7 +6,7 @@ * Use THIS file instead of sdv7 when the board's UF2 bootloader * bundles SoftDevice s140 v6.x (app starts at 0x26000). * - * Boards: RAK4631 + * Boards: RAK4631, ThinkNode M6 * * Usage in board overlay: * /delete-node/ &boot_partition; @@ -22,6 +22,18 @@ * 0xF4000 - 0x100000 (48KB) UF2 bootloader (reserved) */ +/ { + chosen { + /* nRF52840 SoC DTSI defines sram0 but does NOT set zephyr,sram + * in chosen. The upstream nrf52840_partition.dtsi provides it, + * but custom boards that include this file directly (without + * nrf52840_partition.dtsi) would get RAM = 0 in the linker + * script, causing "region RAM overflowed" on the first build. + * Set it here so all boards using this DTSI get it for free. */ + zephyr,sram = &sram0; + }; +}; + &flash0 { partitions { compatible = "fixed-partitions"; diff --git a/zephcore/boards/common/nrf52_partitions_sdv7.dtsi b/zephcore/boards/common/nrf52_partitions_sdv7.dtsi index 9bf9c75..bad6ccf 100644 --- a/zephcore/boards/common/nrf52_partitions_sdv7.dtsi +++ b/zephcore/boards/common/nrf52_partitions_sdv7.dtsi @@ -25,7 +25,7 @@ * │ - SD v7: Application starts at 0x27000 (156KB reserved) │ * │ Boards: T1000-E, Ikoka Nano 30dBm, Wio Tracker L1 │ * │ - SD v6: Application starts at 0x26000 (152KB reserved) │ - * │ Boards: RAK4631 │ + * │ Boards: RAK4631, ThinkNode M6 │ * │ │ * │ USAGE IN BOARD DTS (if base includes nrf52840_partition.dtsi): │ * │ /delete-node/ &boot_partition; │ @@ -51,6 +51,18 @@ * 0xF4000 - 0x100000 (48KB) UF2 bootloader (reserved) */ +/ { + chosen { + /* nRF52840 SoC DTSI defines sram0 but does NOT set zephyr,sram + * in chosen. The upstream nrf52840_partition.dtsi provides it, + * but custom boards that include this file directly (without + * nrf52840_partition.dtsi) would get RAM = 0 in the linker + * script, causing "region RAM overflowed" on the first build. + * Set it here so all boards using this DTSI get it for free. */ + zephyr,sram = &sram0; + }; +}; + &flash0 { partitions { compatible = "fixed-partitions"; diff --git a/zephcore/boards/example_board/README.md b/zephcore/boards/example_board/README.md index f920f79..1365766 100644 --- a/zephcore/boards/example_board/README.md +++ b/zephcore/boards/example_board/README.md @@ -14,6 +14,7 @@ Supported Boards | T1000-E | `west build -b t1000_e zephcore` | UF2 drag-drop or `west flash` | | ThinkNode M1 | `west build -b thinknode_m1 zephcore` | UF2 drag-drop or `west flash` | | ThinkNode M3 | `west build -b thinknode_m3 zephcore` | UF2 drag-drop or `west flash` | +| ThinkNode M6 | `west build -b thinknode_m6 zephcore` | UF2 drag-drop or `west flash` | | RAK WisMesh Tag | `west build -b rak_wismesh_tag zephcore` | UF2 drag-drop or `west flash` | | Ikoka Nano 30dBm | `west build -b ikoka_nano_30dbm zephcore` | UF2 drag-drop | @@ -136,6 +137,25 @@ A full custom board includes: __defconfig — Minimal defconfig board.cmake — Flash runner config +**Critical: `zephyr,sram` in the chosen node (nRF52840 only)** + +The nRF52840 SoC DTSI defines `sram0` but does NOT set `zephyr,sram` in +the chosen node. Without it, the linker gets `RAM size = 0` and every +build fails with "region 'RAM' overflowed" regardless of actual RAM use. + +Boards that include `` get this for free. +Boards that use `nrf52_partitions_sdv6.dtsi` or `nrf52_partitions_sdv7.dtsi` +directly (without the upstream include) also get it now — those DTSIs set +`zephyr,sram = &sram0` themselves. + +If you write a fully custom DTS that includes neither, add it yourself: + + chosen { + zephyr,sram = &sram0; + zephyr,code-partition = &code_partition; + ... + }; + What Goes in board.conf ----------------------- diff --git a/zephcore/boards/nrf52840/thinknode_m6/Kconfig.thinknode_m6 b/zephcore/boards/nrf52840/thinknode_m6/Kconfig.thinknode_m6 new file mode 100644 index 0000000..7228291 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/Kconfig.thinknode_m6 @@ -0,0 +1,6 @@ +# Copyright (c) 2025 ZephCore +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_THINKNODE_M6 + select SOC_NRF52840_QIAA diff --git a/zephcore/boards/nrf52840/thinknode_m6/board.cmake b/zephcore/boards/nrf52840/thinknode_m6/board.cmake new file mode 100644 index 0000000..34bb176 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/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_m6/board.conf b/zephcore/boards/nrf52840/thinknode_m6/board.conf new file mode 100644 index 0000000..cf50bd6 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/board.conf @@ -0,0 +1,23 @@ +# Elecrow ThinkNode M6 (nRF52840 + SX1262) +# Board-specific configuration +# +# Hardware: +# - nRF52840 SoC with BLE (DCDC regulator) +# - SX1262 LoRa radio (DIO2 RF switch, DIO3 TCXO 3.3V, 22dBm) +# - GPS L76K on UART0 (9600 baud, NMEA) +# - Battery ADC on AIN4 (P0.28), 1.75:1 voltage divider, ADC_CTRL=P0.11 +# - LEDs: RED=P0.12, BLUE=P0.07 (active-HIGH), TX LED = BLUE +# - Button on P0.17 (active-low, pull-up) +# - QSPI Flash MX25R1635F 2MB + +# Board identification (matches Arduino MeshCore variant name) +CONFIG_ZEPHCORE_BOARD_NAME="ThinkNode M6" + +# Device Information Service model name +CONFIG_BT_DIS_MODEL_NUMBER_STR="Elecrow ThinkNode-M6" + +# SoftDevice firmware ID (ThinkNode M6 bootloader uses S140 v6, same as M1/M3) +CONFIG_ZEPHCORE_SD_FWID=0x00B6 + +# Contacts — QSPI (2MB) provides ample storage for more contacts +CONFIG_ZEPHCORE_MAX_CONTACTS=510 diff --git a/zephcore/boards/nrf52840/thinknode_m6/board.yml b/zephcore/boards/nrf52840/thinknode_m6/board.yml new file mode 100644 index 0000000..3129c8b --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/board.yml @@ -0,0 +1,10 @@ +# Copyright (c) 2025 ZephCore +# +# SPDX-License-Identifier: Apache-2.0 + +board: + name: thinknode_m6 + full_name: Elecrow ThinkNode M6 (nRF52840 + SX1262) + vendor: elecrow + socs: + - name: nrf52840 diff --git a/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6-pinctrl.dtsi b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6-pinctrl.dtsi new file mode 100644 index 0000000..7a92c32 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6-pinctrl.dtsi @@ -0,0 +1,97 @@ +/* + * Elecrow ThinkNode M6 - Pin Control + * Copyright (c) 2025 ZephCore + * SPDX-License-Identifier: Apache-2.0 + * + * Pin assignments from Arduino variant.h and platformio.ini: + * - SPI1 (LoRa SX1262): SCK=P1.13, MOSI=P1.14, MISO=P1.15, NSS=P1.12 + * - I2C0 (sensors): SDA=P1.09, SCL=P0.08 + * - UART0 (GPS 9600): TX=P0.02 (→GPS RX), RX=P0.03 (←GPS TX) + * - QSPI (MX25R1635F): SCK=P1.03, CS=P0.23, IO0=P1.01, IO1=P1.02, + * IO2=P1.04, IO3=P1.05 + */ + +&pinctrl { + /* GPS UART0 - 9600 baud + * Note: PIN_GPS_TX/RX naming is from GPS module's perspective in variant.h. + * nRF UART TX → P0.02 (PIN_GPS_RX), nRF UART RX ← P0.03 (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; + }; + }; + + /* SPI1 for SX1262 LoRa - CS controlled manually (P1.12) */ + spi1_default: spi1_default { + group1 { + psels = , + , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + /* QSPI for MX25R1635F 2MB external flash */ + qspi_default: qspi_default { + group1 { + psels = , + , + , + , + , + ; + }; + }; + + qspi_sleep: qspi_sleep { + group1 { + psels = , + , + , + , + ; + low-power-enable; + }; + group2 { + psels = ; + low-power-enable; + bias-pull-up; + }; + }; +}; diff --git a/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.dts b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.dts new file mode 100644 index 0000000..08a0026 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.dts @@ -0,0 +1,325 @@ +/* + * Elecrow ThinkNode M6 — nRF52840 + SX1262 + * Copyright (c) 2025 ZephCore + * + * SPDX-License-Identifier: Apache-2.0 + * + * Hardware (from Arduino variant.h / platformio.ini): + * - nRF52840 SoC with BLE (DCDC regulator, NRF52BoardDCDC) + * - SX1262 LoRa radio on SPI1 (DIO2 RF switch, DIO3 TCXO 3.3V, 22dBm) + * NSS=P1.12, DIO1=P1.06, RESET=P1.10, BUSY=P1.11 + * - GPS L76K on UART0 (9600 baud, generic NMEA) + * Control: GPS_EN=P0.06 (active-HIGH), GPS_RESET=P0.29 (active-LOW), + * GPS_STANDBY=P0.30, GPS_PPS=P0.31 + * - Battery ADC on AIN4 (P0.28), 1.75:1 voltage divider + * ADC_CTRL enable pin: P0.11 (gpio-hog, always HIGH) + * - LEDs: RED=P0.12, BLUE=P0.07 (both active-HIGH, LED_STATE_ON=HIGH) + * TX LED = BLUE (P_LORA_TX_LED = PIN_LED_BLUE) + * - Button on P0.17 (active-low, pull-up) + * - I2C on P1.09/P0.08 for on-board sensors + * - QSPI Flash MX25R1635F (2MB): SCK=P1.03, CS=P0.23, IO0=P1.01, + * IO1=P1.02, IO2=P1.04, IO3=P1.05, enable=P0.21 + * - Power enable: PIN_PWR_EN=P0.27 (regulator-boot-on) + */ + +/dts-v1/; +#include +#include +#include +#include +#include "thinknode_m6-pinctrl.dtsi" + +/ { + model = "Elecrow ThinkNode M6"; + compatible = "elecrow,thinknode-m6"; + + chosen { + zephyr,sram = &sram0; + zephyr,code-partition = &code_partition; + zephyr,console = &cdc_acm_uart; + zephyr,shell-uart = &cdc_acm_uart; + }; + + leds { + compatible = "gpio-leds"; + + led_red: led_0 { + /* Active-high (LED_STATE_ON = HIGH in variant.h) */ + gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + label = "Red LED"; + }; + + led_blue: led_1 { + /* Active-high, also used as LoRa TX LED (P_LORA_TX_LED) */ + gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>; + label = "Blue LED"; + }; + }; + + buttons: buttons { + compatible = "gpio-keys"; + + user_button: button_0 { + /* Active-low, internal pull-up */ + gpios = <&gpio0 17 (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 on AIN4 (P0.28), 1.75:1 voltage divider. + * With GAIN_1_6 + internal ref (3600mV full scale) × 1.75 = 6300 multiplier. */ + zephyr,user { + io-channels = <&adc 4>; + vbat-mv-multiplier = <6300>; + }; + + /* Board power enable (PIN_PWR_EN = P0.27) — must be HIGH for peripherals */ + pwr_enable: pwr-enable { + compatible = "regulator-fixed"; + regulator-name = "pwr-enable"; + enable-gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + + /* QSPI flash enable (QSPI_FLASH_EN = P0.21) — must be HIGH before flash responds. + * WARNING: Nordic QSPI NOR driver hangs forever if flash doesn't respond. + * This regulator ensures flash is powered before driver init (priority 41). */ + qspi_flash_enable: qspi-flash-enable { + compatible = "regulator-fixed"; + regulator-name = "qspi-flash-enable"; + enable-gpios = <&gpio0 21 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + startup-delay-us = <1000>; + }; + + /* GPS enable (GPS_EN = P0.06, active-HIGH) — managed by ZephyrGPSManager */ + gps_en: gps-enable { + compatible = "gpio-leds"; + gps_enable_pin: gps_enable { + gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>; + label = "GPS Enable"; + }; + }; + + /* GPS hardware reset (GPS_RESET = P0.29, active-LOW) */ + gps_rst: gps-reset { + compatible = "gpio-leds"; + gps_reset_pin: gps_reset { + gpios = <&gpio0 29 GPIO_ACTIVE_LOW>; + label = "GPS Reset"; + }; + }; + + /* GPS standby (GPS_STANDBY = P0.30, active-HIGH = standby) */ + gps_stby: gps-standby { + compatible = "gpio-leds"; + gps_standby_pin: gps_standby { + gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + label = "GPS Standby"; + }; + }; + + aliases { + led0 = &led_red; + led1 = &led_blue; + lora-tx-led = &led_blue; + sw0 = &user_button; + watchdog0 = &wdt0; + lora0 = &lora; + gps-enable = &gps_enable_pin; + gps-reset = &gps_reset_pin; + gps-sleep-int = &gps_standby_pin; + }; +}; + +®0 { + status = "okay"; +}; + +®1 { + regulator-initial-mode = ; +}; + +&adc { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + /* Battery voltage on P0.28 (AIN4) — 1.75:1 voltage divider */ + channel@4 { + reg = <4>; + 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"; + + /* ADC control (PIN_ADC_CTRL = P0.11) — always HIGH to enable battery ADC. + * Arduino code toggles this before/after ADC reads; keeping it permanently + * HIGH is safe and avoids needing custom ADC ctrl support in ZephCore. */ + adc-ctrl-hog { + gpio-hog; + gpios = <11 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "ADC Ctrl"; + }; +}; + +&gpio1 { + status = "okay"; +}; + +/* GPS on UART0 (9600 baud) + * + * L76K GPS module (generic NMEA, multi-constellation). + * Control pins managed by ZephyrGPSManager via aliases: + * gps-enable (GPS_EN = P0.06): HIGH = GPS powered/active + * gps-reset (GPS_RESET = P0.29): LOW = reset asserted + * gps-sleep-int (GPS_STANDBY = P0.30): HIGH = standby + * + * zephyr,deferred-init: GPS must be powered (GPS_EN HIGH) before NMEA + * output begins. ZephyrGPSManager asserts GPS_EN 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 SX1262 LoRa */ +&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,sx1262"; + reg = <0>; + spi-max-frequency = <8000000>; + + reset-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; + busy-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; + dio1-gpios = <&gpio1 6 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; + + /* DIO2 drives the RF switch for TX/RX selection */ + dio2-tx-enable; + + /* DIO3 provides TCXO reference voltage at 3.3V */ + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <10>; + + /* RX boosted mode for better sensitivity (SX126X_RX_BOOSTED_GAIN=1) */ + rx-boosted; + }; +}; + +/* QSPI Flash — MX25R1635F 2MB */ +&qspi { + status = "okay"; + pinctrl-0 = <&qspi_default>; + pinctrl-1 = <&qspi_sleep>; + pinctrl-names = "default", "sleep"; + + qspi_flash: qspi_flash@0 { + compatible = "nordic,qspi-nor"; + reg = <0>; + writeoc = "pp"; + readoc = "fastread"; + sck-frequency = <16000000>; + jedec-id = [c2 28 15]; /* MX25R1635F */ + size = <16777216>; /* 2MB = 16Mbit */ + has-dpd; + t-enter-dpd = <10000>; + t-exit-dpd = <35000>; + }; +}; + +/* USB CDC for console/CLI */ +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" + +/* External QSPI flash partitions */ +&qspi_flash { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Full 2MB for LittleFS storage */ + qspi_storage_partition: partition@0 { + label = "qspi_storage"; + reg = <0x00000000 0x00200000>; + }; + }; +}; + +/* External QSPI /ext automount */ +#include "../../common/qspi-ext.dtsi" diff --git a/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.yaml b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.yaml new file mode 100644 index 0000000..29911de --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6.yaml @@ -0,0 +1,20 @@ +identifier: thinknode_m6 +name: Elecrow ThinkNode M6 (nRF52840 + SX1262) +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_m6/thinknode_m6_defconfig b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6_defconfig new file mode 100644 index 0000000..b6fe6d7 --- /dev/null +++ b/zephcore/boards/nrf52840/thinknode_m6/thinknode_m6_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 diff --git a/zephcore/tools/formatter/boards/thinknode_m6/board.conf b/zephcore/tools/formatter/boards/thinknode_m6/board.conf new file mode 100644 index 0000000..b4f719d --- /dev/null +++ b/zephcore/tools/formatter/boards/thinknode_m6/board.conf @@ -0,0 +1,12 @@ +# ThinkNode M6 formatter config +# Disable subsystems auto-enabled by M6 DTS nodes that bloat RAM: +# CONFIG_INPUT — gpio-keys + input-longpress + zephcore,input-multi-tap nodes +# CONFIG_ADC — battery ADC channel node +# CONFIG_REGULATOR — regulator-fixed nodes (replaced by gpio-hogs in board.overlay) +CONFIG_INPUT=n +CONFIG_ADC=n +CONFIG_REGULATOR=n + +# QSPI flash present — enable driver to erase /ext partition +CONFIG_NORDIC_QSPI_NOR=y +CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 diff --git a/zephcore/tools/formatter/boards/thinknode_m6/board.overlay b/zephcore/tools/formatter/boards/thinknode_m6/board.overlay new file mode 100644 index 0000000..9503be2 --- /dev/null +++ b/zephcore/tools/formatter/boards/thinknode_m6/board.overlay @@ -0,0 +1,37 @@ +/* + * ThinkNode M6 formatter overlay — minimal drivers, single LittleFS instance. + * + * The M6 main DTS includes both filesystem.dtsi (/lfs) and qspi-ext.dtsi + * (/ext), giving two LittleFS instances. Each needs ~8-10KB RAM for block + * caches; two instances overflow the formatter's RAM budget. Drop /ext here + * — the QSPI storage partition node remains so main.c can still erase it via + * FIXED_PARTITION_EXISTS(qspi_storage_partition). + * + * Also replace regulator-fixed power-enable nodes with gpio-hogs so + * CONFIG_REGULATOR is not forced on by regulator-boot-on. + */ + +/* Remove /ext LittleFS fstab — formatter only needs one LittleFS instance */ +/delete-node/ &qspi_lfs; + +/* Remove regulator-fixed nodes and replace with gpio-hogs */ +/delete-node/ &pwr_enable; +/delete-node/ &qspi_flash_enable; + +&gpio0 { + /* Board power enable (PIN_PWR_EN = P0.27) */ + pwr-en-hog { + gpio-hog; + gpios = <27 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "PWR Enable"; + }; + + /* QSPI flash enable (QSPI_FLASH_EN = P0.21) — must be HIGH before flash responds */ + qspi-flash-en-hog { + gpio-hog; + gpios = <21 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "QSPI Flash Enable"; + }; +};