From 568d311ab0310bb9e040b30eb600b6a3edb7e614 Mon Sep 17 00:00:00 2001 From: rlwilliamson-dev <123014229+rlwilliamson-dev@users.noreply.github.com> Date: Mon, 1 Jun 2026 16:22:19 -0500 Subject: [PATCH] boards: add GAT562 30S Mesh Kit (nRF52840, RAK4631 core) The GAT562 30S Mesh Kit is an nRF52840 + SX1262 board built on the RAK4631 WisBlock core module with a 30 dBm (1 W) external PA, so it reuses the proven rak4631 LoRa path. Deltas vs rak4631: 1.8 V TCXO (per the MeshCore variant), battery multiplier 6232, buzzer on P1.01, an AT6558R UART GPS, active-high LEDs, and a 5-way joystick that selects the joystick companion menu UI. A single board serves both the full kit and the screenless solar repeater pod; absent peripherals (OLED, GPS, joystick, buzzer) are optional in devicetree and skipped at runtime. Board-specific notes: - GPS: AT6558R NMEA on UART0 @ 9600 (P0.15 RX / P0.16 TX), powered by a WB_IO2/P1.02 gpio-hog and parsed by gnss-nmea-generic. Uses CONFIG_UART_ASYNC_API (DMA receive); nRF UARTE interrupt-driven RX did not feed the modem backend. - The 6 button/joystick inputs are routed to GPIO SENSE (sense-edge-mask on &gpio0) so they don't consume the GPIOTE channel the SX1262 DIO1 "done" IRQ needs. Registration: board definition, CMakeLists.txt platform-conf match, build.sh (nRF_boards), supported_boards.md, the top-level README board table, and the porting-guide board table. Hardware-tested on the kit, companion and repeater: LoRa TX/RX with BLE active (no CAD errors), BLE pairing (PIN 123456) and two-way messaging, joystick menu UI, SSD1306 OLED, buzzer, battery %, UF2 + DFU-zip flashing, and a 14-satellite GPS fix. --- README.md | 1 + build.sh | 1 + zephcore/CMakeLists.txt | 2 +- zephcore/boards/example_board/README.md | 1 + .../nrf52840/gat562_30s/Kconfig.gat562_30s | 6 + .../boards/nrf52840/gat562_30s/board.cmake | 10 + .../boards/nrf52840/gat562_30s/board.conf | 34 ++ zephcore/boards/nrf52840/gat562_30s/board.yml | 6 + .../gat562_30s/gat562_30s-pinctrl.dtsi | 132 +++++++ .../boards/nrf52840/gat562_30s/gat562_30s.dts | 340 ++++++++++++++++++ .../nrf52840/gat562_30s/gat562_30s_defconfig | 30 ++ .../nrf52840/gat562_30s/pre_dt_board.cmake | 5 + zephcore/boards/supported_boards.md | 1 + 13 files changed, 568 insertions(+), 1 deletion(-) create mode 100644 zephcore/boards/nrf52840/gat562_30s/Kconfig.gat562_30s create mode 100644 zephcore/boards/nrf52840/gat562_30s/board.cmake create mode 100644 zephcore/boards/nrf52840/gat562_30s/board.conf create mode 100644 zephcore/boards/nrf52840/gat562_30s/board.yml create mode 100644 zephcore/boards/nrf52840/gat562_30s/gat562_30s-pinctrl.dtsi create mode 100644 zephcore/boards/nrf52840/gat562_30s/gat562_30s.dts create mode 100644 zephcore/boards/nrf52840/gat562_30s/gat562_30s_defconfig create mode 100644 zephcore/boards/nrf52840/gat562_30s/pre_dt_board.cmake diff --git a/README.md b/README.md index 2107e43..f6124e8 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Other benefits: | **ThinkNode M6** | SX1262 | GPS (L76K), QSPI flash, RGB LEDs | | **LilyGo T-Echo** | SX1262 (TCXO 1.8V) | GPS (L76K), 1.54" e-paper (SSD1681), BME280, QSPI flash, touch-button backlight | | **Ikoka Nano 30dBm** | SX1262 (E22-900M30S, 30 dBm PA) | RGB LEDs | +| **GAT562 30S Mesh Kit** | SX1262 (30 dBm / 1 W PA) | RAK4631 core module. OLED (SSD1306), 5-way joystick, buzzer, GPS, BME280 pad, 2×18650 + solar | | **SenseCAP Solar** | SX1262 | GPS (L76K), QSPI flash, battery monitor | | **XIAO nRF52840 + Wio-SX1262** | SX1262 | Bare XIAO + Wio-SX1262 expansion | | **ProMicro SX1262** | SX1262 (E22-900M30S) | GPS, battery ADC, button, LED | diff --git a/build.sh b/build.sh index 649478c..279ee32 100644 --- a/build.sh +++ b/build.sh @@ -20,6 +20,7 @@ nRF_boards=( lilygo_techo promicro_sx1262 heltec_t114 + gat562_30s ) ESP32_boards=( diff --git a/zephcore/CMakeLists.txt b/zephcore/CMakeLists.txt index df928a5..571eade 100644 --- a/zephcore/CMakeLists.txt +++ b/zephcore/CMakeLists.txt @@ -255,7 +255,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 "rak3401_1watt" 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" OR BOARD MATCHES "promicro_lr2021" OR BOARD MATCHES "promicro_sx1262" OR BOARD MATCHES "sensecap_solar" OR BOARD MATCHES "xiao_nrf52840" OR BOARD MATCHES "lilygo_techo" OR BOARD MATCHES "heltec_t114") +if(BOARD MATCHES ".*nrf52.*" OR BOARD MATCHES "rak4631" OR BOARD MATCHES "rak_wismesh_tag" OR BOARD MATCHES "rak3401_1watt" 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" OR BOARD MATCHES "promicro_lr2021" OR BOARD MATCHES "promicro_sx1262" OR BOARD MATCHES "sensecap_solar" OR BOARD MATCHES "xiao_nrf52840" OR BOARD MATCHES "lilygo_techo" OR BOARD MATCHES "heltec_t114" OR BOARD MATCHES "gat562") 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/example_board/README.md b/zephcore/boards/example_board/README.md index dc6768b..46782f8 100644 --- a/zephcore/boards/example_board/README.md +++ b/zephcore/boards/example_board/README.md @@ -21,6 +21,7 @@ Supported Boards | 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 | +| GAT562 30S Mesh Kit | `west build -b gat562_30s zephcore` | UF2 drag-drop or `west flash` | | LilyGo T-Echo | `west build -b lilygo_techo zephcore` | UF2 drag-drop or `west flash` | | Heltec T114 | `west build -b heltec_t114 zephcore` | UF2 drag-drop or `west flash` | diff --git a/zephcore/boards/nrf52840/gat562_30s/Kconfig.gat562_30s b/zephcore/boards/nrf52840/gat562_30s/Kconfig.gat562_30s new file mode 100644 index 0000000..3e1741a --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/Kconfig.gat562_30s @@ -0,0 +1,6 @@ +# GAT562 30S Mesh Kit board selection +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_GAT562_30S + select SOC_NRF52840_QIAA + select ZEPHCORE_UI_JOYSTICK # 5-way joystick -> full companion menu UI diff --git a/zephcore/boards/nrf52840/gat562_30s/board.cmake b/zephcore/boards/nrf52840/gat562_30s/board.cmake new file mode 100644 index 0000000..f79da42 --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/board.cmake @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 +# GAT562 30S Mesh Kit — nRF52840 (same SWD/UF2 runners as RAK4631) + +board_runner_args(jlink "--device=nRF52840_xxAA" "--speed=4000") +board_runner_args(pyocd "--target=nrf52840" "--frequency=4000000") +include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake) +include(${ZEPHYR_BASE}/boards/common/nrfjprog.board.cmake) +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) diff --git a/zephcore/boards/nrf52840/gat562_30s/board.conf b/zephcore/boards/nrf52840/gat562_30s/board.conf new file mode 100644 index 0000000..1dc2792 --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/board.conf @@ -0,0 +1,34 @@ +# GAT562 30S Mesh Kit (nRF52840 + SX1262) +# +# Built on the RAK4631 core module with a 30 dBm (1 W) external PA. The SX1262 +# is driven at the ZephCore default 22 dBm; the onboard PA brings the antenna +# output up to ~30 dBm. DIO2 keys the T/R switch, DIO3 supplies the 1.8 V TCXO +# (see gat562_30s.dts). Flash layout matches RAK4631 (SoftDevice s140 v6, +# app @ 0x26000), so the stock UF2 bootloader is reused — no re-flash needed. +# +# Most features are auto-detected from devicetree: +# - PWM + buzzer (buzzer nodelabel) +# - SSD1306 OLED (zephyr,display chosen) -> also UI_DISPLAY below +# - LoRa RX duty cycle (companion + SX1262) +# - battery ADC, GPS, LEDs, user button + +# Board identification +CONFIG_ZEPHCORE_BOARD_NAME="GAT562 30S Mesh Kit" +CONFIG_BT_DIS_MODEL_NUMBER_STR="GAT562_30S" + +# SoftDevice firmware ID (s140 v6.1.1 — same as RAK4631) +CONFIG_ZEPHCORE_SD_FWID=0x00B6 + +# Compile in the UI display stack; the OLED panel is optional at runtime. +CONFIG_ZEPHCORE_UI_DISPLAY=y + +# GPS: AT6558R UART NMEA receiver on UART0 @ 9600 baud (P0.15 RX / P0.16 TX), +# powered by the WB_IO2/P1.02 gpio-hog (see gat562_30s.dts). The +# gnss-nmea-generic driver is auto-selected from the DTS node; CONFIG_GNSS and +# CONFIG_MODEM_MODULES come from boards/common/zephcore_common.conf. +# +# Use the async (DMA) UART receive path for the GPS: nRF UARTE's interrupt- +# driven RX did not feed modem_backend_uart reliably here, so the modem chat +# never saw any NMEA. CONFIG_UART_ASYNC_API switches the backend to its +# DMA-based receiver, which delivers the stream correctly. +CONFIG_UART_ASYNC_API=y diff --git a/zephcore/boards/nrf52840/gat562_30s/board.yml b/zephcore/boards/nrf52840/gat562_30s/board.yml new file mode 100644 index 0000000..36dde89 --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/board.yml @@ -0,0 +1,6 @@ +board: + name: gat562_30s + full_name: GAT562 30S Mesh Kit (nRF52840 + SX1262, 30dBm/1W) + vendor: gat + socs: + - name: nrf52840 diff --git a/zephcore/boards/nrf52840/gat562_30s/gat562_30s-pinctrl.dtsi b/zephcore/boards/nrf52840/gat562_30s/gat562_30s-pinctrl.dtsi new file mode 100644 index 0000000..06ad2c7 --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/gat562_30s-pinctrl.dtsi @@ -0,0 +1,132 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * GAT562 30S Mesh Kit pin control. + * + * RAK4631 core-module pinout (UART/I2C/SPI/QSPI identical to upstream + * rak4631) plus a PWM channel for the onboard buzzer on P1.01. + */ + +&pinctrl { + /* GPS on UART0: MCU TX P0.16 -> GPS RX, MCU RX P0.15 <- GPS TX. + * The GPS is wired to P0.15/P0.16; it runs on UARTE0 because UARTE1's + * interrupt-driven RX did not feed the modem backend on this SoC (the + * other nRF52 GPS boards in this tree also use uart0 + gnss-nmea-generic). */ + uart0_default: uart0_default { + group1 { + psels = , + ; + }; + }; + + uart0_sleep: uart0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + /* GPS on UART1: MCU TX P0.16 -> GPS RX, MCU RX P0.15 <- GPS TX */ + uart1_default: uart1_default { + group1 { + psels = , + ; + }; + }; + + uart1_sleep: uart1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + /* I2C0: SSD1306 OLED + sensors (SDA P0.13 / SCL P0.14) */ + i2c0_default: i2c0_default { + group1 { + psels = , + ; + }; + }; + + i2c0_sleep: i2c0_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + /* I2C1 (P0.24/P0.25) — defined for parity, not enabled */ + i2c1_default: i2c1_default { + group1 { + psels = , + ; + }; + }; + + i2c1_sleep: i2c1_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; + + /* LoRa SX1262 on SPI1: SCK P1.11 / MOSI P1.12 / MISO P1.13 */ + spi1_default: spi1_default { + group1 { + psels = , + , + ; + }; + }; + + spi1_sleep: spi1_sleep { + group1 { + psels = , + , + ; + low-power-enable; + }; + }; + + /* Buzzer on PWM0 -> P1.01 */ + pwm0_default: pwm0_default { + group1 { + psels = ; + }; + }; + + pwm0_sleep: pwm0_sleep { + group1 { + psels = ; + low-power-enable; + }; + }; + + /* QSPI pins (kept for parity; &qspi is disabled on this board) */ + qspi_default: qspi_default { + group1 { + psels = , + , + , + , + , + ; + }; + }; + + qspi_sleep: qspi_sleep { + group1 { + psels = , + , + , + , + , + ; + low-power-enable; + }; + }; +}; diff --git a/zephcore/boards/nrf52840/gat562_30s/gat562_30s.dts b/zephcore/boards/nrf52840/gat562_30s/gat562_30s.dts new file mode 100644 index 0000000..15683e4 --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/gat562_30s.dts @@ -0,0 +1,340 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * GAT562 30S Mesh Kit — nRF52840 + SX1262 on a RAK4631 core module, with a + * 30 dBm (1 W) external PA, SSD1306 OLED, GPS, buzzer, 2x18650 + solar input. + * + * LoRa wiring is identical to the RAK4631 WisBlock core: + * SCK P1.11 MOSI P1.12 MISO P1.13 NSS P1.10 + * RST P1.06 BUSY P1.14 DIO1 P1.15 PWR_EN P1.05 (hog HIGH) + * DIO2 = T/R switch, DIO3 = TCXO. + * + * GAT562-specific vs a stock RAK4631: + * - DIO3 TCXO at 1.8 V (matches the official MeshCore GAT562 variant) + * - Battery multiplier 6232 (vs 6161): 3 * 1.75 * 1.187 * 1000 + * - Buzzer on P1.01 (PWM0) + * - GPS: UART NMEA on UART0 @ 9600 (MCU RX P0.15 / TX P0.16), always-on + * - 6 buttons on GPIO SENSE (sense-edge-mask) so DIO1 keeps a GPIOTE chan + * - LEDs active-high: green P1.03 (LoRa TX), blue P1.04 + * - User button P0.09 (NFC1) + */ + +/dts-v1/; +#include +#include "gat562_30s-pinctrl.dtsi" +#include +#include +#include +#include + +/ { + model = "GAT562 30S Mesh Kit"; + compatible = "gat,gat562-30s"; + + chosen { + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &code_partition; + zephyr,console = &cdc_acm_uart; + zephyr,shell-uart = &cdc_acm_uart; + zephyr,display = &ssd1306; + }; + + aliases { + lora0 = &lora; + led0 = &green_led; + led1 = &blue_led; + lora-tx-led = &green_led; + sw0 = &user_button; + buzzer = &buzzer; + watchdog0 = &wdt0; + }; + + leds { + compatible = "gpio-leds"; + /* Active-high on GAT562 (LED_STATE_ON = 1; TX LED driven HIGH) */ + green_led: led_1 { + gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + label = "Green LED"; + }; + blue_led: led_2 { + gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>; + label = "Blue LED"; + }; + }; + + /* + * Inputs: back/menu button (P0.09) + 5-way joystick (P0.28/04/30/31/26). + * The joystick drives the companion menu UI (ZEPHCORE_UI_JOYSTICK). The + * back button is a single GPIO whose tap-count/hold is decoded by the + * filters below — same scheme as the Wio Tracker L1: + * 1 tap -> KEY_1 (back/cancel) long hold -> KEY_POWER + * 2 taps -> KEY_B (advert) 3 -> KEY_D (buzzer) + * 4 taps -> KEY_C (GPS) 5 -> KEY_E (LED) + * (NFC pins P0.09/P0.10 are freed for GPIO by nfct-pins-as-gpios above.) + */ + buttons: buttons { + compatible = "gpio-keys"; + + user_button: button_0 { + gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + label = "Back Button"; + }; + + joystick_up: button_1 { + gpios = <&gpio0 28 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + label = "Joystick Up"; + }; + + joystick_down: button_2 { + gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + label = "Joystick Down"; + }; + + joystick_left: button_3 { + gpios = <&gpio0 30 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + label = "Joystick Left"; + }; + + joystick_right: button_4 { + gpios = <&gpio0 31 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + label = "Joystick Right"; + }; + + joystick_press: button_5 { + gpios = <&gpio0 26 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + zephyr,code = ; + label = "Joystick Press"; + }; + }; + + /* Back button: short tap -> KEY_A (feeds multitap), hold >=1s -> KEY_POWER */ + user_btn_longpress { + compatible = "zephyr,input-longpress"; + input = <&buttons>; + input-codes = ; + short-codes = ; + long-codes = ; + long-delay-ms = <1000>; + }; + + /* Tap-count decode of the back button. No 'input' phandle: KEY_A is + * emitted by the longpress pseudo-device, not by &buttons. */ + user_btn_multitap { + compatible = "zephcore,input-multi-tap"; + input-codes = ; + tap-codes = ; + tap-delay-ms = <400>; + }; + + /* Onboard buzzer on P1.01 (PWM0). The official MeshCore variant defines + * PIN_BUZZER=33 (P1.01); its PIN_GPS_EN=33 is vestigial template cruft — + * the UART GPS is always-on and needs no enable, so P1.01 is the buzzer. */ + pwmbuzzer { + compatible = "pwm-leds"; + buzzer: buzzer { + pwms = <&pwm0 0 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + }; + }; + + /* Battery sense: AIN3 = P0.05 with the GAT562 divider (~1.73x) */ + zephyr,user { + io-channels = <&adc 3>; + vbat-mv-multiplier = <6232>; /* mv = raw * multiplier / 4096 */ + }; +}; + +®0 { + status = "okay"; +}; + +®1 { + regulator-initial-mode = ; +}; + +&uicr { + gpio-as-nreset; + nfct-pins-as-gpios; /* free P0.09 / P0.10 for the user button */ +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; + + /* + * Route the 6 button/joystick edge interrupts (P0.04/09/26/28/30/31) + * through the shared GPIO SENSE/PORT event instead of dedicating a + * GPIOTE IN channel to each. The nRF52840 has only 8 GPIOTE channels; + * with 6 buttons each taking one (gpio-keys uses GPIO_INT_EDGE_BOTH), + * the SX1262 DIO1 interrupt could be starved of a channel, so CAD/TX/RX + * "done" IRQs never fire and every RF op times out (CAD failed -116). + * Moving the slow button inputs to sense frees all 6 channels for DIO1. + * Mask = (1<<4)|(1<<9)|(1<<26)|(1<<28)|(1<<30)|(1<<31). + */ + sense-edge-mask = <0xD4000210>; +}; + +&gpio1 { + status = "okay"; + + /* SX1262 module power-enable on P1.05: held HIGH. The native sx126x + * driver must not toggle this per-direction (it is module power, not a + * per-TX/RX antenna switch), so it is hogged instead of being a + * rx-enable-gpios on the lora node. */ + sx1262_power_en { + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "sx1262-power-en"; + }; + + /* GPS power-enable on WB_IO2 / P1.02: held HIGH so the AT6558R GNSS is + * powered and transmitting NMEA at boot. Without this the receiver is + * silent (no UART data at all). Hogged (not driven by the GPS manager) + * because the module is simply always-on while the board is powered. */ + gps_power_en { + gpio-hog; + gpios = <2 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "gps-power-en"; + }; +}; + +&adc { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + channel@3 { + reg = <3>; + zephyr,gain = "ADC_GAIN_1_6"; + zephyr,reference = "ADC_REF_INTERNAL"; + zephyr,acquisition-time = ; + zephyr,input-positive = ; /* P0.05 */ + zephyr,resolution = <12>; + }; +}; + +/* + * GPS: UART NMEA receiver on UART0 @ 9600 baud (MCU RX P0.15 <- GPS TX, + * MCU TX P0.16 -> GPS RX). Multi-constellation (GPS + GLONASS), always + * powered — no enable pin. Matches the official MeshCore gat562_30s_mesh_kit + * variant (MicroNMEALocationProvider on Serial1, 9600 baud). Runs on UARTE0 + * (like the other nRF52 GPS boards here): UARTE1's interrupt-driven RX did + * not deliver to the modem backend on this SoC. Zephyr's gnss-nmea-generic + * driver parses the stream and publishes via the GNSS subsystem. + */ +&uart0 { + status = "okay"; + current-speed = <9600>; + pinctrl-0 = <&uart0_default>; + pinctrl-1 = <&uart0_sleep>; + pinctrl-names = "default", "sleep"; + + gnss: gnss-nmea-generic { + compatible = "gnss-nmea-generic"; + }; +}; + +/* UART1 unused — the GPS moved to UART0 (see above). */ +&uart1 { + status = "disabled"; +}; + +/* LoRa SX1262 on SPI1 — RAK4631 core-module wiring */ +&spi1 { + compatible = "nordic,nrf-spi"; + status = "okay"; + cs-gpios = <&gpio1 10 GPIO_ACTIVE_LOW>; /* NSS P1.10 */ + pinctrl-0 = <&spi1_default>; + pinctrl-1 = <&spi1_sleep>; + pinctrl-names = "default", "sleep"; + + lora: lora@0 { + compatible = "semtech,sx1262"; + reg = <0>; + spi-max-frequency = <1000000>; + reset-gpios = <&gpio1 6 GPIO_ACTIVE_LOW>; /* RST P1.06 */ + busy-gpios = <&gpio1 14 GPIO_ACTIVE_HIGH>; /* BUSY P1.14 */ + dio1-gpios = <&gpio1 15 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; /* DIO1 P1.15 */ + dio2-tx-enable; /* DIO2 = T/R switch */ + /* 1.8 V TCXO via DIO3 — matches the official MeshCore GAT562 variant + * (SX126X_DIO3_TCXO_VOLTAGE 1.8). The TCXO on the RAK4631 core runs + * fine at 1.8 V; 3.3 V also works on this unit, but 1.8 V mirrors the + * vendor's known-good value. The module is a TCXO part: without DIO3 + * control it has no clock and sits in permanent BUSY. NOTE: the SX1262 + * signals CAD/TX/RX "done" on DIO1, which needs a free nRF GPIOTE + * channel. This board's 6 buttons are routed to GPIO SENSE (see + * sense-edge-mask on &gpio0) so they don't consume all 8 channels and + * starve DIO1 — without that, every RF op times out ("CAD failed -116"). */ + dio3-tcxo-voltage = ; + tcxo-power-startup-delay-ms = <5>; + rx-boosted; + }; +}; + +/* I2C0: SSD1306 OLED @ 0x3C + auto-detected sensors (BME280 pad, etc.) */ +&i2c0 { + compatible = "nordic,nrf-twi"; + status = "okay"; + pinctrl-0 = <&i2c0_default>; + pinctrl-1 = <&i2c0_sleep>; + pinctrl-names = "default", "sleep"; + + ssd1306: ssd1306@3c { + compatible = "solomon,ssd1306"; + reg = <0x3c>; + width = <128>; + height = <64>; + segment-offset = <0>; + page-offset = <0>; + display-offset = <0>; + multiplex-ratio = <63>; + segment-remap; + com-invdir; + prechargep = <0x22>; + }; + + #include "../../common/sensors-i2c.dtsi" +}; + +/* PWM0 drives the buzzer on P1.01 */ +&pwm0 { + status = "okay"; + pinctrl-0 = <&pwm0_default>; + pinctrl-1 = <&pwm0_sleep>; + pinctrl-names = "default", "sleep"; +}; + +/* + * No external QSPI flash on the GAT562 core module. The SoC leaves &qspi + * disabled by default; pin it explicitly so a probe of an absent chip can + * never hang boot. + */ +&qspi { + status = "disabled"; +}; + +/* USB CDC-ACM: console + repeater CLI */ +zephyr_udc0: &usbd { + compatible = "nordic,nrf-usbd"; + status = "okay"; + + cdc_acm_uart: cdc_acm_uart { + compatible = "zephyr,cdc-acm-uart"; + }; +}; + +/* SoftDevice s140 v6 + UF2 bootloader flash layout (app @ 0x26000) */ +#include "../../common/nrf52_partitions_sdv6.dtsi" + +/* Mark the buttons node as a System OFF wakeup source */ +#include "../../common/nrf52_wakeup.dtsi" diff --git a/zephcore/boards/nrf52840/gat562_30s/gat562_30s_defconfig b/zephcore/boards/nrf52840/gat562_30s/gat562_30s_defconfig new file mode 100644 index 0000000..7b78d98 --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/gat562_30s_defconfig @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: Apache-2.0 +# GAT562 30S Mesh Kit default configuration +# (most subsystems also come from zephcore_common.conf + nrf52_common.conf; +# these are the board essentials, kept self-contained like other custom boards) + +# MPU + hardware stack protection +CONFIG_ARM_MPU=y +CONFIG_HW_STACK_PROTECTION=y + +# GPIO + pin control +CONFIG_GPIO=y +CONFIG_PINCTRL=y + +# Console over USB CDC-ACM (DT node + nrf52_common.conf USB stack) +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y +CONFIG_SERIAL=y +CONFIG_UART_LINE_CTRL=y + +# Flash / NVS (LittleFS app data partition) +CONFIG_FLASH=y +CONFIG_FLASH_MAP=y +CONFIG_NVS=y + +# SPI for LoRa, ADC for battery sense +CONFIG_SPI=y +CONFIG_ADC=y + +# SEGGER RTT (matches the RAK4631 base this board derives from) +CONFIG_USE_SEGGER_RTT=y diff --git a/zephcore/boards/nrf52840/gat562_30s/pre_dt_board.cmake b/zephcore/boards/nrf52840/gat562_30s/pre_dt_board.cmake new file mode 100644 index 0000000..895843e --- /dev/null +++ b/zephcore/boards/nrf52840/gat562_30s/pre_dt_board.cmake @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: Apache-2.0 +# Suppress unique_unit_address warnings for the overlapping nRF52840 +# peripherals (power/clock/bprot @ 0x40000000, acl/flash-controller @ +# 0x4001e000) — same as the upstream rak4631 board. +list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled") diff --git a/zephcore/boards/supported_boards.md b/zephcore/boards/supported_boards.md index b931cb8..8ff4cac 100644 --- a/zephcore/boards/supported_boards.md +++ b/zephcore/boards/supported_boards.md @@ -19,6 +19,7 @@ xiao_nrf52840 lilygo_techo promicro_sx1262 heltec_t114 +gat562_30s ``` > **RAK WisMesh Pocket** (WisBlock pocket): use `-b rak4631` — same board string and firmware as **RAK4631**.