add seeed lvk + nrf54lm20a

This commit is contained in:
liquidraver
2026-10-02 13:27:21 +02:00
parent 3c7a7c830a
commit 3b886b861b
14 changed files with 701 additions and 1 deletions
+1
View File
@@ -158,6 +158,7 @@ xiao_mg24
```
me25ls02/nrf54l15/cpuapp
seeed_lr2021_evk/nrf54l15/cpuapp
seeed_lr2021_evk_lm20a/nrf54lm20a/cpuapp # source-only, no published firmware
xiao_nrf54l15/nrf54l15/cpuapp
```
<!-- /boards -->
+26
View File
@@ -175,6 +175,17 @@ static const struct device *const fuel_gauge_dev =
#define HAS_FUEL_GAUGE 0
#endif
/* nPM1300 charger (XIAO nRF54LM20A): the PMIC measures VBAT with its own ADC
* and Zephyr exposes that through the sensor API, not the fuel-gauge one.
* Voltage only; state of charge comes from the discharge curve. */
#if !HAS_FUEL_GAUGE && DT_HAS_COMPAT_STATUS_OKAY(nordic_npm1300_charger)
#define HAS_PMIC_CHARGER 1
static const struct device *const pmic_charger_dev =
DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(nordic_npm1300_charger));
#else
#define HAS_PMIC_CHARGER 0
#endif
/* Initialize activity LED GPIO at boot */
#if HAS_TX_LED
/* Width of the receive blink. A transmit holds the LED for its whole airtime,
@@ -255,6 +266,21 @@ uint16_t ZephyrBoard::readBattMilliVolts()
LOG_WRN("Fuel gauge voltage read failed: %d", ret);
}
return 0;
#elif HAS_PMIC_CHARGER
if (device_is_ready(pmic_charger_dev)) {
struct sensor_value v;
int ret = sensor_sample_fetch(pmic_charger_dev);
if (ret == 0) {
ret = sensor_channel_get(pmic_charger_dev,
SENSOR_CHAN_GAUGE_VOLTAGE, &v);
}
if (ret == 0) {
return (uint16_t)(v.val1 * 1000 + v.val2 / 1000); /* V -> mV */
}
LOG_WRN("PMIC battery voltage read failed: %d", ret);
}
return 0;
#elif DT_NODE_EXISTS(DT_PATH(zephyr_user)) && \
DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
if (!adc_is_ready_dt(&vbat_adc)) {
@@ -0,0 +1,33 @@
# Copyright (c) 2026 ZephCore
# SPDX-License-Identifier: MIT
if BOARD_SEEED_LR2021_EVK_LM20A_NRF54LM20A_CPUAPP
config HAS_BT_CTLR
default BT
# nPM1300 init order, copied from upstream Zephyr's xiao_nrf54lm20a
# Kconfig.defconfig. The charger driver raises the PMIC's VBUS current limit
# from its 100 mA power-up default to 500 mA, and it lives under the sensor
# subsystem (priority 90). The regulators must come up after it, or the LDO1
# soft-start inrush trips over-current protection and the board brown-outs in a
# boot loop. The 500 mA limit matters to us beyond boot: an LR2021 at +22 dBm
# does not fit in 100 mA on a kit running from USB alone.
config SENSOR
default y
config REGULATOR
default y
if REGULATOR_NPM13XX
config REGULATOR_NPM13XX_COMMON_INIT_PRIORITY
default 91
config REGULATOR_NPM13XX_INIT_PRIORITY
default 92
endif # REGULATOR_NPM13XX
endif # BOARD_SEEED_LR2021_EVK_LM20A_NRF54LM20A_CPUAPP
@@ -0,0 +1,6 @@
# Semtech LR2021 LoRa Plus EVK on a XIAO nRF54LM20A — board configuration
# Copyright (c) 2026 ZephCore
# SPDX-License-Identifier: MIT
config BOARD_SEEED_LR2021_EVK_LM20A
select SOC_NRF54LM20A_CPUAPP if BOARD_SEEED_LR2021_EVK_LM20A_NRF54LM20A_CPUAPP
@@ -0,0 +1,20 @@
# Copyright (c) 2026 ZephCore
# SPDX-License-Identifier: MIT
#
# Same flashing story as seeed_lr2021_evk: the XIAO's USB-C goes to a SAMD11
# that presents CMSIS-DAP plus a USB CDC for the uart20 console. The nRF54LM20A
# does have a USB peripheral, but this XIAO leaves D+/D- unconnected, so there
# is no UF2 and no DFU.
#
# The openocd config is upstream Zephyr's for the XIAO nRF54LM20A, used in place
# rather than copied: it sources boards/seeed/common/openocd_nrf54l.cfg by a
# path relative to itself.
board_runner_args(openocd "--config=${ZEPHYR_BASE}/boards/seeed/xiao_nrf54lm20a/support/openocd.cfg"
"--cmd-load=nrf54l_load" "--cmd-erase=nrf54l_mass_erase"
"--cmd-verify=verify_image" -c "targets nrf54lm20a.cpu")
board_runner_args(jlink "--device=nRF54LM20A_M33" "--speed=4000")
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
@@ -0,0 +1,22 @@
# Semtech LR2021 LoRa Plus EVK (XIAO nRF54LM20A + Wio-LR2021)
# Board-specific configuration
# Board identification
CONFIG_ZEPHCORE_BOARD_NAME="LR2021 LoRa Plus EVK LM20A"
# Device Information Service model name
CONFIG_BT_DIS_MODEL_NUMBER_STR="Seeed LR2021 LoRa Plus EVK LM20A"
# LR2021 radio driver
CONFIG_ZEPHCORE_RADIO_LR2021=y
# 511 KB of RAM leaves room well past the defaults (350 / 256). 510 contacts is
# the most the companion protocol can report to the app (one byte, doubled);
# each contact costs 188 B of RAM and each queue slot 173 B.
CONFIG_ZEPHCORE_MAX_CONTACTS=510
CONFIG_ZEPHCORE_OFFLINE_QUEUE_SIZE=512
# /ext on the XIAO's SPI NOR: LittleFS takes its block size from the flash page
# layout, and the SPI NOR driver's default page is the 64 KB block, not the
# 4 KB sector (the QSPI driver's equivalent is set in nrf52_common.conf).
CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096
@@ -0,0 +1,9 @@
# Copyright (c) 2026 ZephCore
# SPDX-License-Identifier: MIT
board:
name: seeed_lr2021_evk_lm20a
full_name: Semtech LR2021 LoRa Plus EVK (XIAO nRF54LM20A + Wio-LR2021)
vendor: seeed
socs:
- name: nrf54lm20a
@@ -0,0 +1,19 @@
# LR2021 LoRa Plus EVK (XIAO nRF54LM20A) bring-up logging.
#
# west build -b seeed_lr2021_evk_lm20a/nrf54lm20a/cpuapp zephcore --pristine --no-sysbuild -- \
# -DEXTRA_CONF_FILE="boards/common/debug.conf;boards/nrf54l/seeed_lr2021_evk_lm20a/bringup.conf"
#
# Same set, for the same reasons, as boards/nrf54l/seeed_lr2021_evk/bringup.conf.
# Not for daily use.
CONFIG_LORA_LOG_LEVEL_DBG=y
CONFIG_I2C_LOG_LEVEL_INF=y
CONFIG_DISPLAY_LOG_LEVEL_DBG=y
# One line per real input event: K1 reaches the XIAO through a pogo pin, and
# whether it lands on this XIAO's D14 pad is a bench question.
CONFIG_INPUT_LOG_LEVEL_INF=y
CONFIG_INPUT_EVENT_DUMP=y
CONFIG_FS_LOG_LEVEL_DBG=y
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: MIT
# Suppress "unique_unit_address_if_enabled" to handle some overlaps
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
@@ -0,0 +1,86 @@
/*
* Semtech LR2021 LoRa Plus EVK on a XIAO nRF54LM20A — pin control
* Copyright (c) 2026 ZephCore
* SPDX-License-Identifier: MIT
*
* Pin assignments are the XIAO nRF54LM20A's fixed connector mapping, copied
* from Zephyr's xiao_nrf54lm20a_nrf54lm20a-pinctrl.dtsi. Only the three buses
* this kit uses are declared:
*
* uart20 P1.11 TX / P1.10 RX — console, via the SAMD11 CMSIS-DAP bridge
* i2c22 P1.03 SDA / P1.07 SCL — D4/D5: OLED + the two I2C Grove ports
* spi23 P1.04 SCK / P1.06 MOSI / P1.05 MISO — D8/D10/D9: LR2021
* spi00 P2.01 SCK / P2.02 MOSI / P2.04 MISO — the XIAO's 8 MB flash (/ext)
*
* uart21 (D6/D7) is deliberately absent — see the DIO7/DIO11 note in the .dts.
*/
&pinctrl {
/omit-if-no-ref/ uart20_default: uart20_default {
group1 {
psels = <NRF_PSEL(UART_TX, 1, 11)>;
};
group2 {
psels = <NRF_PSEL(UART_RX, 1, 10)>;
bias-pull-up;
};
};
/omit-if-no-ref/ uart20_sleep: uart20_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 1, 11)>,
<NRF_PSEL(UART_RX, 1, 10)>;
low-power-enable;
};
};
/omit-if-no-ref/ i2c22_default: i2c22_default {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 1, 3)>,
<NRF_PSEL(TWIM_SCL, 1, 7)>;
};
};
/omit-if-no-ref/ i2c22_sleep: i2c22_sleep {
group1 {
psels = <NRF_PSEL(TWIM_SDA, 1, 3)>,
<NRF_PSEL(TWIM_SCL, 1, 7)>;
low-power-enable;
};
};
/omit-if-no-ref/ spi00_default: spi00_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 2, 1)>,
<NRF_PSEL(SPIM_MOSI, 2, 2)>,
<NRF_PSEL(SPIM_MISO, 2, 4)>;
};
};
/omit-if-no-ref/ spi00_sleep: spi00_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 2, 1)>,
<NRF_PSEL(SPIM_MOSI, 2, 2)>,
<NRF_PSEL(SPIM_MISO, 2, 4)>;
low-power-enable;
};
};
/omit-if-no-ref/ spi23_default: spi23_default {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 4)>,
<NRF_PSEL(SPIM_MOSI, 1, 6)>,
<NRF_PSEL(SPIM_MISO, 1, 5)>;
};
};
/omit-if-no-ref/ spi23_sleep: spi23_sleep {
group1 {
psels = <NRF_PSEL(SPIM_SCK, 1, 4)>,
<NRF_PSEL(SPIM_MOSI, 1, 6)>,
<NRF_PSEL(SPIM_MISO, 1, 5)>;
low-power-enable;
};
};
};
@@ -0,0 +1,430 @@
/*
* Semtech LR2021 LoRa Plus Evaluation Kit with a XIAO nRF54LM20A fitted
* Copyright (c) 2026 ZephCore
* SPDX-License-Identifier: MIT
*
* The same three-board sandwich as boards/nrf54l/seeed_lr2021_evk, with the
* MCU module swapped:
*
* Seeed XIAO nRF54LM20A — the MCU (2036 KB RRAM, 511 KB RAM, nPM1300)
* LoRa Plus Expansion Board V2a — OLED, buttons, Grove, SMA, SWD
* Wio-LR2021 module — LR2021WIO1XDCS, 868/915 MHz, switchless
*
* Everything about the carrier and the radio module is unchanged and is
* explained in seeed_lr2021_evk_nrf54l15_cpuapp.dts; this file only records
* what the other XIAO changes. Sources, in devdocs/seeed_lr2021_evk/assets/lm20a:
* the XIAO nRF54LM20A schematic and Zephyr's own xiao_nrf54lm20a board.
*
* XIAO connector map (Zephyr seeed_xiao_connector.dtsi, schematic sheet 6):
* D0 P1.00 LR2021 IRQ (chip DIO8) D8 P1.04 SPI SCK (spi23)
* D1 P1.31 LR2021 BUSY D9 P1.05 SPI MISO (spi23)
* D2 P1.30 LR2021 NRESET D10 P1.06 SPI MOSI (spi23)
* D3 P1.29 LR2021 NSS
* D4 P1.03 I2C SDA (i2c22) — OLED + 2x Grove
* D5 P1.07 I2C SCL (i2c22) — OLED + 2x Grove
* D6 P1.08 LR2021 DIO7 / uart21 TX / Grove UART
* D7 P1.09 LR2021 DIO11 / uart21 RX / Grove UART
* D16 P3.05 K1 user button on the expansion board (back pad TP16; the
* expansion board calls this pogo "D14", which is the L15's map)
*
* What differs from the nRF54L15 XIAO, beyond the pin numbers:
* - The radio is on spi23. spi00 belongs to the XIAO's own 8 MB flash on P2,
* which is mounted as /ext.
* - Every pin used here sits on a port with GPIOTE (P0, P1, P3), so the
* buttons are interrupt-driven and the L15's polling workaround is gone.
* - An nPM1300 PMIC makes the 3.3 V rail and charges the battery.
* - No 2.4 GHz antenna switch: ANT goes through a fixed match to the
* ceramic antenna (sheet 6). Seeed's pin sheet lists RF_SW_PWR/RF_SW_CTL
* on P1.27/P1.28, but no such net exists in the schematic.
* - The SoC has USB, the board does not use it: D+/D- are no-connects and
* the VBUS link R23 is not fitted. Flashing and console stay on the SAMD11.
*/
/dts-v1/;
#include <nordic/nrf54lm20a_cpuapp.dtsi>
#include "seeed_lr2021_evk_lm20a-pinctrl.dtsi"
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include <zephyr/dt-bindings/regulator/npm13xx.h>
/ {
model = "Semtech LR2021 LoRa Plus EVK (XIAO nRF54LM20A)";
compatible = "seeed,lr2021-evk-lm20a";
chosen {
zephyr,sram = &cpuapp_sram_app;
zephyr,flash = &cpuapp_rram;
zephyr,flash-controller = &rram_controller;
zephyr,console = &uart20;
zephyr,shell-uart = &uart20;
zephyr,bt-hci = &bt_hci_controller;
zephyr,display = &ssd1306;
/* No zephyr,code-partition: no bootloader, the image links at
* RRAM base 0x0. Same choice as seeed_lr2021_evk. */
};
aliases {
lora0 = &lora;
led0 = &blue_led;
sw0 = &user_button;
};
/* RGB LED on the XIAO core board. */
leds {
compatible = "gpio-leds";
blue_led: led_0 {
gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
label = "Blue LED";
};
red_led: led_1 {
gpios = <&gpio1 22 GPIO_ACTIVE_LOW>;
label = "Red LED";
};
green_led: led_2 {
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
label = "Green LED";
};
};
buttons: buttons {
compatible = "gpio-keys";
/*
* K1 on the expansion board: a bare switch to GND, so the
* internal pull-up is required.
*
* NOT this XIAO's D14. K1 reaches the MCU through a pogo pin
* placed for the nRF54L15 XIAO's D14 back pad, and the two XIAOs
* put different nets on the same eight pad positions (both KiCad
* board files, devdocs/seeed_lr2021_evk/assets). The pad that
* pogo touches here is TP16 = D16 = P3.05; D14 (P3.03, TP14) sits
* in the other pad row. P3 has a GPIOTE instance (gpiote20), so
* no polling as on the L15's P2.09.
*
* Derived from the board files, NOT confirmed on hardware: on the
* one kit tried (2026-10-02) holding K1 pulled none of P3.00..07
* low with pull-ups on all eight, i.e. the pogo pins made no
* contact at all. The XIAO's own button below is the one that works.
*/
user_button: button_0 {
gpios = <&gpio3 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
zephyr,code = <INPUT_KEY_0>;
label = "K1 (expansion board)";
};
/* The XIAO core board's own USR button. Same key code as K1. */
xiao_button: button_1 {
gpios = <&gpio0 9 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
zephyr,code = <INPUT_KEY_0>;
label = "USR (XIAO core board)";
};
};
/* Button chain — same mapping as RAK4631 (rak4631/board.overlay). */
user_btn_longpress {
compatible = "zephyr,input-longpress";
input = <&buttons>;
input-codes = <INPUT_KEY_0>;
short-codes = <INPUT_KEY_A>;
long-codes = <INPUT_KEY_ENTER>;
long-delay-ms = <1000>;
};
page_btn_multitap {
compatible = "zephcore,input-multi-tap";
input-codes = <INPUT_KEY_A>;
tap-codes = <INPUT_KEY_1 INPUT_KEY_LEFT>;
tap-delay-ms = <400>;
};
/*
* nPM1300 on a bit-banged bus (P1.17 SCL / P1.18 SDA). Copied from
* upstream Zephyr's xiao_nrf54lm20a; the init order it depends on is in
* Kconfig.defconfig.
*/
pmic_i2c: pmic-i2c {
compatible = "gpio-i2c";
#address-cells = <1>;
#size-cells = <0>;
sda-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
scl-gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;
clock-frequency = <100000>;
status = "okay";
pmic: npm1300@6b {
compatible = "nordic,npm1300";
reg = <0x6b>;
pmic_charger: charger {
compatible = "nordic,npm1300-charger";
term-microvolt = <4200000>;
term-warm-microvolt = <4000000>;
current-microamp = <150000>;
dischg-limit-microamp = <1000000>;
vbus-limit-microamp = <500000>;
thermistor-ohms = <10000>;
thermistor-beta = <3380>;
charging-enable;
};
regulators {
compatible = "nordic,npm1300-regulator";
/*
* BUCK2 is VSYS_3V3: the nRF54, the SAMD11 debugger
* and, through the expansion board, the LR2021.
*/
vsys_3v3: BUCK2 {
regulator-always-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
/* IMU and microphone supply. */
imu_vdd: LDO1 {
regulator-init-microvolt = <3300000>;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-initial-mode = <NPM13XX_LDSW_MODE_LDO>;
regulator-allowed-modes = <NPM13XX_LDSW_MODE_LDO>;
regulator-boot-on;
};
};
};
};
};
&cpuapp_sram {
status = "okay";
};
&hfpll {
clock-frequency = <DT_FREQ_M(128)>;
};
&grtc {
owned-channels = <0 1 2 3 4 5 6 7 8 9 10 11>;
/* Channels 7-11 reserved for Zero Latency IRQs, 3-4 for FLPR */
child-owned-channels = <3 4 7 8 9 10 11>;
status = "okay";
};
/* Clock set as upstream's xiao_nrf54lm20a. */
&clock {
status = "okay";
};
&xo {
status = "okay";
};
&lfclk {
status = "okay";
};
&xo24m {
status = "okay";
};
/* Console: P1.11 TX / P1.10 RX -> SAMD11 CMSIS-DAP bridge -> USB CDC */
&uart20 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&uart20_default>;
pinctrl-1 = <&uart20_sleep>;
pinctrl-names = "default", "sleep";
};
/* D6/D7 are also the LR2021's DIO7/DIO11 — see seeed_lr2021_evk. */
&uart21 {
status = "disabled";
};
&i2c22 {
status = "okay";
pinctrl-0 = <&i2c22_default>;
pinctrl-1 = <&i2c22_sleep>;
pinctrl-names = "default", "sleep";
clock-frequency = <400000>;
/* Mandatory for the SSD1306 on nrf-twim: 1 + 1024, rounded up. */
zephyr,concat-buf-size = <1088>;
/* ZJY-2864KSWPG01 on the expansion board; settings as seeed_lr2021_evk. */
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;
inversion-on;
prechargep = <0x22>;
};
};
&spi23 {
status = "okay";
cs-gpios = <&gpio1 29 GPIO_ACTIVE_LOW>; /* D3 = P1.29 NSS */
pinctrl-0 = <&spi23_default>;
pinctrl-1 = <&spi23_sleep>;
pinctrl-names = "default", "sleep";
/* The bus must idle at the LR2021's NOP, not Nordic's 0xFF. */
overrun-character = <0x00>;
lora: lora@0 {
compatible = "semtech,lr2021";
reg = <0>;
spi-max-frequency = <8000000>;
reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>; /* D2 = P1.30 */
busy-gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>; /* D1 = P1.31 */
irq-gpios = <&gpio1 0 (GPIO_PULL_DOWN | GPIO_ACTIVE_HIGH)>; /* D0 = P1.00 */
irq-dio = <8>; /* chip DIO8 -> module pin 1 -> D0 */
/* No TCXO and no RF switch: both are properties of the Wio-LR2021
* module, settled on hardware — see seeed_lr2021_evk. */
rx-boosted;
};
};
/*
* The XIAO's own 8 MB SPI NOR (PY25Q64HA) on P2, mounted as /ext by
* qspi-ext.dtsi below: contacts, channels and blobs move there, and contact
* saves become atomic. Flash parameters are upstream Zephyr's xiao_nrf54lm20a
* node, except the clock: upstream gives the part's 133 MHz ceiling, this
* stays at 8 MHz until a faster rate is measured to be worth having.
*
* The label is "qspi_flash" because that is the name qspi-ext.dtsi and
* ZephyrFsFormat.c look for; the part is driven as plain single-line SPI.
*/
&spi00 {
status = "okay";
cs-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&spi00_default>;
pinctrl-1 = <&spi00_sleep>;
pinctrl-names = "default", "sleep";
qspi_flash: py25q64ha@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <8000000>;
jedec-id = [85 20 17];
sfdp-bfp = [e5 20 f9 ff ff ff ff 03 44 eb 08 6b 08 3b 80 bb
fe ff ff ff ff ff 00 ff ff ff 44 eb 0c 20 0f 52
10 d8 00 81];
size = <67108864>;
has-dpd;
t-enter-dpd = <3000>;
requires-ulbpr;
hold-gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
wp-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
/* Full 8 MB for LittleFS storage */
qspi_storage_partition: partition@0 {
label = "qspi_storage";
reg = <0x00000000 0x00800000>;
};
};
};
};
&gpio0 {
status = "okay";
};
&gpio1 {
status = "okay";
};
&gpio2 {
status = "okay";
};
&gpio3 {
status = "okay";
};
&gpiote20 {
status = "okay";
};
&gpiote30 {
status = "okay";
};
&vregmain {
status = "okay";
regulator-initial-mode = <NRF5X_REG_MODE_DCDC>;
};
/* Crystal load capacitances as upstream's xiao_nrf54lm20a. */
&lfxo {
load-capacitors = "internal";
load-capacitance-femtofarad = <17000>;
status = "okay";
};
&hfxo {
load-capacitors = "internal";
load-capacitance-femtofarad = <15000>;
status = "okay";
};
&radio {
status = "okay";
};
&bt_hci_controller {
status = "okay";
};
&temp {
status = "okay";
};
/* Default Nordic RRAM map, then re-carved below for ZephCore. */
#include <vendor/nordic/nrf54lm20a_cpuapp_partition.dtsi>
/*
* RRAM layout (2036 KB total, 0x1FD000; the last 96 KB are the FLPR core's).
*
* No bootloader: the application starts at 0x0, so the DFU slots are deleted.
*
* 0x000000 - 0x1C0000 (1792 KB) application (links from 0x0)
* 0x1C0000 - 0x1E0000 (128 KB) LittleFS: identity, prefs, contacts,
* channels, BLE bonds
* 0x1E0000 - 0x1E5000 (20 KB) unused
* 0x1E5000 - 0x1FD000 (96 KB) reserved for FLPR
*/
/delete-node/ &slot0_partition;
/delete-node/ &slot1_partition;
/delete-node/ &storage_partition;
&cpuapp_rram {
partitions {
lfs_partition: partition@1c0000 {
compatible = "zephyr,mapped-partition";
label = "lfs";
reg = <0x1C0000 0x20000>;
};
};
};
/* LittleFS auto-mount — standard /lfs mount point */
#include "../../common/filesystem.dtsi"
/* /ext on the 8 MB SPI NOR: deferred init, mounted by the store on first use */
#include "../../common/qspi-ext.dtsi"
@@ -0,0 +1,29 @@
# Semtech LR2021 LoRa Plus EVK (XIAO nRF54LM20A) default configuration
# SPDX-License-Identifier: MIT
CONFIG_ARM_MPU=y
CONFIG_HW_STACK_PROTECTION=y
CONFIG_NULL_POINTER_EXCEPTION_DETECTION_NONE=y
CONFIG_CACHE_MANAGEMENT=y
CONFIG_EXTERNAL_CACHE=y
# Console on uart20 -> SAMD11 CMSIS-DAP bridge -> USB CDC
# (the SoC's own USB is not routed to the connector on this XIAO)
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_GPIO=y
CONFIG_PINCTRL=y
CONFIG_SPI=y
CONFIG_I2C=y
# RRAM + LittleFS
CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NRF_GRTC_START_SYSCOUNTER=y
# nPM1300 regulators; init order is in Kconfig.defconfig.
CONFIG_REGULATOR=y
@@ -0,0 +1,3 @@
# ZephCore board manifest — schema in zephcore/scripts/board_manifest.py
# No release: until validated on hardware.
target: seeed_lr2021_evk_lm20a/nrf54lm20a/cpuapp
@@ -1154,7 +1154,10 @@ static bool lr20xx_apply_rx_duty_cycle(struct lr20xx_data *data)
* As on the LR11xx (DS §6.3.8 is word for word UM §7.2.6): any NSS edge in
* the sleep phase ends the loop, and BUSY is high in sleep and in Rx alike.
* So suspend = SetStandby (never an NSS poke: that caused the X1's CMD_PERR
* storm), resume = re-arm. Caller holds spi_mutex. LLD 05 §13. */
* storm), resume = re-arm. Resume expects the standby suspend left: the chip
* answers SetRxDutyCycle with CMD_FAIL while in Rx (measured; DS §6.3.5 says
* it of SetRx), so a caller that enters Rx in between leaves it again first.
* Caller holds spi_mutex. LLD 05 §13. */
static bool lr20xx_dc_suspend(struct lr20xx_data *data)
{
if (!data->rx_duty_cycle_enabled || !data->in_rx_mode) {
@@ -2440,6 +2443,12 @@ int16_t lr20xx_get_rssi_inst(const struct device *dev)
out = rssi;
}
if (armed) {
/* Leave the Rx entered above; dc_resume() re-arms from standby. */
lr20xx_system_set_standby_mode(&data->hal_ctx,
LR20XX_SYSTEM_STANDBY_MODE_RC);
}
lr20xx_dc_resume(data, armed);
k_mutex_unlock(&data->spi_mutex);
@@ -2529,6 +2538,10 @@ int lr20xx_get_rssi_burst(const struct device *dev, int16_t *out, int n,
LR20XX_SYSTEM_IRQ_SYNC_WORD_HEADER_VALID))) {
got = -EAGAIN;
}
/* Leave the Rx entered above; dc_resume() re-arms from standby. */
lr20xx_system_set_standby_mode(&data->hal_ctx,
LR20XX_SYSTEM_STANDBY_MODE_RC);
}
lr20xx_dc_resume(data, armed);