Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions boards/framework/framework_wireless_dongle/Kconfig.defconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Framework Computer Inc
# SPDX-License-Identifier: Apache-2.0

if BOARD_FRAMEWORK_WIRELESS_DONGLE_NRF54LM20A_CPUAPP

config HW_STACK_PROTECTION
default ARCH_HAS_STACK_PROTECTION

endif # BOARD_FRAMEWORK_WIRELESS_DONGLE_NRF54LM20A_CPUAPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright (c) 2026 Framework Computer Inc
# SPDX-License-Identifier: Apache-2.0

config BOARD_FRAMEWORK_WIRELESS_DONGLE
select SOC_NRF54LM20A_CPUAPP if BOARD_FRAMEWORK_WIRELESS_DONGLE_NRF54LM20A_CPUAPP
17 changes: 17 additions & 0 deletions boards/framework/framework_wireless_dongle/Kconfig.sysbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright (c) 2026 Framework Computer Inc
# SPDX-License-Identifier: Apache-2.0

# Match the factory bootloader: the flash layout has a single application
# slot, so MCUboot can only run in single application mode, and images are
# verified with ED25519 signatures.
if BOOTLOADER_MCUBOOT

choice MCUBOOT_MODE
default MCUBOOT_MODE_SINGLE_APP
endchoice

choice BOOT_SIGNATURE_TYPE
default BOOT_SIGNATURE_TYPE_ED25519
endchoice

endif # BOOTLOADER_MCUBOOT
9 changes: 9 additions & 0 deletions boards/framework/framework_wireless_dongle/board.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Framework Computer Inc
# SPDX-License-Identifier: Apache-2.0

if(CONFIG_SOC_NRF54LM20A_CPUAPP)
board_runner_args(jlink "--device=nRF54LM20A_M33" "--speed=4000")
endif()

include(${ZEPHYR_BASE}/boards/common/nrfutil.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
34 changes: 34 additions & 0 deletions boards/framework/framework_wireless_dongle/board.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
board:
name: framework_wireless_dongle
full_name: Framework Wireless Dongle
vendor: framework
socs:
- name: nrf54lm20a
runners:
run_once:
'--recover':
- runners:
- nrfjprog
- nrfutil
run: first
groups:
- boards:
- framework_wireless_dongle/nrf54lm20a/cpuapp
'--erase':
- runners:
- nrfjprog
- jlink
- nrfutil
run: first
groups:
- boards:
- framework_wireless_dongle/nrf54lm20a/cpuapp
'--reset':
- runners:
- nrfjprog
- jlink
- nrfutil
run: last
groups:
- boards:
- framework_wireless_dongle/nrf54lm20a/cpuapp
123 changes: 123 additions & 0 deletions boards/framework/framework_wireless_dongle/doc/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
.. zephyr:board:: framework_wireless_dongle

Overview
********

The Framework Wireless Dongle is the USB-A receiver that ships with the
:zephyr:board:`framework_wireless_tp_kb`. It connects to Bluetooth Low Energy input devices and
presents them to the host as a USB HID device, without needing Bluetooth on the host. It is built
around the Nordic nRF54LM20A SoC and has no user interface of its own: no buttons and no LEDs.

The dongle ships with an MCUboot bootloader that supports serial recovery over USB.

Hardware
********

* nRF54LM20A SoC: 128 MHz Arm Cortex-M33, RISC-V FLPR coprocessor, 2 MB RRAM, 512 kB RAM,
multiprotocol 2.4 GHz radio (Bluetooth LE, IEEE 802.15.4, proprietary)
* USB high-speed device on the USB-A plug, which also powers the dongle
* 32 MHz crystal, no 32.768 kHz crystal (the low frequency clock runs from the internal RC
oscillator)
* Debug UART (UARTE20) on test pads

Supported Features
==================

.. zephyr:board-supported-hw::

Connections and IOs
===================

+-------+-------------+----------------------+
| Pin | Function | Usage |
+=======+=============+======================+
| P2.02 | UARTE20 TX | Debug UART, test pad |
+-------+-------------+----------------------+
| P2.00 | UARTE20 RX | Debug UART, test pad |
+-------+-------------+----------------------+

Flash Layout
============

The board's flash layout matches the factory bootloader:

+-------------------+----------+----------+---------------------------------+
| Partition | Offset | Size | Usage |
+===================+==========+==========+=================================+
| ``mcuboot`` | 0x000000 | 96 kB | MCUboot with USB serial recovery|
+-------------------+----------+----------+---------------------------------+
| ``image-0`` | 0x018000 | 1828 kB | Application |
+-------------------+----------+----------+---------------------------------+
| ``storage`` | 0x1e1000 | 16 kB | Settings storage |
+-------------------+----------+----------+---------------------------------+

There is only one application slot, so when building MCUboot with sysbuild the board defaults to
``SB_CONFIG_MCUBOOT_MODE_SINGLE_APP``. The factory bootloader verifies ED25519 signatures, so the
board also defaults to ``SB_CONFIG_BOOT_SIGNATURE_TYPE_ED25519``. Sysbuild then signs images with
MCUboot's ``root-ed25519.pem``; set ``SB_CONFIG_BOOT_SIGNATURE_KEY_FILE`` to use a different key.

Programming and Debugging
*************************

.. zephyr:board-supported-runners::

Flashing with a debugger
========================

SWD is available on test pads. Flashing with a J-Link or an nRF Util compatible probe uses the
standard flow, for example for the :zephyr:code-sample:`usb-cdc-acm` sample:

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/cdc_acm
:board: framework_wireless_dongle/nrf54lm20a/cpuapp
:goals: build flash

Flashing a plain application this way overwrites the factory bootloader. To keep it, build the
application for the ``image-0`` slot with sysbuild and MCUboot enabled, and flash only the
application domain. A plain ``west flash`` of a sysbuild build also writes the MCUboot image built
by sysbuild over the factory bootloader.

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/cdc_acm
:board: framework_wireless_dongle/nrf54lm20a/cpuapp
:goals: build flash
:west-args: --sysbuild
:gen-args: -DSB_CONFIG_BOOTLOADER_MCUBOOT=y
:flash-args: --domain cdc_acm

Flashing over USB
=================

The factory MCUboot bootloader exposes a USB CDC ACM serial port for :ref:`mcumgr <mcu_mgr>`
serial recovery. As the dongle has no button, recovery mode is requested from the running
application through the :ref:`retention boot mode <retention_api>` (for example with the mcumgr
``os reset`` command with the boot mode argument, if the application enables it). Build the
application with MCUboot support so that the image is signed and linked for the application slot:

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/cdc_acm
:board: framework_wireless_dongle/nrf54lm20a/cpuapp
:goals: build
:west-args: --sysbuild
:gen-args: -DSB_CONFIG_BOOTLOADER_MCUBOOT=y

The image must be signed with a key the installed bootloader trusts. Upload the signed
application image with mcumgr and reset the device:

.. code-block:: console

mcumgr --conntype serial --connstring dev=/dev/ttyACM0 image upload build/cdc_acm/zephyr/zephyr.signed.bin
mcumgr --conntype serial --connstring dev=/dev/ttyACM0 reset

Debugging
=========

The debug UART (115200 baud) on the test pads is the default console. The SoC can be debugged
over SWD with J-Link or nRF Util using ``west debug``.

References
**********

* `Framework Computer`_

.. _Framework Computer: https://frame.work
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2026 Framework Computer Inc
* SPDX-License-Identifier: Apache-2.0
*/

&pinctrl {
uart20_default: uart20_default {
group1 {
psels = <NRF_PSEL(UART_TX, 2, 2)>;
};

group2 {
psels = <NRF_PSEL(UART_RX, 2, 0)>;
bias-pull-up;
};
};

uart20_sleep: uart20_sleep {
group1 {
psels = <NRF_PSEL(UART_TX, 2, 2)>,
<NRF_PSEL(UART_RX, 2, 0)>;
low-power-enable;
};
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2026 Framework Computer Inc
*
* SPDX-License-Identifier: Apache-2.0
*/

/dts-v1/;

#include <nordic/nrf54lm20a_cpuapp.dtsi>
#include "framework_wireless_dongle-pinctrl.dtsi"

/ {
compatible = "framework,wireless_dongle_nrf54lm20a-cpuapp";
model = "Framework Wireless Dongle";

chosen {
zephyr,console = &uart20;
zephyr,shell-uart = &uart20;
zephyr,uart-mcumgr = &uart20;
zephyr,bt-mon-uart = &uart20;
zephyr,bt-c2h-uart = &uart20;
zephyr,flash-controller = &rram_controller;
zephyr,flash = &cpuapp_rram;
zephyr,code-partition = &slot0_partition;
zephyr,sram = &cpuapp_sram_app;
zephyr,ieee802154 = &ieee802154;
};

aliases {
watchdog0 = &wdt31;
};
};

&cpuapp_sram {
status = "okay";
};

&hfpll {
clock-frequency = <DT_FREQ_M(128)>;
};

&hfxo {
load-capacitors = "internal";
load-capacitance-femtofarad = <15000>;
};

/* No DCDC inductor is fitted, VREGMAIN runs in LDO mode. */
&vregmain {
status = "okay";
regulator-initial-mode = <NRF5X_REG_MODE_LDO>;
};

&vregusb {
status = "okay";
};

&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";
};

/* Debug UART on test pads */
&uart20 {
status = "okay";
current-speed = <115200>;
pinctrl-0 = <&uart20_default>;
pinctrl-1 = <&uart20_sleep>;
pinctrl-names = "default", "sleep";
};

&gpio0 {
status = "okay";
};

&gpio1 {
status = "okay";
};

&gpio2 {
status = "okay";
};

&gpio3 {
status = "okay";
};

&gpiote20 {
status = "okay";
};

&gpiote30 {
status = "okay";
};

&radio {
status = "okay";
};

&ieee802154 {
status = "okay";
};

&temp {
status = "okay";
};

&clock {
status = "okay";
};

&xo {
status = "okay";
};

/* No 32.768 kHz crystal is fitted, the LFCLK runs from the internal RC oscillator. */
&lfclk {
status = "okay";
k32src = "rc";
k32src-accuracy-ppm = <250>;
};

&xo24m {
status = "okay";
};

&usbhs_wrapper {
status = "okay";
};

zephyr_udc0: &usbhs {
status = "okay";
};

/*
* Flash layout matching the factory MCUboot bootloader: 96 kB bootloader
* with USB serial recovery, a single application slot and 16 kB of settings
* storage. The last 96 kB of RRAM are reserved for the FLPR core.
*/
&cpuapp_rram {
partitions {
ranges;
#address-cells = <1>;
#size-cells = <1>;

boot_partition: partition@0 {
compatible = "zephyr,mapped-partition";
label = "mcuboot";
reg = <0x0 DT_SIZE_K(96)>;
};

slot0_partition: partition@18000 {
compatible = "zephyr,mapped-partition";
label = "image-0";
reg = <0x18000 DT_SIZE_K(1828)>;
};

storage_partition: partition@1e1000 {
compatible = "zephyr,mapped-partition";
label = "storage";
reg = <0x1e1000 DT_SIZE_K(16)>;
};
};
};
Loading
Loading